diff --git a/pkg/patterns/declarative/pkg/manifest/objects.go b/pkg/patterns/declarative/pkg/manifest/objects.go index b6e828e3..6e54bf85 100644 --- a/pkg/patterns/declarative/pkg/manifest/objects.go +++ b/pkg/patterns/declarative/pkg/manifest/objects.go @@ -33,6 +33,7 @@ import ( type Objects struct { Items []*Object Blobs [][]byte + Path string } type Object struct { diff --git a/pkg/patterns/declarative/reconciler.go b/pkg/patterns/declarative/reconciler.go index d5de0f89..72324fc2 100644 --- a/pkg/patterns/declarative/reconciler.go +++ b/pkg/patterns/declarative/reconciler.go @@ -111,11 +111,11 @@ func (r *Reconciler) reconcileExists(ctx context.Context, name types.NamespacedN log.WithValues("object", name.String()).Info("reconciling") var fs filesys.FileSystem - if r.options.kustomize { + if r.IsKustomizeOptionUsed() { fs = filesys.MakeFsInMemory() } - objects, err := r.buildDeploymentObjects(ctx, name, instance, fs) + objects, err := r.BuildDeploymentObjectsWithFs(ctx, name, instance, fs) if err != nil { log.Error(err, "building deployment objects") return reconcile.Result{}, fmt.Errorf("error building deployment objects: %v", err) @@ -136,20 +136,23 @@ func (r *Reconciler) reconcileExists(ctx context.Context, name types.NamespacedN } var manifestStr string - if r.options.kustomize { + if r.IsKustomizeOptionUsed() { // run kustomize to create final manifest opts := krusty.MakeDefaultOptions() k := krusty.MakeKustomizer(fs, opts) - m, err := k.Run(string(filepath.Separator)) + m, err := k.Run(objects.Path) if err != nil { log.Error(err, "running kustomize to create final manifest") return reconcile.Result{}, fmt.Errorf("error running kustomize: %v", err) } + log.Info("running kustomize to create final manifest") manifestYaml, err := m.AsYaml() if err != nil { log.Error(err, "creating final manifest yaml") return reconcile.Result{}, fmt.Errorf("error converting kustomize output to yaml: %v", err) } + + log.Info("creating final manifest yaml") manifestStr = string(manifestYaml) } else { @@ -194,12 +197,12 @@ func (r *Reconciler) reconcileExists(ctx context.Context, name types.NamespacedN // BuildDeploymentObjects performs all manifest operations to build a final set of objects for deployment func (r *Reconciler) BuildDeploymentObjects(ctx context.Context, name types.NamespacedName, instance DeclarativeObject) (*manifest.Objects, error) { - return r.buildDeploymentObjects(ctx, name, instance, nil) + return r.BuildDeploymentObjectsWithFs(ctx, name, instance, nil) } -// buildDeploymentObjects is the implementation of BuildDeploymentObjects, supporting saving to a filesystem for kustomize +// BuildDeploymentObjectsWithFs is the implementation of BuildDeploymentObjects, supporting saving to a filesystem for kustomize // If fs is provided, the transformed manifests will be saved to that filesystem -func (r *Reconciler) buildDeploymentObjects(ctx context.Context, name types.NamespacedName, instance DeclarativeObject, fs filesys.FileSystem) (*manifest.Objects, error) { +func (r *Reconciler) BuildDeploymentObjectsWithFs(ctx context.Context, name types.NamespacedName, instance DeclarativeObject, fs filesys.FileSystem) (*manifest.Objects, error) { log := log.Log // 1. Load the manifest @@ -250,9 +253,13 @@ func (r *Reconciler) buildDeploymentObjects(ctx context.Context, name types.Name } fs.WriteFile(string(manifestPath), json) } + for _, blob := range objects.Blobs { + fs.WriteFile(string(manifestPath), blob) + } } - + manifestObjects.Path = filepath.Dir(manifestPath) manifestObjects.Items = append(manifestObjects.Items, objects.Items...) + manifestObjects.Blobs = append(manifestObjects.Blobs, objects.Blobs...) } // 6. Sort objects to work around dependent objects in the same manifest (eg: service-account, deployment) manifestObjects.Sort(DefaultObjectOrder(ctx)) @@ -366,6 +373,14 @@ func (r *Reconciler) injectOwnerRef(ctx context.Context, instance DeclarativeObj return nil } +// IsKustomizeOptionUsed checks if the option for Kustomize build is used for creating manifests +func (r *Reconciler) IsKustomizeOptionUsed() bool { + if r.options.kustomize { + return true + } + return false +} + // SetSink provides a Sink that will be notified for all deployments func (r *Reconciler) SetSink(sink Sink) { r.options.sink = sink diff --git a/pkg/test/golden/validator.go b/pkg/test/golden/validator.go index 20558b14..0db07a06 100644 --- a/pkg/test/golden/validator.go +++ b/pkg/test/golden/validator.go @@ -39,6 +39,8 @@ import ( "sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative" "sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative/pkg/manifest" "sigs.k8s.io/kubebuilder-declarative-pattern/pkg/test/mocks" + "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/api/krusty" ) func NewValidator(t *testing.T, b *scheme.Builder) *validator { @@ -135,8 +137,8 @@ func (v *validator) Validate(r declarative.Reconciler) { t := v.T t.Helper() - serializer := json.NewSerializer(json.DefaultMetaFactory, v.scheme, v.scheme, false) - yamlizer := json.NewYAMLSerializer(json.DefaultMetaFactory, v.scheme, v.scheme) + serializer := json.NewSerializerWithOptions(json.DefaultMetaFactory, v.scheme, v.scheme, json.SerializerOptions{Yaml: false, Pretty: false, Strict: false}) + yamlizer := json.NewSerializerWithOptions(json.DefaultMetaFactory, v.scheme, v.scheme, json.SerializerOptions{Yaml: true, Pretty: false, Strict: false}) metadataAccessor := meta.NewAccessor() @@ -217,7 +219,11 @@ func (v *validator) Validate(r declarative.Reconciler) { nsn := types.NamespacedName{Namespace: namespace, Name: name} - objects, err := r.BuildDeploymentObjects(ctx, nsn, cr.(declarative.DeclarativeObject)) + var fs filesys.FileSystem + if r.IsKustomizeOptionUsed() { + fs = filesys.MakeFsInMemory() + } + objects, err := r.BuildDeploymentObjectsWithFs(ctx, nsn, cr.(declarative.DeclarativeObject), fs) if err != nil { t.Errorf("error building deployment objects: %v", err) continue @@ -227,17 +233,30 @@ func (v *validator) Validate(r declarative.Reconciler) { { var b bytes.Buffer - for i, o := range objects.Items { - if i != 0 { - b.WriteString("\n---\n\n") + if r.IsKustomizeOptionUsed() { + opts := krusty.MakeDefaultOptions() + k := krusty.MakeKustomizer(fs, opts) + m, err := k.Run(objects.Path) + if err != nil { + t.Fatalf("running kustomize to create final manifest: %v", err) + } + manifestYaml, err := m.AsYaml() + if err != nil { + t.Fatalf("creating final manifest yaml: %v", err) } - u := o.UnstructuredObject() - if err := yamlizer.Encode(u, &b); err != nil { - t.Fatalf("error encoding to yaml: %v", err) + actualYAML = string(manifestYaml) + } else { + for i, o := range objects.Items { + if i != 0 { + b.WriteString("\n---\n\n") + } + u := o.UnstructuredObject() + if err := yamlizer.Encode(u, &b); err != nil { + t.Fatalf("error encoding to yaml: %v", err) + } } + actualYAML = b.String() } - - actualYAML = b.String() } expectedPath := strings.Replace(p, ".in.yaml", ".out.yaml", -1)