Skip to content

Commit c34ddd1

Browse files
committed
wip
1 parent 5704834 commit c34ddd1

File tree

6 files changed

+113
-38
lines changed

6 files changed

+113
-38
lines changed

api/v1alpha1/condition_types.go

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ const (
3939
// RepositoryIsNotReadyReason is used when the referenced repository is not Ready yet.
4040
RepositoryIsNotReadyReason = "RepositoryIsNotReady"
4141

42+
// ComponentNotFoundReason is used when the referenced component is not found.
43+
ComponentNotFoundReason = "ComponentNotFound"
44+
4245
// ComponentIsNotReadyReason is used when the referenced component is not Ready yet.
4346
ComponentIsNotReadyReason = "ComponentIsNotReady"
4447

internal/controller/component/suite_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import (
5151

5252
const (
5353
ARTIFACT_PATH = "ocm-k8s-artifactstore--*"
54-
ARTIFACT_SERVER = "localhost:8080"
54+
ARTIFACT_SERVER = "localhost:0"
5555
)
5656

5757
var cfg *rest.Config

internal/controller/configuration/configuration_controller.go

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type Reconciler struct {
8585
// Reconcile is part of the main kubernetes reconciliation loop which aims to
8686
// move the current state of the cluster closer to the desired state.
8787
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, err error) {
88+
log.FromContext(ctx).V(1).Info("reconciling")
8889
configuration := &v1alpha1.ConfiguredResource{}
8990
if err := r.Get(ctx, req.NamespacedName, configuration); err != nil {
9091
return ctrl.Result{}, client.IgnoreNotFound(err)
@@ -228,6 +229,7 @@ func (r *Reconciler) reconcileExists(ctx context.Context, configuration *v1alpha
228229
return ctrl.Result{}, fmt.Errorf("failed to reconcile artifact: %w", err)
229230
}
230231

232+
logger.Info("updating")
231233
logger.Info("configuration successful", "artifact", configuration.Status.ArtifactRef)
232234
status.MarkReady(r.EventRecorder, configuration, "configured successfully")
233235

internal/controller/resource/resource_controller.go

+11-20
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,16 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
123123
// +kubebuilder:rbac:groups=openfluxcd.mandelsoft.org,resources=artifacts/finalizers,verbs=update
124124

125125
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
126+
log.FromContext(ctx).V(1).Info("starting reconciling resource")
127+
126128
resource := &v1alpha1.Resource{}
127129
if err := r.Get(ctx, req.NamespacedName, resource); err != nil {
128130
return ctrl.Result{}, client.IgnoreNotFound(err)
129131
}
130132

131-
return r.reconcileWithStatusUpdate(ctx, resource)
132-
}
133-
134-
func (r *Reconciler) reconcileWithStatusUpdate(ctx context.Context, resource *v1alpha1.Resource) (ctrl.Result, error) {
135133
patchHelper := patch.NewSerialPatcher(resource, r.Client)
136134

137-
result, err := r.reconcileExists(ctx, resource)
138-
135+
result, err := r.reconcilePrerequisite(ctx, resource)
139136
err = errors.Join(err, status.UpdateStatus(ctx, patchHelper, resource, r.EventRecorder, resource.GetRequeueAfter(), err))
140137
if err != nil {
141138
return ctrl.Result{}, err
@@ -144,9 +141,9 @@ func (r *Reconciler) reconcileWithStatusUpdate(ctx context.Context, resource *v1
144141
return result, nil
145142
}
146143

147-
func (r *Reconciler) reconcileExists(ctx context.Context, resource *v1alpha1.Resource) (ctrl.Result, error) {
144+
func (r *Reconciler) reconcilePrerequisite(ctx context.Context, resource *v1alpha1.Resource) (ctrl.Result, error) {
148145
logger := log.FromContext(ctx)
149-
logger.V(1).Info("preparing reconciling resource")
146+
logger.V(1).Info("checking if resource is suspended or deleted")
150147

151148
if resource.Spec.Suspend {
152149
return ctrl.Result{}, nil
@@ -159,6 +156,7 @@ func (r *Reconciler) reconcileExists(ctx context.Context, resource *v1alpha1.Res
159156
}
160157

161158
if removed := controllerutil.RemoveFinalizer(resource, v1alpha1.ArtifactFinalizer); removed {
159+
logger.V(1).Info("removing finalizer, restarting reconciler")
162160
if err := r.Update(ctx, resource); err != nil {
163161
return ctrl.Result{}, fmt.Errorf("failed to remove finalizer: %w", err)
164162
}
@@ -168,19 +166,16 @@ func (r *Reconciler) reconcileExists(ctx context.Context, resource *v1alpha1.Res
168166
}
169167

170168
if added := controllerutil.AddFinalizer(resource, v1alpha1.ArtifactFinalizer); added {
171-
err := r.Update(ctx, resource)
172-
if err != nil {
169+
logger.V(1).Info("adding finalizer, restarting reconciler")
170+
if err := r.Update(ctx, resource); err != nil {
173171
return ctrl.Result{}, fmt.Errorf("failed to add finalizer: %w", err)
174172
}
175173

176174
return ctrl.Result{Requeue: true}, nil
177175
}
178176

179-
return r.reconcile(ctx, resource)
180-
}
177+
logger.V(1).Info("checking if referenced component is ready")
181178

182-
func (r *Reconciler) reconcile(ctx context.Context, resource *v1alpha1.Resource) (ctrl.Result, error) {
183-
logger := log.FromContext(ctx)
184179
// Get component to resolve resource from component descriptor and verify digest
185180
component := &v1alpha1.Component{}
186181
if err := r.Get(ctx, types.NamespacedName{
@@ -203,13 +198,9 @@ func (r *Reconciler) reconcile(ctx context.Context, resource *v1alpha1.Resource)
203198
return ctrl.Result{}, errors.New("component is not ready")
204199
}
205200

206-
return r.reconcileOCM(ctx, resource, component)
207-
}
208-
209-
func (r *Reconciler) reconcileOCM(ctx context.Context, resource *v1alpha1.Resource, component *v1alpha1.Component) (ctrl.Result, error) {
210201
octx := ocmctx.New(datacontext.MODE_EXTENDED)
211202

212-
result, err := r.reconcileResource(ctx, octx, resource, component)
203+
result, err := r.reconcile(ctx, octx, resource, component)
213204

214205
// Always finalize ocm context after reconciliation
215206
err = errors.Join(err, octx.Finalize())
@@ -223,7 +214,7 @@ func (r *Reconciler) reconcileOCM(ctx context.Context, resource *v1alpha1.Resour
223214
return result, nil
224215
}
225216

226-
func (r *Reconciler) reconcileResource(ctx context.Context, octx ocmctx.Context, resource *v1alpha1.Resource, component *v1alpha1.Component) (ctrl.Result, error) {
217+
func (r *Reconciler) reconcile(ctx context.Context, octx ocmctx.Context, resource *v1alpha1.Resource, component *v1alpha1.Component) (ctrl.Result, error) {
227218
logger := log.FromContext(ctx)
228219
logger.V(1).Info("reconciling resource")
229220

internal/controller/resource/resource_controller_test.go

+59-16
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
artifactv1 "github.com/openfluxcd/artifact/api/v1alpha1"
3636
corev1 "k8s.io/api/core/v1"
3737
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
38+
"k8s.io/apimachinery/pkg/api/errors"
3839
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3940
. "ocm.software/ocm/api/helper/builder"
4041
environment "ocm.software/ocm/api/helper/env"
@@ -65,11 +66,10 @@ const (
6566

6667
var _ = Describe("Resource Controller", func() {
6768
var (
68-
ctx context.Context
69-
cancel context.CancelFunc
7069
env *Builder
7170
ctfPath string
7271
)
72+
7373
BeforeEach(func() {
7474
ctfPath = Must(os.MkdirTemp("", CTFPath))
7575
DeferCleanup(func() error {
@@ -78,31 +78,29 @@ var _ = Describe("Resource Controller", func() {
7878

7979
env = NewBuilder(environment.FileSystem(osfs.OsFs))
8080
DeferCleanup(env.Cleanup)
81-
82-
ctx, cancel = context.WithCancel(context.Background())
83-
DeferCleanup(cancel)
8481
})
8582

8683
Context("resource controller", func() {
8784
var (
8885
componentName string
86+
resourceName string
8987
testNumber int
90-
//componentObj *v1alpha1.Component
9188
)
9289

93-
BeforeEach(func() {
90+
BeforeEach(func(ctx SpecContext) {
9491
By("mocking the component controller")
9592
componentName = fmt.Sprintf("%s-%d", ComponentObj, testNumber)
93+
resourceName = fmt.Sprintf("%s-%d", ResourceObj, testNumber)
9694
mockComponentReconciler(ctx, env, ctfPath, componentName)
95+
testNumber++
9796
})
9897

99-
It("can reconcile a resource", func() {
100-
98+
FIt("can reconcile a resource", func(ctx SpecContext) {
10199
By("creating a resource object")
102100
resource := &v1alpha1.Resource{
103101
ObjectMeta: metav1.ObjectMeta{
104102
Namespace: Namespace,
105-
Name: ResourceObj,
103+
Name: resourceName,
106104
},
107105
Spec: v1alpha1.ResourceSpec{
108106
ComponentRef: corev1.LocalObjectReference{
@@ -117,26 +115,23 @@ var _ = Describe("Resource Controller", func() {
117115
},
118116
}
119117
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
120-
DeferCleanup(func(ctx SpecContext) {
121-
Expect(k8sClient.Delete(ctx, resource, client.PropagationPolicy(metav1.DeletePropagationForeground))).To(Succeed())
122-
})
123118

124119
By("checking that the resource has been reconciled successfully")
125-
Eventually(komega.Object(resource), "5m").Should(
120+
Eventually(komega.Object(resource), "15s", "100ms").Should(
126121
HaveField("Status.ObservedGeneration", Equal(int64(1))))
127122
Expect(resource).To(HaveField("Status.ArtifactRef.Name", Not(BeEmpty())))
128123
Expect(resource).To(HaveField("Status.Resource.Name", Equal(ResourceObj)))
129124
Expect(resource).To(HaveField("Status.Resource.Type", Equal(artifacttypes.PLAIN_TEXT)))
130125
Expect(resource).To(HaveField("Status.Resource.Version", Equal(ResourceVersion)))
131126

132-
By("checking that the artifact has been created successfully")
127+
By("checking that the resource artifact was created")
133128
artifact := &artifactv1.Artifact{
134129
ObjectMeta: metav1.ObjectMeta{
135130
Namespace: resource.Namespace,
136131
Name: resource.Status.ArtifactRef.Name,
137132
},
138133
}
139-
Eventually(komega.Get(artifact)).Should(Succeed())
134+
Eventually(komega.Get(artifact), "15s", "100ms").Should(Succeed())
140135

141136
By("checking that the artifact server provides the resource")
142137
r := Must(http.Get(artifact.Spec.URL))
@@ -152,11 +147,59 @@ var _ = Describe("Resource Controller", func() {
152147
resourceContent := Must(io.ReadAll(reader))
153148

154149
Expect(string(resourceContent)).To(Equal(ResourceContent))
150+
151+
By("checking that the resource is deleted correctly")
152+
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
153+
Eventually(komega.Object(resource), "15s").Should(HaveField("Status.DeletionTimestamp", Not(BeNil())))
154+
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(resource), resource)).To(Succeed())
155+
156+
// Simulate ownerreference deletion
157+
Expect(k8sClient.Delete(ctx, artifact)).To(Succeed())
158+
159+
Eventually(func(ctx SpecContext) error {
160+
return k8sClient.Get(ctx, client.ObjectKeyFromObject(resource), resource)
161+
}).WithContext(ctx).Should(Satisfy(errors.IsNotFound))
162+
})
163+
164+
It("stops when requirements are not met: component not found", func(ctx SpecContext) {
165+
By("creating a resource object")
166+
resource := &v1alpha1.Resource{
167+
ObjectMeta: metav1.ObjectMeta{
168+
Namespace: Namespace,
169+
Name: resourceName,
170+
},
171+
Spec: v1alpha1.ResourceSpec{
172+
ComponentRef: corev1.LocalObjectReference{
173+
Name: "anotherName",
174+
},
175+
Resource: v1alpha1.ResourceID{
176+
ByReference: v1alpha1.ResourceReference{
177+
Resource: v1.NewIdentity(ResourceObj),
178+
},
179+
},
180+
Interval: metav1.Duration{Duration: time.Minute * 5},
181+
},
182+
}
183+
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
184+
DeferCleanup(func(ctx SpecContext) {
185+
Expect(k8sClient.Delete(ctx, resource, client.PropagationPolicy(metav1.DeletePropagationForeground))).To(Succeed())
186+
})
187+
188+
By("checking that the resource was not reconciled successfully")
189+
Eventually(komega.Object(resource), "5m").Should(
190+
HaveField("Status.ObservedGeneration", Equal(int64(1))))
191+
Expect(resource).To(HaveField("Status.ArtifactRef.Name", Not(BeEmpty())))
192+
Expect(resource).To(HaveField("Status.Resource.Name", Equal(ResourceObj)))
193+
Expect(resource).To(HaveField("Status.Resource.Type", Equal(artifacttypes.PLAIN_TEXT)))
194+
Expect(resource).To(HaveField("Status.Resource.Version", Equal(ResourceVersion)))
195+
155196
})
156197
})
157198
})
158199

159200
func mockComponentReconciler(ctx context.Context, env *Builder, ctfPath, name string) {
201+
GinkgoHelper()
202+
160203
// Create a ctf storing a component-version with a blob data as content
161204
env.OCMCommonTransport(ctfPath, accessio.FormatDirectory, func() {
162205
env.Component(Component, func() {

internal/controller/resource/suite_test.go

+37-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import (
3232
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3333
"k8s.io/client-go/kubernetes/scheme"
3434
"k8s.io/client-go/rest"
35+
"k8s.io/client-go/tools/clientcmd"
36+
"k8s.io/client-go/tools/clientcmd/api"
3537
"k8s.io/client-go/tools/record"
3638
ctrl "sigs.k8s.io/controller-runtime"
3739
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -52,7 +54,7 @@ import (
5254

5355
const (
5456
ARTIFACT_PATH = "ocm-k8s-artifactstore--*"
55-
ARTIFACT_SERVER = "localhost:8081"
57+
ARTIFACT_SERVER = "localhost:8085"
5658
)
5759

5860
var cfg *rest.Config
@@ -91,6 +93,8 @@ var _ = BeforeSuite(func() {
9193
Expect(cfg).NotTo(BeNil())
9294
DeferCleanup(testEnv.Stop)
9395

96+
createKubeConfig(cfg)
97+
9498
Expect(v1alpha1.AddToScheme(scheme.Scheme)).Should(Succeed())
9599
Expect(artifactv1.AddToScheme(scheme.Scheme)).Should(Succeed())
96100
Expect(err).NotTo(HaveOccurred())
@@ -146,3 +150,35 @@ var _ = BeforeSuite(func() {
146150
Expect(k8sManager.Start(ctx)).To(Succeed())
147151
}()
148152
})
153+
154+
func createKubeConfig(cfg *rest.Config) {
155+
// Write the kubeconfig to the temporary file
156+
kubeconfig := api.Config{
157+
Clusters: map[string]*api.Cluster{
158+
"test-cluster": {
159+
Server: cfg.Host,
160+
CertificateAuthorityData: cfg.CAData,
161+
},
162+
},
163+
AuthInfos: map[string]*api.AuthInfo{
164+
"test-user": {
165+
ClientCertificateData: cfg.CertData,
166+
ClientKeyData: cfg.KeyData,
167+
},
168+
},
169+
Contexts: map[string]*api.Context{
170+
"test-context": {
171+
Cluster: "test-cluster",
172+
AuthInfo: "test-user",
173+
},
174+
},
175+
CurrentContext: "test-context",
176+
}
177+
178+
kubeconfigFile, err := os.Create(filepath.Join(os.Getenv("HOME"), ".kubeconfig.env"))
179+
180+
kubeconfigBytes, err := clientcmd.Write(kubeconfig)
181+
Expect(err).NotTo(HaveOccurred())
182+
_, err = kubeconfigFile.Write(kubeconfigBytes)
183+
Expect(err).NotTo(HaveOccurred())
184+
}

0 commit comments

Comments
 (0)