Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't create VRF ReservedIPBlock (will not resolve to Ready) #50

Open
displague opened this issue Jul 11, 2024 · 2 comments
Open

Can't create VRF ReservedIPBlock (will not resolve to Ready) #50

displague opened this issue Jul 11, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@displague
Copy link
Collaborator

displague commented Jul 11, 2024

What happened?

Given the following XRD, a ReservedIPBlock will fail to reconcile with errors about quantity conflicting with vrf_id even when no quantity is set and vrf_id is supplied through patching.

XRD ("MetalNetwork" creates a VRF + VLAN + Gateway (associated with the VLAN, with IP reservations from the VRF)

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: metalnetworks.equinix.xrds.crossplane.io
spec:
  group: equinix.xrds.crossplane.io
  names:
    kind: MetalNetwork
    listKind: MetalNetworkList
    plural: metalnetworks
    singular: metalnetwork
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                vrfName:
                  type: string
                  description: "Name of the VRF"
                projectID:
                  type: string
                  description: "Equinix Metal Project ID"
                description:
                  type: string
                  description: "Description of the VRF"
                metro:
                  type: string
                  description: "Metro area for the VRF"
                ipPrefixes:
                  type: array
                  items:
                    type: string
                  description: "IP prefixes for the VRF"
                  default: ["192.168.100.0/24"]
                vxlan:
                  type: integer
                  description: "VXLAN ID for the VRF"
                  default: 1000
              required:
                - vrfName
                - projectID
                - metro
            status:
              type: object
              properties:
                vlanID:
                  type: string
                vrfID:
                  type: string
                gatewayID:
                  type: string
                ipReservationID:
                  type: string
                conditions:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                      status:
                        type: string
                      reason:
                        type: string
                      message:
                        type: string
  claimNames:
    kind: MetalNetworkClaim
    plural: metalnetworkclaims
---
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: metalnetworkcomposition
spec:
  compositeTypeRef:
    apiVersion: equinix.xrds.crossplane.io/v1alpha1
    kind: MetalNetwork
  resources:
    - name: metalvrf
      base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Vrf
        spec:
          providerConfigRef:
            name: default
      patches:
        - fromFieldPath: "spec.description"
          toFieldPath: "spec.forProvider.description"
          transforms:
          - type: string
            string:
              type: Format
              fmt: 'Crossplane managed VRF: %s'
        - fromFieldPath: "spec.vrfName"
          toFieldPath: "spec.forProvider.name"
        - fromFieldPath: "spec.vrfName"
          toFieldPath: "metadata.name"
        - fromFieldPath: "spec.projectID"
          toFieldPath: "spec.forProvider.projectId"
        - fromFieldPath: "spec.description"
          toFieldPath: "spec.forProvider.description"
        - fromFieldPath: "spec.metro"
          toFieldPath: "spec.forProvider.metro"
        - fromFieldPath: "spec.ipPrefixes"
          toFieldPath: "spec.forProvider.ipRanges"
        - type: ToCompositeFieldPath
          fromFieldPath: "status.atProvider.id"
          toFieldPath: "status.vrfID"
    - name: metalvlan
      base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Vlan
        spec:
          providerConfigRef:
            name: default
      patches:
        - fromFieldPath: "spec.description"
          toFieldPath: "spec.forProvider.description"
          transforms:
          - type: string
            string:
              type: Format
              fmt: 'Crossplane managed VLAN: %s'
        - fromFieldPath: "spec.vrfName"
          toFieldPath: "metadata.name"
        - fromFieldPath: "spec.projectID"
          toFieldPath: "spec.forProvider.projectId"
        - fromFieldPath: "spec.description"
          toFieldPath: "spec.forProvider.description"
        - fromFieldPath: "spec.metro"
          toFieldPath: "spec.forProvider.metro"
        - fromFieldPath: "spec.vxlan"
          toFieldPath: "spec.forProvider.vxlan"
        - type: ToCompositeFieldPath
          fromFieldPath: "status.atProvider.id"
          toFieldPath: "status.vlanID"
    - name: metalgateway
      base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Gateway
        spec:
          providerConfigRef:
            name: default
      patches:
        - fromFieldPath: "spec.vrfName"
          toFieldPath: "metadata.name"
        - fromFieldPath: "spec.projectID"
          toFieldPath: "spec.forProvider.projectId"
        - fromFieldPath: "status.ipReservationID"
          toFieldPath: "spec.forProvider.ipReservationId"
        - fromFieldPath: "status.vlanID"
          toFieldPath: "spec.forProvider.vlanId"
        - type: ToCompositeFieldPath
          fromFieldPath: "status.atProvider.id"
          toFieldPath: "status.gatewayID"

    - name: metalgatewayipreservation
      base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: ReservedIPBlock
        spec:
          forProvider:
            type: vrf
          providerConfigRef:
            name: default
      patches:
        - fromFieldPath: "spec.description"
          toFieldPath: "spec.forProvider.description"
          transforms:
          - type: string
            string:
              type: Format
              fmt: 'Crossplane managed IP Reservation: %s'
        - fromFieldPath: "spec.vrfName"
          toFieldPath: "metadata.name"
        - fromFieldPath: "spec.projectID"
          toFieldPath: "spec.forProvider.projectId"
        - fromFieldPath: "spec.description"
          toFieldPath: "spec.forProvider.description"
        - fromFieldPath: "spec.metro"
          toFieldPath: "spec.forProvider.metro"
        - fromFieldPath: "spec.ipPrefixes[0]"
          toFieldPath: "spec.forProvider.network"
          transforms:
            - type: string
              string:
                type: Regexp
                regexp:
                  match: '(.*)/'
                  group: 1
        - fromFieldPath: "spec.ipPrefixes[0]"
          toFieldPath: "spec.forProvider.cidr"
          transforms:
            - type: string
              string:
                type: Regexp
                regexp:
                  match: '/(.*)'
                  group: 1
            - type: convert
              convert:
                toType: int
        - type: ToCompositeFieldPath
          fromFieldPath: "status.atProvider.id"
          toFieldPath: "status.ipReservationID"
        - fromFieldPath: "status.vrfID"
          toFieldPath: "spec.forProvider.vrfId"

Claim:

apiVersion: equinix.xrds.crossplane.io/v1alpha1
kind: MetalNetworkClaim
metadata:
  name: metal-network-instance
spec:
    vrfName: "vrf-via-crossplane-xrd"
    projectID: "my-project-id" # replace this with yours
    description: "vrf created using crossplane composition"
    metro: "da"
    ipPrefixes:
    - 192.168.100.0/24
    vxlan: 1000
$ kubectl get equinix
NAME                                                             READY   SYNCED   EXTERNAL-NAME   AGE
gateway.metal.equinix.jet.crossplane.io/vrf-via-crossplane-xrd   False   True                     32m

NAME                                                                     READY   SYNCED   EXTERNAL-NAME                          AGE
reservedipblock.metal.equinix.jet.crossplane.io/vrf-via-crossplane-xrd   False   False    740d3177-de36-4538-842e-7ed960c66c54   32m

NAME                                                          READY   SYNCED   EXTERNAL-NAME                          AGE
vlan.metal.equinix.jet.crossplane.io/vrf-via-crossplane-xrd   True    True     e0a787ac-fa37-47cf-ac0e-02657fad2cf9   32m

NAME                                                         READY   SYNCED   EXTERNAL-NAME                          AGE
vrf.metal.equinix.jet.crossplane.io/vrf-via-crossplane-xrd   True    True     40025fe3-2138-4e25-a963-4cca23e136bc   22m
$ kubectl describe metalnetworkclaims.equinix.xrds.crossplane.io metal-network-instance 
Name:         metal-network-instance
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  equinix.xrds.crossplane.io/v1alpha1
Kind:         MetalNetworkClaim
Metadata:
  Creation Timestamp:  2024-07-11T14:19:53Z
  Finalizers:
    finalizer.apiextensions.crossplane.io
  Generation:        8
  Resource Version:  16031
  UID:               c441b433-525e-4fcb-a508-c2835dc79677
Spec:
  Composite Delete Policy:  Background
  Composition Ref:
    Name:  metalnetworkcomposition
  Composition Revision Ref:
    Name:                     metalnetworkcomposition-e870161
  Composition Update Policy:  Automatic
  Description:                vrf created using crossplane composition
  Ip Prefixes:
    192.168.100.0/24
  Metro:       da
  Project ID:  24822e74-bf8c-4637-bcb9-71ef8fd88eed
  Resource Ref:
    API Version:  equinix.xrds.crossplane.io/v1alpha1
    Kind:         MetalNetwork
    Name:         metal-network-instance-p24bt
  Vrf Name:       vrf-via-crossplane-xrd
  Vxlan:          1000
Status:
  Conditions:
    Last Transition Time:  2024-07-11T14:19:53Z
    Reason:                ReconcileSuccess
    Status:                True
    Type:                  Synced
    Last Transition Time:  2024-07-11T14:19:53Z
    Message:               Claim is waiting for composite resource to become Ready
    Reason:                Waiting
    Status:                False
    Type:                  Ready
  Vlan ID:                 e0a787ac-fa37-47cf-ac0e-02657fad2cf9
  Vrf ID:                  40025fe3-2138-4e25-a963-4cca23e136bc
Events:
  Type    Reason                 Age                   From                                                             Message
  ----    ------                 ----                  ----                                                             -------
  Normal  BindCompositeResource  33m                   offered/compositeresourcedefinition.apiextensions.crossplane.io  Successfully bound composite resource
  Normal  BindCompositeResource  8m16s (x17 over 33m)  offered/compositeresourcedefinition.apiextensions.crossplane.io  Composite resource is not yet ready
$ kubectl describe reservedipblocks.metal.equinix.jet.crossplane.io 
...
Spec:
  Deletion Policy:  Delete
  For Provider:
    Cidr:            24
    Custom Data:     {}
    Description:     vrf created using crossplane composition
    Metro:           da
    Network:         192.168.100.0
    Project Id:      *redacted*
    Quantity:        256
    Type:            vrf
    Vrf Id:          40025fe3-2138-4e25-a963-4cca23e136bc
    Wait For State:  created
  Provider Config Ref:
    Name:  default
Status:
  At Provider:
  Conditions:
    Last Transition Time:  2024-07-11T14:54:36Z
    Message:               observe failed: cannot run refresh: refresh failed: Invalid combination of arguments: "vrf_id": only one of `quantity,vrf_id` can be specified, but `quantity,vrf_id` were specified.
Invalid combination of arguments: "quantity": only one of `quantity,vrf_id` can be specified, but `quantity,vrf_id` were specified.

Quantity above is shown as 256 but that is not defined anywhere in the XRD or claim. I tried setting quantity: null in the XRD, but that didn't help either.

How can we reproduce it?

What environment did it happen in?

Crossplane version: v1.16.0
Provider version: v0.6.1

@displague displague added the bug Something isn't working label Jul 11, 2024
@displague
Copy link
Collaborator Author

displague commented Jul 11, 2024

The IP reservation is being successfully created. The problem seems to be at refresh, related to the quantity being set to 256 as a computed field despite the field conflicting with the other fields (cidr, vrf_id).

@displague displague changed the title Can't create VRF ReservedIPBlock Can't create VRF ReservedIPBlock (will not resolve to Ready) Jul 11, 2024
@displague
Copy link
Collaborator Author

The Crossplane provider's LateInitializer of quantity field (optional and computed in Terraform) is problematic in this case.

We'll want to change the default initializer, as discussed here https://github.com/crossplane/upjet/blob/e295e17c7be7af3fe711ed53bae201f04f1fa797/docs/configuring-a-resource.md?plain=1#L732, and as previously implemented for the device managed resources due to similar behavior between the Metro and Facility fields which were mutually exclusive but required and (in some revisions) computed when not specified: https://github.com/crossplane-contrib/provider-jet-equinix/blob/main/config/metal/device/config.go#L24-L35

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant