diff --git a/docs/markers.md b/docs/markers.md index 7d30df4..d95b2ba 100644 --- a/docs/markers.md +++ b/docs/markers.md @@ -458,3 +458,71 @@ spec: provider: "azure" ``` +### Stacking Resource Markers + +You can include multiple resource markers on a particular resource. For example: +```yaml +--- +# +operator-builder:resource:field=nginx.include,value=true,include +# +operator-builder:resource:field=nginx.installType,value="deployment",include +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-ingress +... +``` + +The purpose of the first marker is to include *all* nginx ingress contoller +resources when `spec.nginx.include: true`. The second gives users a choice +to install nginx ingress controller as a deployment or daemonset. When +`spec.nginx.installType: deployment` the deployment resource is included. +Therefore the custom resource will need to look as follows for this deployment +resource to be created: + +```yaml +apiVersion: platform.addons.nukleros.io/v1alpha1 +kind: IngressComponent +metadata: + name: ingresscomponent-sample +spec: + nginx: + installType: "deployment" # if not "deployment" deployment resource excluded + include: true # if false, no nginx resources are created + image: "nginx/nginx-ingress" + version: "2.3.0" + replicas: 2 +``` + +The resulting source code looks as follows. If either if-statement is evaluated +as true, the function will return without any object - hence the deployment will +not be included. + +```go +// CreateDeploymentNamespaceNginxIngress creates the Deployment resource with name nginx-ingress. +func CreateDeploymentNamespaceNginxIngress( + parent *platformv1alpha1.IngressComponent, + collection *setupv1alpha1.SupportServices, + reconciler workload.Reconciler, + req *workload.Request, +) ([]client.Object, error) { + + if parent.Spec.Nginx.Include != true { + return []client.Object{}, nil + } + + if parent.Spec.Nginx.InstallType != "deployment" { + return []client.Object{}, nil + } + + var resourceObj = &unstructured.Unstructured{ + Object: map[string]interface{}{ + // +operator-builder:resource:field=nginx.include,value=true,include + // +operator-builder:resource:field=nginx.installType,value="deployment",include + "apiVersion": "apps/v1", + "kind": "Deployment", + ... + } + + return mutate.MutateDeploymentNamespaceNginxIngress(resourceObj, parent, collection, reconciler, req) +} +``` diff --git a/internal/plugins/workload/v1/scaffolds/templates/api/resources/definition.go b/internal/plugins/workload/v1/scaffolds/templates/api/resources/definition.go index 8531365..ebc47d1 100644 --- a/internal/plugins/workload/v1/scaffolds/templates/api/resources/definition.go +++ b/internal/plugins/workload/v1/scaffolds/templates/api/resources/definition.go @@ -88,7 +88,9 @@ func {{ .CreateFuncName }} ( req *workload.Request, ) ([]client.Object, error) { - {{- if ne .IncludeCode "" }}{{ .IncludeCode }}{{ end }} + {{ range .IncludeCode }} + {{ . }} + {{ end }} {{- .SourceCode }} diff --git a/internal/workload/v1/manifests/child_resource.go b/internal/workload/v1/manifests/child_resource.go index a3b3639..f2f0179 100644 --- a/internal/workload/v1/manifests/child_resource.go +++ b/internal/workload/v1/manifests/child_resource.go @@ -35,7 +35,7 @@ type ChildResource struct { Kind string StaticContent string SourceCode string - IncludeCode string + IncludeCode []string MutateFile string UseStrConv bool RBAC *rbac.Rules @@ -77,33 +77,25 @@ func (resource *ChildResource) ProcessResourceMarkers(markerCollection *markers. return fmt.Errorf("%w; %s for child resource %s", err, ErrChildResourceResourceMarkerInspect, resource) } - // ensure we have the expected number of resource markers - // - 0: return immediately as resource markers are not required - // - 1: continue processing normally - // - 2: return an error notifying the user that we only expect 1 - // resource marker + // return immediately if no resource markers are present if len(markerResults) == 0 { return nil } - //nolint: godox // depends on https://github.com/vmware-tanzu-labs/operator-builder/issues/271 - // TODO: we need to ensure only one marker is found and return an error if we find more than one. - // this becomes difficult as the results are returned as yaml nodes. for now, we just focus on the - // first result and all others are ignored but we should notify the user. - result := markerResults[0] + // process the markers + for _, m := range markerResults { + marker, ok := m.Object.(markers.ResourceMarker) + if !ok { + return ErrChildResourceResourceMarkerProcess + } - // process the marker - marker, ok := result.Object.(markers.ResourceMarker) - if !ok { - return ErrChildResourceResourceMarkerProcess - } - - if err := marker.Process(markerCollection); err != nil { - return fmt.Errorf("%w; %s for child resource %s", err, ErrChildResourceResourceMarkerProcess, resource) - } + if err := marker.Process(markerCollection); err != nil { + return fmt.Errorf("%w; %s for child resource %s", err, ErrChildResourceResourceMarkerProcess, resource) + } - if marker.GetIncludeCode() != "" { - resource.IncludeCode = marker.GetIncludeCode() + if marker.GetIncludeCode() != "" { + resource.IncludeCode = append(resource.IncludeCode, marker.GetIncludeCode()) + } } return nil