Hello,
I'm having troubles using the function-go-templating.
Context
- Crossplane 1.19.1 deployed on a vanilla Kubernetes.
- I wrote a XRD of kind: Workspace.
- The composition used by the XR should provision on GCP a customer folder and multiple app folders as subfolders of the latter one.
- I'm not using claims right now.
At first I've tried to test the provisioning of the customer folder only with this configuration:
XRD
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xworkspaces.examples.io
spec:
defaultCompositeDeletePolicy: Background
defaultCompositionRef:
name: folder-project-ex
defaultCompositionUpdatePolicy: Automatic
group: examples.io
names:
kind: XWorkspace
plural: xworkspaces
claimNames:
kind: Workspace
plural: workspaces
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
additionalProperties: false
required:
- customerName
- parentPartition
- apps
properties:
customerName:
type: string
description: "The name of the customer"
parentPartition:
type: string
description: "The foundation root folder id"
apps:
type: array
items:
type: object
required:
- appName
properties:
appName:
type: string
description: "The name of the app"
required:
- spec
composition
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: folder-project-ex
labels:
provider: gcp
spec:
compositeTypeRef:
apiVersion: examples.io/v1alpha1
kind: XWorkspace
mode: Pipeline
pipeline:
- step: create-customer-folder
functionRef:
name: function-go-templating
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
{{ $xr := .observed.composite.resource }}
apiVersion: cloudplatform.gcp.upbound.io/v1beta1
kind: Folder
metadata:
name: {{ print $xr.spec.customerName "-folder" }}
annotations:
gotemplating.fn.crossplane.io/composition-resource-name: {{ print $xr.spec.customerName "-folder" }}
spec:
forProvider:
displayName: {{ $xr.spec.customerName }}
parent: folders/{{ $xr.spec.parentPartition | toString }}
providerConfigRef:
name: gcp-provider-config
XR
apiVersion: examples.io/v1alpha1
kind: XWorkspace
metadata:
name: sella-workspace
spec:
compositionSelector:
matchLabels:
provider: gcp
customerName: "sella"
parentPartition: "545242441117"
apps:
- appName: "homebanking"
- appName: "smarthome"
Problem n.1
The composite resource "xworkspace.examples.io/sella-workspace" is synced but not ready even if the managed resource folder is both synced and ready.
The composite resource events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SelectComposition 22m defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully selected composition: folder-project-ex
Normal SelectComposition 22m defined/compositeresourcedefinition.apiextensions.crossplane.io Selected composition revision: folder-project-ex-2cdf662
Normal ComposeResources 116s (x47 over 22m) defined/compositeresourcedefinition.apiextensions.crossplane.io Composed resource "sella-folder" is not yet ready
The managed resource events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreatedExternalResource 23m managed/cloudplatform.gcp.upbound.io/v1beta1, kind=folder Successfully requested creation of external resource
Warning CannotUpdateManagedResource 23m managed/cloudplatform.gcp.upbound.io/v1beta1, kind=folder Operation cannot be fulfilled on folders.cloudplatform.gcp.upbound.io "sella-folder": the object has been modified; please apply your changes to the latest version and try again
The propagation of the ready state works only if I add a step that uses the function-auto-ready to the composition pipeline. Why? Is this mandatory? How does it work behind the scenes?
Problem n.2
With this auto-ready function set I've tried to test the next step of the pipeline; the one which creates the subfolders based on the apps array in the XR.
So the new composition is the following one:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: folder-project-ex
labels:
provider: gcp
spec:
compositeTypeRef:
apiVersion: examples.io/v1alpha1
kind: XWorkspace
mode: Pipeline
pipeline:
- step: create-customer-folder
functionRef:
name: function-go-templating
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
{{ $xr := .observed.composite.resource }}
apiVersion: cloudplatform.gcp.upbound.io/v1beta1
kind: Folder
metadata:
name: {{ print $xr.spec.customerName "-folder" }}
annotations:
gotemplating.fn.crossplane.io/composition-resource-name: {{ print $xr.spec.customerName "-folder" }}
spec:
forProvider:
displayName: {{ $xr.spec.customerName }}
parent: folders/{{ $xr.spec.parentPartition | toString }}
providerConfigRef:
name: gcp-provider-config
- step: automatically-detect-ready-composed-resources
functionRef:
name: function-auto-ready
- step: create-app-folders
functionRef:
name: function-go-templating
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
{{ $xr := .observed.composite.resource }}
{{ printf "DEBUG xr: %s" $xr}}
{{ $rootFolderMR := get .observed.resources (print $xr.spec.customerName "-folder") }}
{{ printf "DEBUG rootFolderMR :%s" $rootFolderMR }}
{{ $rootFolderID := dig "resource" "status" "atProvider" "id" "" $rootFolderMR }}
{{ printf "DEBUG rootFolderId :%s" $rootFolderID }}
{{ range $xr.spec.apps }}
apiVersion: cloudplatform.gcp.upbound.io/v1beta1
kind: Folder
metadata:
name: {{ print $xr.spec.customerName .appName "-folder" }}
annotations:
gotemplating.fn.crossplane.io/composition-resource-name: {{ print $xr.spec.customerName .appName "-folder" }}
spec:
forProvider:
displayName: {{ .appName }}
parent: folders/{{ $rootFolderID | toString }}
providerConfigRef:
name: gcp-provider-config
{{ end }}
As you can see I use the get and dig functions to retrieve the id of the customer folder provisioned in the first step. Then I iterate over the apps array to provision the app subfolders.
I followed the solutions given in the issue #79 (to access the managed resource) and the protobuf schema provided by the crossplane documentation.
No managed resource is created and an error is logged in the composite events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SelectComposition 22s defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully selected composition: folder-project-ex
Normal SelectComposition 22s defined/compositeresourcedefinition.apiextensions.crossplane.io Selected composition revision: folder-project-ex-15c134f
Warning ComposeResources 13s (x5 over 22s) defined/compositeresourcedefinition.apiextensions.crossplane.io cannot compose resources: pipeline step "create-app-folders" returned a fatal result: cannot execute template: template: manifests:5:20: executing "manifests" at <dig "resource" "status" "atProvider" "id" "" $rootFolderMR>: error calling dig: interface conversion: interface {} is string, not map[string]interface {}
I don't get if the problem is in the $rootFolderMR variable, which is expected to be a map of strings and indeed it is a string or something else. Any idea to solve this?
Questions to clarify some behaviours
- How does the function-auto-ready works? Is it mandatory? If yes, should I use it in more steps of the composition pipeline?
- Is the function-auto-ready ensuring that the status.atProvider object exists and is filled with data at the istant I try to read it (in the 3rd step of the pipeline)?
- If the function-auto-ready is not useful in this case, is crossplane capable of waiting for the first folder (customer folder) to be provisioned and the id to be written to the "status.AtProvider.id" or we need something else?
- Is there the possibility to print for debug purposes? As you can notice in the 3rd step of the pipeline I tried to print the some data in the observed state but nothing changes in the function pod logs.
Thank you in advance for the help!
Hello,
I'm having troubles using the function-go-templating.
Context
At first I've tried to test the provisioning of the customer folder only with this configuration:
XRD
composition
XR
Problem n.1
The composite resource "xworkspace.examples.io/sella-workspace" is synced but not ready even if the managed resource folder is both synced and ready.
The composite resource events
The managed resource events
The propagation of the ready state works only if I add a step that uses the function-auto-ready to the composition pipeline. Why? Is this mandatory? How does it work behind the scenes?
Problem n.2
With this auto-ready function set I've tried to test the next step of the pipeline; the one which creates the subfolders based on the apps array in the XR.
So the new composition is the following one:
As you can see I use the get and dig functions to retrieve the id of the customer folder provisioned in the first step. Then I iterate over the apps array to provision the app subfolders.
I followed the solutions given in the issue #79 (to access the managed resource) and the protobuf schema provided by the crossplane documentation.
No managed resource is created and an error is logged in the composite events
I don't get if the problem is in the $rootFolderMR variable, which is expected to be a map of strings and indeed it is a string or something else. Any idea to solve this?
Questions to clarify some behaviours
Thank you in advance for the help!