crossplane-contrib / function-go-templating

A Go templating composition function
https://crossplane.io
Apache License 2.0
37 stars 26 forks source link

Unable to decode array items that are more complex than a simple list #91

Closed humoflife closed 2 months ago

humoflife commented 2 months ago

What happened?

Receiving the following crossplane beta render error:

error converting YAML to JSON: yaml: line 7: did not find expected ',' or ']'

XR:

apiVersion: dynamodb.aws.platform.upbound.io/v1alpha1
kind: Instance
metadata:
  name: go-template-debug
spec:
  parameters:
    array:
      - name: Tester-1
        type: Diligent
      - name: Tester-2
        type: More Diligent

function-go-templating debug output:

2024-05-01T20:58:57.868-0700    DEBUG   function-go-templating/fn.go:96 rendered manifests  {"manifests": "\n---\napiVersion: dynamodb.aws.upbound.io/v1beta1\nkind: Table\nmetadata:\n  annotations:\n    gotemplating.fn.crossplane.io/composition-resource-name: table\nspec:\n  forProvider:\n    array: [map[name:Tester-1 type:Diligent] map[name:Tester-2 type:More Diligent]]\n"}

Composition is as follows. Note that the issue has nothing to do with the Kind and api version but was first noticed through a DynamoDB table with an attribute and a globalSecondaryIndex that neither were properly decoded from YAML to JSON by function-go-templating:

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: table.dynamodb.aws.platform.upbound.io
  labels:
    provider: aws
spec:
  compositeTypeRef:
    apiVersion: dynamodb.aws.platform.upbound.io/v1alpha1
    kind: XTable

  mode: Pipeline
  pipeline:
    - step: go-templating
      functionRef:
        name: function-go-templating
      input:
        apiVersion: gotemplating.fn.crossplane.io/v1beta1
        kind: GoTemplate
        source: Inline
        inline:
          template: |
            {{ $parameters := .observed.composite.resource.spec.parameters }}
            ---
            apiVersion: dynamodb.aws.upbound.io/v1beta1
            kind: Table
            metadata:
              annotations:
                {{ setResourceNameAnnotation (print "table") }}
            spec:
              forProvider:
                array: {{ $parameters.array }}

    - step: automatically-detect-ready-composed-resources
      functionRef:
        name: crossplane-contrib-function-auto-ready

How can we reproduce it?

crossplane beta render xr.yaml composition.yaml function.yaml

The function.yaml is as follows:

---
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
  name: function-go-templating
  annotations:
    render.crossplane.io/runtime: Development
spec:
  package: function-go-templating
  packagePullPolicy: Always
---
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
  name: crossplane-contrib-function-auto-ready
spec:
  package: xpkg.upbound.io/crossplane-contrib/function-auto-ready:v0.2.1

What environment did it happen in?

Function version: v0.4.1

haarchri commented 2 months ago

something like this is working:

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: table.dynamodb.aws.platform.upbound.io
  labels:
    provider: aws
spec:
  compositeTypeRef:
    apiVersion: dynamodb.aws.platform.upbound.io/v1alpha1
    kind: XTable

  mode: Pipeline
  pipeline:
    - step: go-templating
      functionRef:
        name: function-go-templating
      input:
        apiVersion: gotemplating.fn.crossplane.io/v1beta1
        kind: GoTemplate
        source: Inline
        inline:
          template: |
            {{ $spec := .observed.composite.resource.spec }}
            ---
            apiVersion: dynamodb.aws.upbound.io/v1beta1
            kind: Table
            metadata:
              annotations:
                {{ setResourceNameAnnotation (print "table") }}
            spec:
              forProvider:
                array:
                {{- range $i, $array := $spec.parameters.array }}
                  - name: {{ $array.name }}
                    type: {{ $array.type }}
                {{- end }}

    - step: automatically-detect-ready-composed-resources
      functionRef:
        name: crossplane-contrib-function-auto-ready
phisco commented 2 months ago

It should also work using toYAML

humoflife commented 2 months ago

The above decoding behavior is by design. To use function-go-templating to perform the array assignment, one can use the following syntax.


apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: table.dynamodb.aws.platform.upbound.io
  labels:
    provider: aws
spec:
  compositeTypeRef:
    apiVersion: dynamodb.aws.platform.upbound.io/v1alpha1
    kind: XTable

  mode: Pipeline
  pipeline:
    - step: go-templating
      functionRef:
        name: function-go-templating
      input:
        apiVersion: gotemplating.fn.crossplane.io/v1beta1
        kind: GoTemplate
        source: Inline
        inline:
          template: |
            {{ $spec := .observed.composite.resource.spec }}
            ---
            apiVersion: dynamodb.aws.upbound.io/v1beta1
            kind: Table
            metadata:
              annotations:
                {{ setResourceNameAnnotation (print "table") }}
            spec:
              forProvider:
                array:
                {{- range $i, $array := $spec.parameters.array }}
                  - name: {{ $array.name }}
                    {{- if $array.type }}
                    type: {{ $array.type }}
                    {{- end }}
                {{- end }}
phisco commented 2 months ago

For future reference, somthing like https://github.com/crossplane-contrib/function-go-templating/blob/82dc60773ec3ca1fb870ae0eb9f61310dd813639/example/functions/toYaml/composition.yaml#L25C1-L25C100 should also work