Skip to content

Commit 874a214

Browse files
committed
controller
1 parent 210d300 commit 874a214

File tree

6 files changed

+164
-16
lines changed

6 files changed

+164
-16
lines changed

api/v1alpha1/deployable_types.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2025.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
20+
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
21+
22+
// DeployableSpec defines the desired state of DeployableProvider.
23+
type DeployableSpec struct {
24+
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
25+
// Important: Run "make" to regenerate code after modifying this file
26+
27+
// Image is the image of the provider to be deployed.
28+
Image string `json:"image,omitempty"`
29+
ImagePullSecrets []string `json:"imagePullSecrets,omitempty"`
30+
ImagePullPolicy string `json:"imagePullPolicy,omitempty"`
31+
}
32+
33+
// DeployableStatus defines the observed state of DeployableProvider.
34+
type DeployableStatus struct {
35+
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
36+
// Important: Run "make" to regenerate code after modifying this file
37+
}

api/v1alpha1/deployableprovider_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type DeployableProviderSpec struct {
2828
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
2929
// Important: Run "make" to regenerate code after modifying this file
3030

31+
DeploymentSpec DeployableSpec `json:"deploymentSpec,omitempty"`
32+
3133
// Foo is an example field of DeployableProvider. Edit deployableprovider_types.go to remove/update
3234
Foo string `json:"foo,omitempty"`
3335
}
@@ -36,6 +38,8 @@ type DeployableProviderSpec struct {
3638
type DeployableProviderStatus struct {
3739
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
3840
// Important: Run "make" to regenerate code after modifying this file
41+
42+
DeploymentStatus DeployableStatus `json:"deploymentStatus,omitempty"`
3943
}
4044

4145
// +kubebuilder:object:root=true

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func main() {
202202
os.Exit(1)
203203
}
204204

205-
if err = (&controller.DeployableProviderReconciler{
205+
if err = (&controller.DeployableReconciler{
206206
Client: mgr.GetClient(),
207207
Scheme: mgr.GetScheme(),
208208
}).SetupWithManager(mgr); err != nil {

internal/controller/deployableprovider_controller.go renamed to internal/controller/deployable_controller.go

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,20 @@ package controller
1919
import (
2020
"context"
2121

22+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2223
"k8s.io/apimachinery/pkg/runtime"
24+
"k8s.io/apimachinery/pkg/runtime/schema"
25+
"k8s.io/apimachinery/pkg/util/validation/field"
2326
ctrl "sigs.k8s.io/controller-runtime"
2427
"sigs.k8s.io/controller-runtime/pkg/client"
2528
"sigs.k8s.io/controller-runtime/pkg/log"
26-
27-
openmcpcloudv1alpha1 "github.com/openmcp-project/openmcp-operator/api/v1alpha1"
2829
)
2930

30-
// DeployableProviderReconciler reconciles a DeployableProvider object
31-
type DeployableProviderReconciler struct {
31+
// DeployableReconciler reconciles a DeployableProvider object
32+
type DeployableReconciler struct {
3233
client.Client
33-
Scheme *runtime.Scheme
34+
Scheme *runtime.Scheme
35+
Reconcilers []*GVKReconciler
3436
}
3537

3638
// +kubebuilder:rbac:groups=openmcp.cloud,resources=deployableproviders,verbs=get;list;watch;create;update;patch;delete
@@ -46,18 +48,39 @@ type DeployableProviderReconciler struct {
4648
//
4749
// For more details, check Reconcile and its Result here:
4850
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
49-
func (r *DeployableProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
51+
func (r *DeployableReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
5052
_ = log.FromContext(ctx)
51-
52-
// TODO(user): your logic here
53-
5453
return ctrl.Result{}, nil
5554
}
5655

5756
// SetupWithManager sets up the controller with the Manager.
58-
func (r *DeployableProviderReconciler) SetupWithManager(mgr ctrl.Manager) error {
59-
return ctrl.NewControllerManagedBy(mgr).
60-
For(&openmcpcloudv1alpha1.DeployableProvider{}).
61-
Named("deployableprovider").
62-
Complete(r)
57+
func (r *DeployableReconciler) SetupWithManager(mgr ctrl.Manager) error {
58+
allErrs := field.ErrorList{}
59+
60+
gvkList := []schema.GroupVersionKind{
61+
{Group: "openmcp.cloud", Version: "v1alpha1", Kind: "ClusterProvider"},
62+
{Group: "openmcp.cloud", Version: "v1alpha1", Kind: "MCPServiceProvider"},
63+
}
64+
65+
r.Reconcilers = make([]*GVKReconciler, 0, len(gvkList))
66+
67+
for i, gvk := range gvkList {
68+
r.Reconcilers = append(r.Reconcilers, &GVKReconciler{
69+
GroupVersionKind: gvk,
70+
Client: mgr.GetClient(),
71+
})
72+
73+
obj := &unstructured.Unstructured{}
74+
obj.SetGroupVersionKind(gvk)
75+
76+
err := ctrl.NewControllerManagedBy(mgr).
77+
For(obj).
78+
Named(gvk.String()).
79+
Complete(r.Reconcilers[i])
80+
if err != nil {
81+
allErrs = append(allErrs, field.InternalError(field.NewPath(gvk.String()), err))
82+
}
83+
}
84+
85+
return allErrs.ToAggregate()
6386
}

internal/controller/deployableprovider_controller_test.go renamed to internal/controller/deployable_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ var _ = Describe("DeployableProvider Controller", func() {
6868
})
6969
It("should successfully reconcile the resource", func() {
7070
By("Reconciling the created resource")
71-
controllerReconciler := &DeployableProviderReconciler{
71+
controllerReconciler := &DeployableReconciler{
7272
Client: k8sClient,
7373
Scheme: k8sClient.Scheme(),
7474
}

internal/controller/gvk_controller.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package controller
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8+
"k8s.io/apimachinery/pkg/runtime"
9+
"k8s.io/apimachinery/pkg/runtime/schema"
10+
ctrl "sigs.k8s.io/controller-runtime"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
"sigs.k8s.io/controller-runtime/pkg/log"
13+
14+
"github.com/openmcp-project/openmcp-operator/api/v1alpha1"
15+
)
16+
17+
type GVKReconciler struct {
18+
schema.GroupVersionKind
19+
client.Client
20+
}
21+
22+
func (r *GVKReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
23+
deployable := &unstructured.Unstructured{}
24+
deployable.SetGroupVersionKind(r.GroupVersionKind)
25+
26+
if err := r.Get(ctx, req.NamespacedName, deployable); err != nil {
27+
return ctrl.Result{}, err
28+
}
29+
30+
deployableOrig := deployable.DeepCopy()
31+
32+
l := log.FromContext(ctx)
33+
l.Info("Reconciling deployable")
34+
35+
deployableSpec := v1alpha1.DeployableSpec{}
36+
deploymentSpecRaw, found, err := unstructured.NestedFieldNoCopy(deployable.Object, "spec", "deploymentSpec")
37+
if !found {
38+
return ctrl.Result{}, fmt.Errorf("deploymentSpec not found")
39+
}
40+
if err != nil {
41+
return ctrl.Result{}, err
42+
}
43+
44+
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(deploymentSpecRaw.(map[string]interface{}), &deployableSpec); err != nil {
45+
return ctrl.Result{}, err
46+
}
47+
48+
l.Info("DeployableSpec", "deployableSpec", deployableSpec)
49+
50+
deployableStatus := v1alpha1.DeployableStatus{}
51+
deploymentStatusRaw, found, _ := unstructured.NestedFieldNoCopy(deployable.Object, "status", "deploymentStatus")
52+
if found {
53+
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(deploymentStatusRaw.(map[string]interface{}), &deployableStatus); err != nil {
54+
return ctrl.Result{}, err
55+
}
56+
}
57+
58+
// set status
59+
// deployableStatus.Status = true
60+
61+
deploymentSpecRaw, err = runtime.DefaultUnstructuredConverter.ToUnstructured(&deployableStatus)
62+
if err != nil {
63+
return ctrl.Result{}, err
64+
}
65+
66+
statusRaw, found, _ := unstructured.NestedFieldNoCopy(deployable.Object, "status")
67+
if !found {
68+
statusRaw = map[string]interface{}{}
69+
if err = unstructured.SetNestedField(deployable.Object, statusRaw.(map[string]interface{}), "status"); err != nil {
70+
return ctrl.Result{}, err
71+
}
72+
}
73+
74+
if err = unstructured.SetNestedField(deployable.Object, deploymentSpecRaw, "status", "deploymentStatus"); err != nil {
75+
return ctrl.Result{}, err
76+
}
77+
78+
// patch the status
79+
if err = r.Status().Patch(ctx, deployable, client.MergeFrom(deployableOrig)); err != nil {
80+
return ctrl.Result{}, err
81+
}
82+
83+
return ctrl.Result{}, nil
84+
}

0 commit comments

Comments
 (0)