Skip to content

MR ready XR not ready - dig function to get status atProvider id not working #344

@G-Salviati

Description

@G-Salviati

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

  1. How does the function-auto-ready works? Is it mandatory? If yes, should I use it in more steps of the composition pipeline?
  2. 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)?
  3. 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?
  4. 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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions