Skip to content

Commit 9fa1e43

Browse files
Merge pull request #137 from cloudogu/feature/135_external_blueprint_mask
External blueprint mask
2 parents ca33091 + a7352d3 commit 9fa1e43

37 files changed

+2216
-387
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010

1111
### Added
1212
- [#121] Added use case to check if dogus actually use the desired version and config before completing the blueprint
13+
- [#135] Support for the blueprint mask custom resource.
1314
- [#129] Reconciliation of the blueprint on changes of dogu-crs, ces-configMaps and ces-secrets
1415
- [#131] Ignore loglevel changes while debug-mode is active
1516

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/Masterminds/semver/v3 v3.4.0
77
github.com/cloudogu/ces-commons-lib v0.2.0
88
github.com/cloudogu/cesapp-lib v0.18.1
9-
github.com/cloudogu/k8s-blueprint-lib/v2 v2.0.0-20251023074126-1be92019bece
9+
github.com/cloudogu/k8s-blueprint-lib/v3 v3.0.0
1010
github.com/cloudogu/k8s-debug-mode-cr-lib v1.0.0
1111
github.com/cloudogu/k8s-dogu-lib/v2 v2.10.0
1212
github.com/cloudogu/k8s-registry-lib v0.6.0
@@ -15,7 +15,7 @@ require (
1515
github.com/google/go-cmp v0.7.0
1616
github.com/stretchr/testify v1.11.1
1717
go.uber.org/zap v1.27.0
18-
golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b
18+
golang.org/x/exp v0.0.0-20251017212417-90e834f514db
1919
golang.org/x/net v0.46.0
2020
k8s.io/api v0.34.1
2121
k8s.io/apimachinery v0.34.1
@@ -71,7 +71,7 @@ require (
7171
github.com/prometheus/client_golang v1.23.2 // indirect
7272
github.com/prometheus/client_model v0.6.2 // indirect
7373
github.com/prometheus/common v0.67.1 // indirect
74-
github.com/prometheus/procfs v0.17.0 // indirect
74+
github.com/prometheus/procfs v0.18.0 // indirect
7575
github.com/sirupsen/logrus v1.9.3 // indirect
7676
github.com/spf13/pflag v1.0.10 // indirect
7777
github.com/stretchr/objx v0.5.2 // indirect

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@ github.com/cloudogu/ces-commons-lib v0.2.0 h1:yOEZWFl4W9N3J/6fok4svE3UufK5GQQtyx
1818
github.com/cloudogu/ces-commons-lib v0.2.0/go.mod h1:4rvR2RTDDaz5a6OZ1fW27G0MOnl5I3ackeiHxt4gn3o=
1919
github.com/cloudogu/cesapp-lib v0.18.1 h1:LMdGktIefm/PuhdPqpLTPvjY1smO06EEGBbRSAaYi7U=
2020
github.com/cloudogu/cesapp-lib v0.18.1/go.mod h1:J05eXFxnz4enZblABlmiVTZaUtJ+LIhlJ2UF6l9jpDw=
21-
github.com/cloudogu/k8s-blueprint-lib/v2 v2.0.0-20251023074126-1be92019bece h1:/cmnzgb6bafAeBT/9e0AvV/S1UZtc+mk8Gqo/ccLf6g=
22-
github.com/cloudogu/k8s-blueprint-lib/v2 v2.0.0-20251023074126-1be92019bece/go.mod h1:Qyi8M+HJMHJfhXN6Zotey/tXjFuJDM9RIXn+FjQaJAU=
23-
github.com/cloudogu/k8s-blueprint-lib/v2 v2.0.0 h1:3opEauJ733KlUEhsBVDpi4MdYeiEXg63oedX+/F2Btk=
24-
github.com/cloudogu/k8s-blueprint-lib/v2 v2.0.0/go.mod h1:Qyi8M+HJMHJfhXN6Zotey/tXjFuJDM9RIXn+FjQaJAU=
21+
github.com/cloudogu/k8s-blueprint-lib/v3 v3.0.0 h1:XDWrVVmQ1aJ00aisCNQ1nJqOHVK9LB3q92swJFMZEFg=
22+
github.com/cloudogu/k8s-blueprint-lib/v3 v3.0.0/go.mod h1:3E1iLra8//8+kCwBjuDi6b0iwtNoArYfOIYnzNXSFMQ=
2523
github.com/cloudogu/k8s-debug-mode-cr-lib v1.0.0 h1:geZjXwWQY8d8aEWA9l2is/DwlADdOHQveBokPK63XH0=
2624
github.com/cloudogu/k8s-debug-mode-cr-lib v1.0.0/go.mod h1:OPAO5P5ZSZkEexP9YOWNj4wEE8T3wqs92yyP5muymxQ=
2725
github.com/cloudogu/k8s-dogu-lib/v2 v2.10.0 h1:flTmcBHzHU6uiwpXnlxLi93sKmYD85pul//8KxkkgGI=
@@ -184,6 +182,8 @@ github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oE
184182
github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q=
185183
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
186184
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
185+
github.com/prometheus/procfs v0.18.0 h1:2QTA9cKdznfYJz7EDaa7IiJobHuV7E1WzeBwcrhk0ao=
186+
github.com/prometheus/procfs v0.18.0/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
187187
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
188188
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
189189
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
@@ -249,6 +249,8 @@ golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
249249
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
250250
golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA=
251251
golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
252+
golang.org/x/exp v0.0.0-20251017212417-90e834f514db h1:by6IehL4BH5k3e3SJmcoNbOobMey2SLpAF79iPOEBvw=
253+
golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
252254
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
253255
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
254256
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=

k8s/helm/Chart.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ version: 0.0.0-replaceme
2424
appVersion: "0.0.0-replaceme"
2525

2626
annotations:
27-
"k8s.cloudogu.com/ces-dependency/k8s-blueprint-operator-crd": ">=2.0.0, <3.0.0"
28-
"k8s.cloudogu.com/ces-dependency/k8s-dogu-operator-crd": ">=2.10.0, <3.0.0"
27+
# we need the -0 as otherwise we cannot depend on (and therefore test) pre-release versions
28+
"k8s.cloudogu.com/ces-dependency/k8s-blueprint-operator-crd": ">=3.0.0-0, <4.0.0"
29+
"k8s.cloudogu.com/ces-dependency/k8s-dogu-operator-crd": ">=2.10.0-0, <3.0.0"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: Role
3+
metadata:
4+
labels:
5+
{{- include "k8s-blueprint-operator.labels" . | nindent 4 }}
6+
name: {{ include "k8s-blueprint-operator.name" . }}-blueprint-mask-role
7+
rules:
8+
# issue permissions to read/update fields beyond the status
9+
- apiGroups:
10+
- k8s.cloudogu.com
11+
resources:
12+
- blueprintmasks
13+
verbs:
14+
- get
15+
- list
16+
- watch
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: RoleBinding
3+
metadata:
4+
labels:
5+
{{- include "k8s-blueprint-operator.labels" . | nindent 4 }}
6+
name: {{ include "k8s-blueprint-operator.name" . }}-blueprint-mask-rolebinding
7+
roleRef:
8+
apiGroup: rbac.authorization.k8s.io
9+
kind: Role
10+
name: {{ include "k8s-blueprint-operator.name" . }}-blueprint-mask-role
11+
subjects:
12+
- kind: ServiceAccount
13+
name: {{ include "k8s-blueprint-operator.name" . }}-controller-manager

main.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"os"
88
"time"
99

10-
bpv2 "github.com/cloudogu/k8s-blueprint-lib/v2/api/v2"
10+
bpv3 "github.com/cloudogu/k8s-blueprint-lib/v3/api/v3"
1111
"github.com/cloudogu/k8s-blueprint-operator/v2/pkg"
1212
"github.com/cloudogu/k8s-blueprint-operator/v2/pkg/adapter/reconciler"
1313
"github.com/cloudogu/k8s-blueprint-operator/v2/pkg/config"
@@ -46,7 +46,7 @@ var (
4646
func init() {
4747
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
4848

49-
utilruntime.Must(bpv2.AddToScheme(scheme))
49+
utilruntime.Must(bpv3.AddToScheme(scheme))
5050
utilruntime.Must(v2.AddToScheme(scheme))
5151
// +kubebuilder:scaffold:scheme
5252
}
@@ -86,7 +86,7 @@ func startOperator(
8686
return fmt.Errorf("unable to bootstrap application context: %w", err)
8787
}
8888

89-
err = configureManager(k8sManager, bootstrap.Reconciler)
89+
err = configureManager(k8sManager, bootstrap.BlueprintReconciler)
9090
if err != nil {
9191
return fmt.Errorf("unable to configure manager: %w", err)
9292
}
@@ -110,7 +110,7 @@ func NewK8sManager(
110110
func configureManager(k8sManager controllerManager, blueprintReconciler *reconciler.BlueprintReconciler) error {
111111
err := blueprintReconciler.SetupWithManager(k8sManager)
112112
if err != nil {
113-
return fmt.Errorf("unable to configure reconciler: %w", err)
113+
return fmt.Errorf("unable to configure blueprint reconciler: %w", err)
114114
}
115115

116116
err = addChecks(k8sManager)

main_internal_test.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@ import (
1111
"github.com/stretchr/testify/require"
1212

1313
"k8s.io/apimachinery/pkg/runtime"
14-
"k8s.io/apimachinery/pkg/runtime/schema"
1514
"k8s.io/client-go/rest"
1615
ctrl "sigs.k8s.io/controller-runtime"
1716
"sigs.k8s.io/controller-runtime/pkg/config"
1817
"sigs.k8s.io/controller-runtime/pkg/manager"
1918

20-
bpv2 "github.com/cloudogu/k8s-blueprint-lib/v2/api/v2"
19+
bpv3 "github.com/cloudogu/k8s-blueprint-lib/v3/api/v3"
2120
config2 "github.com/cloudogu/k8s-blueprint-operator/v2/pkg/config"
2221
)
2322

@@ -173,7 +172,7 @@ func Test_startOperator(t *testing.T) {
173172
require.Error(t, err)
174173
assert.ErrorContains(t, err, "unable to bootstrap application context: failed to get remote dogu registry credentials: environment variable DOGU_REGISTRY_PASSWORD must be set")
175174
})
176-
t.Run("should fail to configure reconciler", func(t *testing.T) {
175+
t.Run("should fail to configure blueprint reconciler", func(t *testing.T) {
177176
// given
178177
t.Setenv("NAMESPACE", "ecosystem")
179178
t.Setenv("STAGE", "development")
@@ -212,7 +211,7 @@ func Test_startOperator(t *testing.T) {
212211

213212
// then
214213
require.Error(t, err)
215-
assert.ErrorContains(t, err, "unable to configure manager: unable to configure reconciler")
214+
assert.ErrorContains(t, err, "unable to configure manager: unable to configure blueprint reconciler")
216215
})
217216
t.Run("should fail to add health check to controller manager", func(t *testing.T) {
218217
// given
@@ -427,12 +426,8 @@ func Test_startOperator(t *testing.T) {
427426

428427
func createScheme(t *testing.T) *runtime.Scheme {
429428
t.Helper()
430-
431429
scheme := runtime.NewScheme()
432-
gv, err := schema.ParseGroupVersion("k8s.cloudogu.com/v2")
433-
assert.NoError(t, err)
434-
435-
scheme.AddKnownTypes(gv, &bpv2.Blueprint{})
430+
scheme.AddKnownTypes(bpv3.GroupVersion, &bpv3.Blueprint{}, &bpv3.BlueprintMask{})
436431
return scheme
437432
}
438433

pkg/adapter/kubernetes/blueprintcr/v2/interfaces.go

Lines changed: 0 additions & 14 deletions
This file was deleted.

pkg/adapter/kubernetes/blueprintcr/v2/blueprintSpecCRRepository.go renamed to pkg/adapter/kubernetes/blueprintcr/v3/blueprintSpecCRRepository.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
package v2
1+
package v3
22

33
import (
44
"context"
55
"errors"
66
"fmt"
77

8-
v2 "github.com/cloudogu/k8s-blueprint-lib/v2/api/v2"
9-
serializerv2 "github.com/cloudogu/k8s-blueprint-operator/v2/pkg/adapter/kubernetes/blueprintcr/v2/serializer"
8+
bpv3 "github.com/cloudogu/k8s-blueprint-lib/v3/api/v3"
9+
serializerv2 "github.com/cloudogu/k8s-blueprint-operator/v2/pkg/adapter/kubernetes/blueprintcr/v3/serializer"
1010
corev1 "k8s.io/api/core/v1"
1111
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"k8s.io/utils/ptr"
1414
"sigs.k8s.io/controller-runtime/pkg/log"
1515

16-
bpv2client "github.com/cloudogu/k8s-blueprint-lib/v2/client"
16+
bpv3client "github.com/cloudogu/k8s-blueprint-lib/v3/client"
1717
"github.com/cloudogu/k8s-blueprint-operator/v2/pkg/domain"
1818
"github.com/cloudogu/k8s-blueprint-operator/v2/pkg/domainservice"
1919
)
@@ -25,18 +25,21 @@ type blueprintSpecRepoContext struct {
2525
}
2626

2727
type blueprintSpecRepo struct {
28-
blueprintClient blueprintInterface
29-
eventRecorder eventRecorder
28+
blueprintClient blueprintInterface
29+
blueprintMaskClient blueprintMaskInterface
30+
eventRecorder eventRecorder
3031
}
3132

3233
// NewBlueprintSpecRepository returns a new BlueprintSpecRepository to interact on BlueprintSpecs.
3334
func NewBlueprintSpecRepository(
34-
blueprintClient bpv2client.BlueprintInterface,
35+
blueprintClient bpv3client.BlueprintInterface,
36+
blueprintMaskClient bpv3client.BlueprintMaskInterface,
3537
eventRecorder eventRecorder,
3638
) domainservice.BlueprintSpecRepository {
3739
return &blueprintSpecRepo{
38-
blueprintClient: blueprintClient,
39-
eventRecorder: eventRecorder,
40+
blueprintClient: blueprintClient,
41+
blueprintMaskClient: blueprintMaskClient,
42+
eventRecorder: eventRecorder,
4043
}
4144
}
4245

@@ -79,7 +82,12 @@ func (repo *blueprintSpecRepo) GetById(ctx context.Context, blueprintId string)
7982
},
8083
}
8184

82-
err = serializerv2.SerializeBlueprintAndMask(blueprintSpec, blueprintCR)
85+
maskManifest, err := repo.getMaskManifest(ctx, blueprintId, blueprintCR)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
err = serializerv2.SerializeBlueprintAndMask(blueprintSpec, blueprintCR.Spec.Blueprint, maskManifest)
8391
if err != nil {
8492
invalidErrorEvent := domain.BlueprintSpecInvalidEvent{ValidationError: err}
8593
repo.eventRecorder.Event(blueprintCR, corev1.EventTypeWarning, invalidErrorEvent.Name(), invalidErrorEvent.Message())
@@ -90,6 +98,30 @@ func (repo *blueprintSpecRepo) GetById(ctx context.Context, blueprintId string)
9098
return blueprintSpec, nil
9199
}
92100

101+
func (repo *blueprintSpecRepo) getMaskManifest(ctx context.Context, blueprintId string, blueprintCR *bpv3.Blueprint) (*bpv3.BlueprintMaskManifest, error) {
102+
if blueprintCR.Spec.MaskSource.Manifest != nil && blueprintCR.Spec.MaskSource.CrRef != nil {
103+
err := &domain.InvalidBlueprintError{Message: "blueprint mask and mask ref cannot be set at the same time"}
104+
invalidErrorEvent := domain.BlueprintSpecInvalidEvent{ValidationError: err}
105+
repo.eventRecorder.Event(blueprintCR, corev1.EventTypeWarning, invalidErrorEvent.Name(), invalidErrorEvent.Message())
106+
return nil, fmt.Errorf("could not deserialize blueprint CR %q: %w", blueprintId, err)
107+
}
108+
109+
var maskManifest = blueprintCR.Spec.MaskSource.Manifest
110+
if blueprintCR.Spec.MaskSource.CrRef != nil {
111+
blueprintMask, maskErr := repo.blueprintMaskClient.Get(ctx, blueprintCR.Spec.MaskSource.CrRef.Name, metav1.GetOptions{})
112+
if maskErr != nil {
113+
return nil, &domainservice.NotFoundError{
114+
WrappedError: maskErr,
115+
Message: fmt.Sprintf("could not get blueprint mask from ref %q in blueprint %q", blueprintCR.Spec.MaskSource.CrRef.Name, blueprintId),
116+
DoNotRetry: false,
117+
}
118+
}
119+
120+
maskManifest = blueprintMask.Spec.BlueprintMaskManifest
121+
}
122+
return maskManifest, nil
123+
}
124+
93125
func (repo *blueprintSpecRepo) Count(ctx context.Context, limit int) (int, error) {
94126
limit64 := int64(limit)
95127

@@ -135,13 +167,13 @@ func (repo *blueprintSpecRepo) Update(ctx context.Context, spec *domain.Blueprin
135167

136168
effectiveBlueprint := serializerv2.ConvertToBlueprintDTO(spec.EffectiveBlueprint)
137169

138-
updatedBlueprint := &v2.Blueprint{
170+
updatedBlueprint := &bpv3.Blueprint{
139171
ObjectMeta: metav1.ObjectMeta{
140172
Name: spec.Id,
141173
ResourceVersion: persistenceContext.resourceVersion,
142174
CreationTimestamp: metav1.Time{},
143175
},
144-
Status: &v2.BlueprintStatus{
176+
Status: &bpv3.BlueprintStatus{
145177
EffectiveBlueprint: &effectiveBlueprint,
146178
StateDiff: serializerv2.ConvertToStateDiffDTO(spec.StateDiff),
147179
Conditions: spec.Conditions,
@@ -165,7 +197,7 @@ func (repo *blueprintSpecRepo) Update(ctx context.Context, spec *domain.Blueprin
165197
return nil
166198
}
167199

168-
func setPersistenceContext(blueprintCR *v2.Blueprint, spec *domain.BlueprintSpec) {
200+
func setPersistenceContext(blueprintCR *bpv3.Blueprint, spec *domain.BlueprintSpec) {
169201
if spec.PersistenceContext == nil {
170202
spec.PersistenceContext = make(map[string]interface{}, 1)
171203
}
@@ -195,7 +227,7 @@ func getPersistenceContext(ctx context.Context, spec *domain.BlueprintSpec) (blu
195227
}
196228
}
197229

198-
func (repo *blueprintSpecRepo) publishEvents(blueprintCR *v2.Blueprint, events []domain.Event) {
230+
func (repo *blueprintSpecRepo) publishEvents(blueprintCR *bpv3.Blueprint, events []domain.Event) {
199231
for _, event := range events {
200232
repo.eventRecorder.Event(blueprintCR, corev1.EventTypeNormal, event.Name(), event.Message())
201233
}

0 commit comments

Comments
 (0)