Skip to content

Commit acd93e6

Browse files
feat(juggler): add OCIRepositoryAdapter (#118)
* feat: add OCIRepositoryAdapter * test: OCIRepositoryAdapter GetHealthiness * feat: release v0.1.17 * feat(api): support for OCI URL in Helm chart declaration
1 parent 477d95e commit acd93e6

File tree

9 files changed

+200
-4
lines changed

9 files changed

+200
-4
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.1.16-dev
1+
v0.1.17

api/crds/manifests/core.orchestrate.cloud.sap_controlplanes.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ spec:
6868
repository:
6969
description: Repository is the URL to a Helm repository
7070
type: string
71+
url:
72+
description: URL is the URL to an OCI registry where the Helm
73+
chart is stored.
74+
type: string
7175
version:
7276
description: Version of the Helm chart, latest version if
7377
not set
@@ -97,6 +101,10 @@ spec:
97101
repository:
98102
description: Repository is the URL to a Helm repository
99103
type: string
104+
url:
105+
description: URL is the URL to an OCI registry where the Helm
106+
chart is stored.
107+
type: string
100108
version:
101109
description: Version of the Helm chart, latest version if
102110
not set
@@ -141,6 +149,10 @@ spec:
141149
repository:
142150
description: Repository is the URL to a Helm repository
143151
type: string
152+
url:
153+
description: URL is the URL to an OCI registry where the Helm
154+
chart is stored.
155+
type: string
144156
version:
145157
description: Version of the Helm chart, latest version if
146158
not set
@@ -259,6 +271,10 @@ spec:
259271
repository:
260272
description: Repository is the URL to a Helm repository
261273
type: string
274+
url:
275+
description: URL is the URL to an OCI registry where the Helm
276+
chart is stored.
277+
type: string
262278
version:
263279
description: Version of the Helm chart, latest version if
264280
not set
@@ -288,6 +304,10 @@ spec:
288304
repository:
289305
description: Repository is the URL to a Helm repository
290306
type: string
307+
url:
308+
description: URL is the URL to an OCI registry where the Helm
309+
chart is stored.
310+
type: string
291311
version:
292312
description: Version of the Helm chart, latest version if
293313
not set
@@ -317,6 +337,10 @@ spec:
317337
repository:
318338
description: Repository is the URL to a Helm repository
319339
type: string
340+
url:
341+
description: URL is the URL to an OCI registry where the Helm
342+
chart is stored.
343+
type: string
320344
version:
321345
description: Version of the Helm chart, latest version if
322346
not set

api/crds/manifests/core.orchestrate.cloud.sap_releasechannels.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ spec:
125125
description: if it's a helm chart, this specifies the
126126
helm repo
127127
type: string
128+
ociUrl:
129+
description: if the Helm chart is stored in an OCI registry,
130+
this specifies the OCI URL
131+
type: string
128132
version:
129133
description: The version number for that ComponentVersion
130134
type: string

api/v1beta1/controlplane_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ type ChartSpec struct {
8989
// Repository is the URL to a Helm repository
9090
Repository string `json:"repository,omitempty"`
9191

92+
// URL is the URL to an OCI registry where the Helm chart is stored.
93+
URL string `json:"url,omitempty"`
94+
9295
// Name of the Helm chart
9396
Name string `json:"name,omitempty"`
9497

api/v1beta1/releasechannel_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ type ComponentVersion struct {
7171
HelmRepo string `json:"helmRepo,omitempty"`
7272
// if it's a helm chart, this specifies the chart name
7373
HelmChart string `json:"helmChart,omitempty"`
74+
// if the Helm chart is stored in an OCI registry, this specifies the OCI URL
75+
OCIURL string `json:"ociUrl,omitempty"`
7476
}
7577

7678
// ReleaseChannel is the Schema for the ReleaseChannel API

charts/control-plane-operator/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ apiVersion: v2
22
name: control-plane-operator
33
description: A Helm chart for the Cloud Orchestration Control Plane Operator
44
type: application
5-
version: v0.1.16
6-
appVersion: v0.1.16
5+
version: v0.1.17
6+
appVersion: v0.1.17
77
home: https://github.com/openmcp-project/control-plane-operator
88
sources:
99
- https://github.com/openmcp-project/control-plane-operator

charts/control-plane-operator/values.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ image:
88
repository: ghcr.io/openmcp-project/images/control-plane-operator
99
pullPolicy: IfNotPresent
1010
# Overrides the image tag whose default is the chart appVersion.
11-
tag: v0.1.16
11+
tag: v0.1.17
1212

1313
imagePullSecrets: []
1414
nameOverride: ""

pkg/juggler/fluxcd/flux_sources.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,75 @@ func (g *GitRepositoryAdapter) ApplyDefaults() {
163163

164164
g.Source.Spec.Interval = metav1.Duration{Duration: 1 * time.Hour}
165165
}
166+
167+
//
168+
// -----------------------------------
169+
//
170+
171+
var _ SourceAdapter = &OCIRepositoryAdapter{}
172+
173+
// OCIRepositoryAdapter implements SourceAdapter
174+
type OCIRepositoryAdapter struct {
175+
Source *sourcev1.OCIRepository
176+
}
177+
178+
// ApplyDefaults implements SourceAdapter.
179+
func (o *OCIRepositoryAdapter) ApplyDefaults() {
180+
// This usually does nothing but we can keep it here in case Flux resources will have
181+
// a defaulting func in the future.
182+
scheme.Default(o.Source)
183+
184+
o.Source.Spec.Interval = metav1.Duration{Duration: 1 * time.Hour}
185+
}
186+
187+
// Empty implements SourceAdapter.
188+
func (o *OCIRepositoryAdapter) Empty() SourceAdapter {
189+
return &OCIRepositoryAdapter{&sourcev1.OCIRepository{
190+
ObjectMeta: metav1.ObjectMeta{
191+
Name: o.Source.Name,
192+
Namespace: o.Source.Namespace,
193+
},
194+
}}
195+
}
196+
197+
// GetHealthiness implements SourceAdapter.
198+
func (o *OCIRepositoryAdapter) GetHealthiness() juggler.ResourceHealthiness {
199+
cond := apimeta.FindStatusCondition(o.Source.Status.Conditions, fluxmeta.ReadyCondition)
200+
if cond == nil {
201+
return juggler.ResourceHealthiness{
202+
Healthy: false,
203+
Message: msgReadyNotPresent,
204+
}
205+
}
206+
return juggler.ResourceHealthiness{
207+
Healthy: cond.Status == metav1.ConditionTrue,
208+
Message: cond.Message,
209+
}
210+
}
211+
212+
// GetObject implements SourceAdapter.
213+
func (o *OCIRepositoryAdapter) GetObject() client.Object {
214+
return o.Source
215+
}
216+
217+
// GetObjectKey implements SourceAdapter.
218+
func (o *OCIRepositoryAdapter) GetObjectKey() client.ObjectKey {
219+
return client.ObjectKey{
220+
Namespace: o.Source.Namespace,
221+
Name: o.Source.Name,
222+
}
223+
}
224+
225+
// Reconcile implements SourceAdapter.
226+
func (o *OCIRepositoryAdapter) Reconcile(desired FluxResource) error {
227+
desiredAdapter, ok := desired.(*OCIRepositoryAdapter)
228+
if !ok {
229+
return errNotAGitRepositoryAdapter
230+
}
231+
232+
preserved := o.Source.Spec.DeepCopy()
233+
o.Source.Spec = desiredAdapter.Source.Spec
234+
// Give suspension precedence
235+
o.Source.Spec.Suspend = preserved.Suspend
236+
return nil
237+
}

pkg/juggler/fluxcd/flux_sources_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,94 @@ func TestGitRepositoryAdapter_GetHealthiness(t *testing.T) {
193193
})
194194
}
195195
}
196+
197+
func TestOCIRepositoryAdapter_GetHealthiness(t *testing.T) {
198+
tests := []struct {
199+
name string
200+
adapter OCIRepositoryAdapter
201+
expected juggler.ResourceHealthiness
202+
}{
203+
{
204+
name: "OCIRepositoryAdapter - Status Condition nil - Ready condition not present",
205+
adapter: OCIRepositoryAdapter{
206+
Source: &sourcev1.OCIRepository{
207+
Status: sourcev1.OCIRepositoryStatus{
208+
Conditions: nil,
209+
},
210+
},
211+
},
212+
expected: juggler.ResourceHealthiness{
213+
Healthy: false,
214+
Message: msgReadyNotPresent,
215+
},
216+
},
217+
{
218+
name: "OCIRepositoryAdapter - Status Condition Ready not found",
219+
adapter: OCIRepositoryAdapter{
220+
Source: &sourcev1.OCIRepository{
221+
Status: sourcev1.OCIRepositoryStatus{
222+
Conditions: []metav1.Condition{
223+
{
224+
Type: "NotReady", // can not be found
225+
Status: metav1.ConditionTrue,
226+
Message: "The release is ready",
227+
},
228+
},
229+
},
230+
},
231+
},
232+
expected: juggler.ResourceHealthiness{
233+
Healthy: false,
234+
Message: msgReadyNotPresent,
235+
},
236+
},
237+
{
238+
name: "OCIRepositoryAdapter - Status Condition Ready = True",
239+
adapter: OCIRepositoryAdapter{
240+
Source: &sourcev1.OCIRepository{
241+
Status: sourcev1.OCIRepositoryStatus{
242+
Conditions: []metav1.Condition{
243+
{
244+
Type: fluxmeta.ReadyCondition,
245+
Status: metav1.ConditionTrue,
246+
Message: "The release is ready",
247+
},
248+
},
249+
},
250+
},
251+
},
252+
expected: juggler.ResourceHealthiness{
253+
Healthy: true,
254+
Message: "The release is ready",
255+
},
256+
},
257+
{
258+
name: "OCIRepositoryAdapter - Status Condition Ready = False",
259+
adapter: OCIRepositoryAdapter{
260+
Source: &sourcev1.OCIRepository{
261+
Status: sourcev1.OCIRepositoryStatus{
262+
Conditions: []metav1.Condition{
263+
{
264+
Type: fluxmeta.ReadyCondition,
265+
Status: metav1.ConditionFalse,
266+
Message: "The release is not ready",
267+
},
268+
},
269+
},
270+
},
271+
},
272+
expected: juggler.ResourceHealthiness{
273+
Healthy: false,
274+
Message: "The release is not ready",
275+
},
276+
},
277+
}
278+
for _, tt := range tests {
279+
t.Run(tt.name, func(t *testing.T) {
280+
actual := tt.adapter.GetHealthiness()
281+
if !assert.Equal(t, tt.expected, actual) {
282+
t.Errorf("OCIRepositoryAdapter.GetHealthiness() = %v, want %v", actual, tt.expected)
283+
}
284+
})
285+
}
286+
}

0 commit comments

Comments
 (0)