Skip to content

Commit 7d4960f

Browse files
authored
Feat/organization idp setup (#19)
* feat: added default subroutine for realm creation On-behalf-of: SAP [email protected] * feat: switched from helm to flux On-behalf-of: SAP [email protected] * feat: added oci repos and helm releases creation On-behalf-of: SAP [email protected] * feat: added values substitution On-behalf-of: SAP [email protected] * feat: added tests, code refactoring On-behalf-of: SAP [email protected] * chore: code refactoring On-behalf-of: SAP [email protected] * chore: more refactoring On-behalf-of: SAP [email protected] * fix: removed file reading, fixed naming On-behalf-of: SAP [email protected] * chore: tests refactoring On-behalf-of: SAP [email protected] * chore: added tests for getting workspace name On-behalf-of: SAP [email protected] * chore: fixed linter and tests issues On-behalf-of: SAP [email protected] * chore: more refactoring On-behalf-of: SAP [email protected] * added requeue after for finalize function, updated oci repo yaml On-behalf-of: SAP [email protected] * chore: tests update On-behalf-of: SAP [email protected] * chore: linter version bump On-behalf-of: SAP [email protected] * fix: fixed linter installing path On-behalf-of: SAP [email protected] * removed requeue after On-behalf-of: SAP [email protected] * fix: updated go mod file On-behalf-of: SAP [email protected]
1 parent 21ba16f commit 7d4960f

File tree

11 files changed

+604
-12
lines changed

11 files changed

+604
-12
lines changed

Taskfile.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ vars:
88
CRD_DIRECTORY: config/crd/bases
99
KCP_APIGEN_VERSION: v0.21.0
1010
KCP_VERSION: 0.26.1
11-
GOLANGCI_LINT_VERSION: v1.64.8
11+
GOLANGCI_LINT_VERSION: v2.4.0
1212
GOARCH:
1313
sh: go env GOARCH
1414
GOOS:
@@ -29,7 +29,7 @@ tasks:
2929
setup:golangci-lint:
3030
internal: true
3131
cmds:
32-
- test -s {{.LOCAL_BIN}}/golangci-lint || GOBIN=$(pwd)/{{.LOCAL_BIN}} go install github.com/golangci/golangci-lint/cmd/golangci-lint@{{.GOLANGCI_LINT_VERSION}}
32+
- test -s {{.LOCAL_BIN}}/golangci-lint || GOBIN=$(pwd)/{{.LOCAL_BIN}} go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@{{.GOLANGCI_LINT_VERSION}}
3333
setup:docker-compose:
3434
internal: true
3535
cmds:

cmd/initializer.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ import (
44
"crypto/tls"
55
"os"
66

7+
helmv2 "github.com/fluxcd/helm-controller/api/v2"
8+
sourcev1 "github.com/fluxcd/source-controller/api/v1"
79
"github.com/kcp-dev/logicalcluster/v3"
810
"github.com/spf13/cobra"
11+
"k8s.io/apimachinery/pkg/runtime"
12+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
913
"k8s.io/client-go/rest"
1014
ctrl "sigs.k8s.io/controller-runtime"
15+
"sigs.k8s.io/controller-runtime/pkg/client"
1116
"sigs.k8s.io/controller-runtime/pkg/healthz"
1217
"sigs.k8s.io/controller-runtime/pkg/kcp"
1318
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
@@ -51,13 +56,29 @@ var initializerCmd = &cobra.Command{
5156
os.Exit(1)
5257
}
5358

59+
runtimeScheme := runtime.NewScheme()
60+
utilruntime.Must(sourcev1.AddToScheme(runtimeScheme))
61+
utilruntime.Must(helmv2.AddToScheme(runtimeScheme))
62+
5463
orgClient, err := logicalClusterClientFromKey(mgr, log)(logicalcluster.Name("root:orgs"))
5564
if err != nil {
5665
setupLog.Error(err, "Failed to create org client")
5766
os.Exit(1)
5867
}
5968

60-
if err := controller.NewLogicalClusterReconciler(log, mgrCfg, mgr.GetClient(), orgClient, appCfg).SetupWithManager(mgr, defaultCfg, log); err != nil {
69+
inClusterConfig, err := rest.InClusterConfig()
70+
if err != nil {
71+
log.Error().Err(err).Msg("Failed to create in cluster config")
72+
os.Exit(1)
73+
}
74+
75+
inClusterClient, err := client.New(inClusterConfig, client.Options{Scheme: scheme})
76+
if err != nil {
77+
log.Error().Err(err).Msg("Failed to create in cluster client")
78+
os.Exit(1)
79+
}
80+
81+
if err := controller.NewLogicalClusterReconciler(log, mgrCfg, mgr.GetClient(), orgClient, appCfg, inClusterClient).SetupWithManager(mgr, defaultCfg, log); err != nil {
6182
setupLog.Error(err, "unable to create controller", "controller", "LogicalCluster")
6283
os.Exit(1)
6384
}

go.mod

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ require (
2929
sigs.k8s.io/controller-runtime v0.21.0
3030
)
3131

32+
require (
33+
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
34+
github.com/fluxcd/pkg/apis/acl v0.7.0 // indirect
35+
github.com/fluxcd/pkg/apis/kustomize v1.10.0 // indirect
36+
github.com/fluxcd/pkg/apis/meta v1.12.0 // indirect
37+
)
38+
3239
require (
3340
github.com/99designs/gqlgen v0.17.78 // indirect
3441
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
@@ -39,6 +46,8 @@ require (
3946
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
4047
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
4148
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
49+
github.com/fluxcd/helm-controller/api v1.3.0
50+
github.com/fluxcd/source-controller/api v1.6.2
4251
github.com/fsnotify/fsnotify v1.9.0 // indirect
4352
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
4453
github.com/getsentry/sentry-go v0.35.1 // indirect
@@ -118,6 +127,6 @@ require (
118127
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d // indirect
119128
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
120129
sigs.k8s.io/randfill v1.0.0 // indirect
121-
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
122-
sigs.k8s.io/yaml v1.6.0 // indirect
130+
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
131+
sigs.k8s.io/yaml v1.6.0
123132
)

go.sum

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,20 @@ github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtz
2424
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
2525
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
2626
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
27-
github.com/evanphx/json-patch v5.8.0+incompatible h1:1Av9pn2FyxPdvrWNQszj1g6D6YthSmvCfcN6SYclTJg=
28-
github.com/evanphx/json-patch v5.8.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
27+
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
28+
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
2929
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
3030
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
31+
github.com/fluxcd/helm-controller/api v1.3.0 h1:PupXPuQbksmU0g2Lc6NjIYal2HJGL+6xohsf82eGVjo=
32+
github.com/fluxcd/helm-controller/api v1.3.0/go.mod h1:4b8PfdH0e/9Pfol2ogdMYbQ1nLjcVu9gAv27cQzIPK4=
33+
github.com/fluxcd/pkg/apis/acl v0.7.0 h1:dMhZJH+g6ZRPjs4zVOAN9vHBd1DcavFgcIFkg5ooOE0=
34+
github.com/fluxcd/pkg/apis/acl v0.7.0/go.mod h1:uv7pXXR/gydiX4MUwlQa7vS8JONEDztynnjTvY3JxKQ=
35+
github.com/fluxcd/pkg/apis/kustomize v1.10.0 h1:47EeSzkQvlQZdH92vHMe2lK2iR8aOSEJq95avw5idts=
36+
github.com/fluxcd/pkg/apis/kustomize v1.10.0/go.mod h1:UsqMV4sqNa1Yg0pmTsdkHRJr7bafBOENIJoAN+3ezaQ=
37+
github.com/fluxcd/pkg/apis/meta v1.12.0 h1:XW15TKZieC2b7MN8VS85stqZJOx+/b8jATQ/xTUhVYg=
38+
github.com/fluxcd/pkg/apis/meta v1.12.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI=
39+
github.com/fluxcd/source-controller/api v1.6.2 h1:UmodAeqLIeF29HdTqf2GiacZyO+hJydJlepDaYsMvhc=
40+
github.com/fluxcd/source-controller/api v1.6.2/go.mod h1:ZJcAi0nemsnBxjVgmJl0WQzNvB0rMETxQMTdoFosmMw=
3141
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
3242
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
3343
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
@@ -321,8 +331,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh
321331
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
322332
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
323333
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
324-
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
325-
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
334+
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
335+
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
326336
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
327337
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
328338
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ type Config struct {
77
} `mapstructure:",squash"`
88
APIExportEndpointSliceName string `mapstructure:"api-export-endpoint-slice-name"`
99
CoreModulePath string `mapstructure:"core-module-path"`
10+
WorkspaceDir string `mapstructure:"workspace-dir" default:"/operator/"`
1011
}

internal/controller/initializer_controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ type LogicalClusterReconciler struct {
2121
lifecycle *lifecyclecontrollerruntime.LifecycleManager
2222
}
2323

24-
func NewLogicalClusterReconciler(log *logger.Logger, restCfg *rest.Config, cl, orgClient client.Client, cfg config.Config) *LogicalClusterReconciler {
24+
func NewLogicalClusterReconciler(log *logger.Logger, restCfg *rest.Config, cl, orgClient client.Client, cfg config.Config, inClusterClient client.Client) *LogicalClusterReconciler {
2525
return &LogicalClusterReconciler{
2626
lifecycle: lifecyclecontrollerruntime.NewLifecycleManager(
2727
[]lifecyclesubroutine.Subroutine{
2828
subroutine.NewWorkspaceInitializer(cl, orgClient, restCfg, cfg),
29+
subroutine.NewRealmSubroutine(inClusterClient),
2930
},
3031
"logicalcluster",
3132
"LogicalClusterReconciler",
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: helm.toolkit.fluxcd.io/v2
2+
kind: HelmRelease
3+
metadata:
4+
name: organization-idp
5+
namespace: default
6+
spec:
7+
interval: 10m
8+
timeout: 20m
9+
chartRef:
10+
kind: OCIRepository
11+
name: organization-idp
12+
releaseName: organization-idp
13+
targetNamespace: default
14+
values:
15+
imagePullSecret: github
16+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: source.toolkit.fluxcd.io/v1
2+
kind: OCIRepository
3+
metadata:
4+
name: organization-idp
5+
namespace: default
6+
spec:
7+
interval: 5m
8+
url: oci://ghcr.io/platform-mesh/helm-charts/organization-idp
9+
ref:
10+
semver: "0.1.0"
11+
secretRef:
12+
name: github
13+

internal/subroutine/realm.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
package subroutine
2+
3+
import (
4+
"bytes"
5+
"context"
6+
_ "embed"
7+
"encoding/json"
8+
"fmt"
9+
"strings"
10+
"text/template"
11+
12+
kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
13+
lifecycleruntimeobject "github.com/platform-mesh/golang-commons/controller/lifecycle/runtimeobject"
14+
lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine"
15+
"github.com/platform-mesh/golang-commons/errors"
16+
"github.com/platform-mesh/golang-commons/logger"
17+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
18+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
19+
ctrl "sigs.k8s.io/controller-runtime"
20+
"sigs.k8s.io/controller-runtime/pkg/client"
21+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
22+
"sigs.k8s.io/yaml"
23+
)
24+
25+
var (
26+
//go:embed manifests/organizationIdp/repository.yaml
27+
repository string
28+
29+
//go:embed manifests/organizationIdp/helmrelease.yaml
30+
helmRelease string
31+
)
32+
33+
type realmSubroutine struct {
34+
k8s client.Client
35+
}
36+
37+
func NewRealmSubroutine(k8s client.Client) *realmSubroutine {
38+
return &realmSubroutine{
39+
k8s: k8s,
40+
}
41+
}
42+
43+
var _ lifecyclesubroutine.Subroutine = &realmSubroutine{}
44+
45+
func (r *realmSubroutine) GetName() string { return "Realm" }
46+
47+
func (r *realmSubroutine) Finalizers() []string { return []string{} }
48+
49+
func (r *realmSubroutine) Finalize(ctx context.Context, instance lifecycleruntimeobject.RuntimeObject) (reconcile.Result, errors.OperatorError) {
50+
log := logger.LoadLoggerFromContext(ctx)
51+
52+
lc := instance.(*kcpv1alpha1.LogicalCluster)
53+
workspaceName := getWorkspaceName(lc)
54+
if workspaceName == "" {
55+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to get workspace path"), true, false)
56+
}
57+
58+
ociObj, err := unstructuredFromString(repository, nil, log)
59+
if err != nil {
60+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to load OCI repository manifest: %w", err), true, true)
61+
}
62+
if err := r.k8s.Delete(ctx, &ociObj); err != nil {
63+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to delete OCI repository: %w", err), true, true)
64+
}
65+
66+
helmObj, err := unstructuredFromString(helmRelease, nil, log)
67+
if err != nil {
68+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to load HelmRelease manifest: %w", err), true, true)
69+
}
70+
helmObj.SetName(workspaceName)
71+
if err := r.k8s.Delete(ctx, &helmObj); err != nil {
72+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to delete HelmRelease: %w", err), true, true)
73+
}
74+
75+
log.Info().Str("realm", workspaceName).Msg("Successfully finalized resources")
76+
return ctrl.Result{}, nil
77+
}
78+
79+
func (r *realmSubroutine) Process(ctx context.Context, instance lifecycleruntimeobject.RuntimeObject) (reconcile.Result, errors.OperatorError) {
80+
lc := instance.(*kcpv1alpha1.LogicalCluster)
81+
82+
workspaceName := getWorkspaceName(lc)
83+
if workspaceName == "" {
84+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to get workspace path"), true, false)
85+
}
86+
87+
patch := map[string]interface{}{
88+
"crossplane": map[string]interface{}{
89+
"realm": map[string]interface{}{
90+
"name": workspaceName,
91+
"displayName": workspaceName,
92+
},
93+
"client": map[string]interface{}{
94+
"name": workspaceName,
95+
"displayName": workspaceName,
96+
},
97+
},
98+
"keycloakConfig": map[string]interface{}{
99+
"client": map[string]interface{}{
100+
"name": workspaceName,
101+
"targetSecret": map[string]interface{}{
102+
"name": fmt.Sprintf("portal-client-secret-%s", workspaceName),
103+
},
104+
},
105+
},
106+
}
107+
108+
marshalledPatch, err := json.Marshal(patch)
109+
if err != nil {
110+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to marshall patch map: %w", err), true, true)
111+
}
112+
113+
values := apiextensionsv1.JSON{Raw: marshalledPatch}
114+
releaseName := fmt.Sprintf("%s-idp", workspaceName)
115+
116+
err = applyManifestWithMergedValues(ctx, repository, r.k8s, nil)
117+
if err != nil {
118+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to create OCI repository: %w", err), true, true)
119+
}
120+
121+
err = applyReleaseWithValues(ctx, helmRelease, r.k8s, values, releaseName)
122+
if err != nil {
123+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to create HelmRelease: %w", err), true, true)
124+
}
125+
126+
return ctrl.Result{}, nil
127+
}
128+
129+
func getWorkspaceName(lc *kcpv1alpha1.LogicalCluster) string {
130+
if path, ok := lc.Annotations["kcp.io/path"]; ok {
131+
pathElements := strings.Split(path, ":")
132+
return pathElements[len(pathElements)-1]
133+
}
134+
return ""
135+
}
136+
137+
func applyReleaseWithValues(ctx context.Context, release string, k8sClient client.Client, values apiextensionsv1.JSON, releaseName string) error {
138+
log := logger.LoadLoggerFromContext(ctx)
139+
140+
obj, err := unstructuredFromString(release, map[string]string{}, log)
141+
if err != nil {
142+
return errors.Wrap(err, "Failed to get unstructuredFromFile")
143+
}
144+
obj.SetName(releaseName)
145+
146+
if err := unstructured.SetNestedField(obj.Object, releaseName, "spec", "releaseName"); err != nil {
147+
return errors.Wrap(err, "failed to set spec.releaseName")
148+
}
149+
150+
obj.Object["spec"].(map[string]interface{})["values"] = values
151+
152+
err = k8sClient.Patch(ctx, &obj, client.Apply, client.FieldOwner("security-operator"))
153+
if err != nil {
154+
return errors.Wrap(err, "Failed to apply manifest: (%s/%s)", obj.GetKind(), obj.GetName())
155+
}
156+
return nil
157+
}
158+
159+
func unstructuredFromString(manifest string, templateData map[string]string, log *logger.Logger) (unstructured.Unstructured, error) {
160+
manifestBytes := []byte(manifest)
161+
162+
res, err := ReplaceTemplate(templateData, manifestBytes)
163+
if err != nil {
164+
return unstructured.Unstructured{}, errors.Wrap(err, "Failed to replace template")
165+
}
166+
167+
var objMap map[string]interface{}
168+
if err := yaml.Unmarshal(res, &objMap); err != nil {
169+
return unstructured.Unstructured{}, errors.Wrap(err, "Failed to unmarshal YAML from template. Output:\n%s", string(res))
170+
}
171+
172+
log.Debug().Str("obj", fmt.Sprintf("%+v", objMap)).Msg("Unmarshalled object")
173+
174+
obj := unstructured.Unstructured{Object: objMap}
175+
176+
log.Debug().Str("kind", obj.GetKind()).Str("name", obj.GetName()).Str("namespace", obj.GetNamespace()).Msg("Applying manifest")
177+
return obj, err
178+
}
179+
180+
func ReplaceTemplate(templateData map[string]string, templateBytes []byte) ([]byte, error) {
181+
tmpl, err := template.New("manifest").Parse(string(templateBytes))
182+
if err != nil {
183+
return []byte{}, errors.Wrap(err, "Failed to parse template")
184+
}
185+
var result bytes.Buffer
186+
err = tmpl.Execute(&result, templateData)
187+
if err != nil {
188+
keys := make([]string, 0, len(templateData))
189+
for k := range templateData {
190+
keys = append(keys, k)
191+
}
192+
return []byte{}, errors.Wrap(err, "Failed to execute template with keys %v", keys)
193+
}
194+
if result.Len() == 0 {
195+
return []byte{}, nil
196+
}
197+
return result.Bytes(), nil
198+
}
199+
200+
func applyManifestWithMergedValues(ctx context.Context, manifest string, k8sClient client.Client, templateData map[string]string) error {
201+
log := logger.LoadLoggerFromContext(ctx)
202+
203+
obj, err := unstructuredFromString(manifest, templateData, log)
204+
if err != nil {
205+
return err
206+
}
207+
208+
err = k8sClient.Patch(ctx, &obj, client.Apply, client.FieldOwner("security-operator"))
209+
if err != nil {
210+
return errors.Wrap(err, "Failed to apply manifest (%s/%s)", obj.GetKind(), obj.GetName())
211+
}
212+
return nil
213+
}

0 commit comments

Comments
 (0)