diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 54ba50fb..dc7f77b9 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,13 +1,13 @@ ack_generate_info: - build_date: "2022-03-02T19:07:54Z" - build_hash: ade2429bb444ab635916395ea5773d141ba135e1 - go_version: go1.17.5 + build_date: "2022-03-14T23:35:32Z" + build_hash: 00cd850c16117752abe18558326a508436565b1a + go_version: go1.17.8 version: v0.17.2 -api_directory_checksum: ad688fd5a2b395bf5f01413c99ac635e7670ba75 +api_directory_checksum: 45311575b1cf56326ccad9a2caea143fc104b630 api_version: v1alpha1 aws_sdk_go_version: v1.42.0 generator_config_info: - file_checksum: cdc6db8f7b924d8b14a4926f0bb937b7952b102f + file_checksum: b588c7e44229d7db3737b17b76a68708c71e5b68 original_file_name: generator.yaml last_modification: reason: API generation diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml index 1d63c272..63cef627 100644 --- a/apis/v1alpha1/generator.yaml +++ b/apis/v1alpha1/generator.yaml @@ -118,6 +118,10 @@ resources: Routes: custom_field: list_of: CreateRouteInput + VpcId: + references: + resource: VPC + path: Status.VPCID hooks: sdk_create_post_set_output: template_path: hooks/route_table/sdk_create_post_set_output.go.tpl @@ -134,6 +138,9 @@ resources: is_primary_key: true VpcId: is_required: true + references: + resource: VPC + path: Status.VPCID renames: operations: CreateSecurityGroup: @@ -155,11 +162,33 @@ resources: - InvalidVpcID.NotFound - VPCIdNotSpecified Subnet: + fields: + VpcId: + references: + resource: VPC + path: Status.VPCID exceptions: terminal_codes: - InvalidVpcID.Malformed - InvalidVpcID.NotFound VpcEndpoint: + fields: + VpcId: + references: + resource: VPC + path: Status.VPCID + RouteTableIds: + references: + resource: RouteTable + path: Status.RouteTableID + SecurityGroupIds: + references: + resource: SecurityGroup + path: Status.ID + SubnetIds: + references: + resource: Subnet + path: Status.SubnetID exceptions: terminal_codes: - InvalidVpcId.Malformed diff --git a/apis/v1alpha1/route_table.go b/apis/v1alpha1/route_table.go index 60573d86..8e971ef4 100644 --- a/apis/v1alpha1/route_table.go +++ b/apis/v1alpha1/route_table.go @@ -28,8 +28,8 @@ type RouteTableSpec struct { // The tags to assign to the route table. TagSpecifications []*TagSpecification `json:"tagSpecifications,omitempty"` // The ID of the VPC. - // +kubebuilder:validation:Required - VPCID *string `json:"vpcID"` + VPCID *string `json:"vpcID,omitempty"` + VPCRef *ackv1alpha1.AWSResourceReferenceWrapper `json:"vpcRef,omitempty"` } // RouteTableStatus defines the observed state of RouteTable diff --git a/apis/v1alpha1/security_group.go b/apis/v1alpha1/security_group.go index fcb11b18..195adaea 100644 --- a/apis/v1alpha1/security_group.go +++ b/apis/v1alpha1/security_group.go @@ -45,8 +45,8 @@ type SecurityGroupSpec struct { // The tags to assign to the security group. TagSpecifications []*TagSpecification `json:"tagSpecifications,omitempty"` // [EC2-VPC] The ID of the VPC. Required for EC2-VPC. - // +kubebuilder:validation:Required - VPCID *string `json:"vpcID"` + VPCID *string `json:"vpcID,omitempty"` + VPCRef *ackv1alpha1.AWSResourceReferenceWrapper `json:"vpcRef,omitempty"` } // SecurityGroupStatus defines the observed state of SecurityGroup diff --git a/apis/v1alpha1/subnet.go b/apis/v1alpha1/subnet.go index 9057aab5..fe0a8f7a 100644 --- a/apis/v1alpha1/subnet.go +++ b/apis/v1alpha1/subnet.go @@ -54,8 +54,8 @@ type SubnetSpec struct { // The tags to assign to the subnet. TagSpecifications []*TagSpecification `json:"tagSpecifications,omitempty"` // The ID of the VPC. - // +kubebuilder:validation:Required - VPCID *string `json:"vpcID"` + VPCID *string `json:"vpcID,omitempty"` + VPCRef *ackv1alpha1.AWSResourceReferenceWrapper `json:"vpcRef,omitempty"` } // SubnetStatus defines the observed state of Subnet diff --git a/apis/v1alpha1/vpc_endpoint.go b/apis/v1alpha1/vpc_endpoint.go index 9787994b..7e8e4c77 100644 --- a/apis/v1alpha1/vpc_endpoint.go +++ b/apis/v1alpha1/vpc_endpoint.go @@ -47,10 +47,12 @@ type VPCEndpointSpec struct { // Default: true PrivateDNSEnabled *bool `json:"privateDNSEnabled,omitempty"` // (Gateway endpoint) One or more route table IDs. - RouteTableIDs []*string `json:"routeTableIDs,omitempty"` + RouteTableIDs []*string `json:"routeTableIDs,omitempty"` + RouteTableRefs []*ackv1alpha1.AWSResourceReferenceWrapper `json:"routeTableRefs,omitempty"` // (Interface endpoint) The ID of one or more security groups to associate with // the endpoint network interface. - SecurityGroupIDs []*string `json:"securityGroupIDs,omitempty"` + SecurityGroupIDs []*string `json:"securityGroupIDs,omitempty"` + SecurityGroupRefs []*ackv1alpha1.AWSResourceReferenceWrapper `json:"securityGroupRefs,omitempty"` // The service name. To get a list of available services, use the DescribeVpcEndpointServices // request, or get the name from the service provider. // +kubebuilder:validation:Required @@ -58,7 +60,8 @@ type VPCEndpointSpec struct { // (Interface and Gateway Load Balancer endpoints) The ID of one or more subnets // in which to create an endpoint network interface. For a Gateway Load Balancer // endpoint, you can specify one subnet only. - SubnetIDs []*string `json:"subnetIDs,omitempty"` + SubnetIDs []*string `json:"subnetIDs,omitempty"` + SubnetRefs []*ackv1alpha1.AWSResourceReferenceWrapper `json:"subnetRefs,omitempty"` // The tags to associate with the endpoint. TagSpecifications []*TagSpecification `json:"tagSpecifications,omitempty"` // The type of endpoint. @@ -66,8 +69,8 @@ type VPCEndpointSpec struct { // Default: Gateway VPCEndpointType *string `json:"vpcEndpointType,omitempty"` // The ID of the VPC in which the endpoint will be used. - // +kubebuilder:validation:Required - VPCID *string `json:"vpcID"` + VPCID *string `json:"vpcID,omitempty"` + VPCRef *ackv1alpha1.AWSResourceReferenceWrapper `json:"vpcRef,omitempty"` } // VPCEndpointStatus defines the observed state of VPCEndpoint diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index ff510814..f67c3234 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -11865,6 +11865,11 @@ func (in *RouteTableSpec) DeepCopyInto(out *RouteTableSpec) { *out = new(string) **out = **in } + if in.VPCRef != nil { + in, out := &in.VPCRef, &out.VPCRef + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteTableSpec. @@ -12894,6 +12899,11 @@ func (in *SecurityGroupSpec) DeepCopyInto(out *SecurityGroupSpec) { *out = new(string) **out = **in } + if in.VPCRef != nil { + in, out := &in.VPCRef, &out.VPCRef + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupSpec. @@ -14453,6 +14463,11 @@ func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { *out = new(string) **out = **in } + if in.VPCRef != nil { + in, out := &in.VPCRef, &out.VPCRef + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. @@ -17241,6 +17256,17 @@ func (in *VPCEndpointSpec) DeepCopyInto(out *VPCEndpointSpec) { } } } + if in.RouteTableRefs != nil { + in, out := &in.RouteTableRefs, &out.RouteTableRefs + *out = make([]*corev1alpha1.AWSResourceReferenceWrapper, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } + } + } if in.SecurityGroupIDs != nil { in, out := &in.SecurityGroupIDs, &out.SecurityGroupIDs *out = make([]*string, len(*in)) @@ -17252,6 +17278,17 @@ func (in *VPCEndpointSpec) DeepCopyInto(out *VPCEndpointSpec) { } } } + if in.SecurityGroupRefs != nil { + in, out := &in.SecurityGroupRefs, &out.SecurityGroupRefs + *out = make([]*corev1alpha1.AWSResourceReferenceWrapper, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } + } + } if in.ServiceName != nil { in, out := &in.ServiceName, &out.ServiceName *out = new(string) @@ -17268,6 +17305,17 @@ func (in *VPCEndpointSpec) DeepCopyInto(out *VPCEndpointSpec) { } } } + if in.SubnetRefs != nil { + in, out := &in.SubnetRefs, &out.SubnetRefs + *out = make([]*corev1alpha1.AWSResourceReferenceWrapper, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } + } + } if in.TagSpecifications != nil { in, out := &in.TagSpecifications, &out.TagSpecifications *out = make([]*TagSpecification, len(*in)) @@ -17289,6 +17337,11 @@ func (in *VPCEndpointSpec) DeepCopyInto(out *VPCEndpointSpec) { *out = new(string) **out = **in } + if in.VPCRef != nil { + in, out := &in.VPCRef, &out.VPCRef + *out = new(corev1alpha1.AWSResourceReferenceWrapper) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCEndpointSpec. diff --git a/config/crd/bases/ec2.services.k8s.aws_routetables.yaml b/config/crd/bases/ec2.services.k8s.aws_routetables.yaml index 6b5eef16..5f4cad5b 100644 --- a/config/crd/bases/ec2.services.k8s.aws_routetables.yaml +++ b/config/crd/bases/ec2.services.k8s.aws_routetables.yaml @@ -91,8 +91,20 @@ spec: vpcID: description: The ID of the VPC. type: string - required: - - vpcID + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object type: object status: description: RouteTableStatus defines the observed state of RouteTable diff --git a/config/crd/bases/ec2.services.k8s.aws_securitygroups.yaml b/config/crd/bases/ec2.services.k8s.aws_securitygroups.yaml index 0d6207a2..9ce09675 100644 --- a/config/crd/bases/ec2.services.k8s.aws_securitygroups.yaml +++ b/config/crd/bases/ec2.services.k8s.aws_securitygroups.yaml @@ -72,10 +72,23 @@ spec: vpcID: description: '[EC2-VPC] The ID of the VPC. Required for EC2-VPC.' type: string + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object required: - description - name - - vpcID type: object status: description: SecurityGroupStatus defines the observed state of SecurityGroup diff --git a/config/crd/bases/ec2.services.k8s.aws_subnets.yaml b/config/crd/bases/ec2.services.k8s.aws_subnets.yaml index 8d55752c..8d1fe4f8 100644 --- a/config/crd/bases/ec2.services.k8s.aws_subnets.yaml +++ b/config/crd/bases/ec2.services.k8s.aws_subnets.yaml @@ -90,9 +90,22 @@ spec: vpcID: description: The ID of the VPC. type: string + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object required: - cidrBlock - - vpcID type: object status: description: SubnetStatus defines the observed state of Subnet diff --git a/config/crd/bases/ec2.services.k8s.aws_vpcendpoints.yaml b/config/crd/bases/ec2.services.k8s.aws_vpcendpoints.yaml index 8aa1fbb5..6fc49bde 100644 --- a/config/crd/bases/ec2.services.k8s.aws_vpcendpoints.yaml +++ b/config/crd/bases/ec2.services.k8s.aws_vpcendpoints.yaml @@ -66,12 +66,44 @@ spec: items: type: string type: array + routeTableRefs: + items: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object + type: array securityGroupIDs: description: (Interface endpoint) The ID of one or more security groups to associate with the endpoint network interface. items: type: string type: array + securityGroupRefs: + items: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object + type: array serviceName: description: The service name. To get a list of available services, use the DescribeVpcEndpointServices request, or get the name from @@ -85,6 +117,22 @@ spec: items: type: string type: array + subnetRefs: + items: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object + type: array tagSpecifications: description: The tags to associate with the endpoint. items: @@ -111,9 +159,22 @@ spec: vpcID: description: The ID of the VPC in which the endpoint will be used. type: string + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object required: - serviceName - - vpcID type: object status: description: VPCEndpointStatus defines the observed state of VPCEndpoint diff --git a/generator.yaml b/generator.yaml index 1d63c272..63cef627 100644 --- a/generator.yaml +++ b/generator.yaml @@ -118,6 +118,10 @@ resources: Routes: custom_field: list_of: CreateRouteInput + VpcId: + references: + resource: VPC + path: Status.VPCID hooks: sdk_create_post_set_output: template_path: hooks/route_table/sdk_create_post_set_output.go.tpl @@ -134,6 +138,9 @@ resources: is_primary_key: true VpcId: is_required: true + references: + resource: VPC + path: Status.VPCID renames: operations: CreateSecurityGroup: @@ -155,11 +162,33 @@ resources: - InvalidVpcID.NotFound - VPCIdNotSpecified Subnet: + fields: + VpcId: + references: + resource: VPC + path: Status.VPCID exceptions: terminal_codes: - InvalidVpcID.Malformed - InvalidVpcID.NotFound VpcEndpoint: + fields: + VpcId: + references: + resource: VPC + path: Status.VPCID + RouteTableIds: + references: + resource: RouteTable + path: Status.RouteTableID + SecurityGroupIds: + references: + resource: SecurityGroup + path: Status.ID + SubnetIds: + references: + resource: Subnet + path: Status.SubnetID exceptions: terminal_codes: - InvalidVpcId.Malformed diff --git a/helm/crds/ec2.services.k8s.aws_routetables.yaml b/helm/crds/ec2.services.k8s.aws_routetables.yaml index 6b5eef16..5f4cad5b 100644 --- a/helm/crds/ec2.services.k8s.aws_routetables.yaml +++ b/helm/crds/ec2.services.k8s.aws_routetables.yaml @@ -91,8 +91,20 @@ spec: vpcID: description: The ID of the VPC. type: string - required: - - vpcID + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object type: object status: description: RouteTableStatus defines the observed state of RouteTable diff --git a/helm/crds/ec2.services.k8s.aws_securitygroups.yaml b/helm/crds/ec2.services.k8s.aws_securitygroups.yaml index 0d6207a2..9ce09675 100644 --- a/helm/crds/ec2.services.k8s.aws_securitygroups.yaml +++ b/helm/crds/ec2.services.k8s.aws_securitygroups.yaml @@ -72,10 +72,23 @@ spec: vpcID: description: '[EC2-VPC] The ID of the VPC. Required for EC2-VPC.' type: string + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object required: - description - name - - vpcID type: object status: description: SecurityGroupStatus defines the observed state of SecurityGroup diff --git a/helm/crds/ec2.services.k8s.aws_subnets.yaml b/helm/crds/ec2.services.k8s.aws_subnets.yaml index 8d55752c..8d1fe4f8 100644 --- a/helm/crds/ec2.services.k8s.aws_subnets.yaml +++ b/helm/crds/ec2.services.k8s.aws_subnets.yaml @@ -90,9 +90,22 @@ spec: vpcID: description: The ID of the VPC. type: string + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object required: - cidrBlock - - vpcID type: object status: description: SubnetStatus defines the observed state of Subnet diff --git a/helm/crds/ec2.services.k8s.aws_vpcendpoints.yaml b/helm/crds/ec2.services.k8s.aws_vpcendpoints.yaml index 8aa1fbb5..6fc49bde 100644 --- a/helm/crds/ec2.services.k8s.aws_vpcendpoints.yaml +++ b/helm/crds/ec2.services.k8s.aws_vpcendpoints.yaml @@ -66,12 +66,44 @@ spec: items: type: string type: array + routeTableRefs: + items: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object + type: array securityGroupIDs: description: (Interface endpoint) The ID of one or more security groups to associate with the endpoint network interface. items: type: string type: array + securityGroupRefs: + items: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object + type: array serviceName: description: The service name. To get a list of available services, use the DescribeVpcEndpointServices request, or get the name from @@ -85,6 +117,22 @@ spec: items: type: string type: array + subnetRefs: + items: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object + type: array tagSpecifications: description: The tags to associate with the endpoint. items: @@ -111,9 +159,22 @@ spec: vpcID: description: The ID of the VPC in which the endpoint will be used. type: string + vpcRef: + description: 'AWSResourceReferenceWrapper provides a wrapper around + *AWSResourceReference type to provide more user friendly syntax + for references using ''from'' field Ex: APIIDRef: from: name: + my-api' + properties: + from: + description: AWSResourceReference provides all the values necessary + to reference another k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + type: object + type: object required: - serviceName - - vpcID type: object status: description: VPCEndpointStatus defines the observed state of VPCEndpoint diff --git a/pkg/resource/route_table/delta.go b/pkg/resource/route_table/delta.go index b12feb6d..f35909bc 100644 --- a/pkg/resource/route_table/delta.go +++ b/pkg/resource/route_table/delta.go @@ -54,6 +54,9 @@ func newResourceDelta( delta.Add("Spec.VPCID", a.ko.Spec.VPCID, b.ko.Spec.VPCID) } } + if !reflect.DeepEqual(a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) { + delta.Add("Spec.VPCRef", a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) + } return delta } diff --git a/pkg/resource/route_table/references.go b/pkg/resource/route_table/references.go index d4a87d98..a6f2601b 100644 --- a/pkg/resource/route_table/references.go +++ b/pkg/resource/route_table/references.go @@ -17,8 +17,15 @@ package route_table import ( "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" @@ -36,17 +43,89 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, error) { - return res, nil + namespace := res.MetaObject().GetNamespace() + ko := rm.concreteResource(res).ko.DeepCopy() + err := validateReferenceFields(ko) + if err == nil { + err = resolveReferenceForVPCID(ctx, apiReader, namespace, ko) + } + + if hasNonNilReferences(ko) { + return ackcondition.WithReferencesResolvedCondition(&resource{ko}, err) + } + return &resource{ko}, err } // validateReferenceFields validates the reference field and corresponding // identifier field. func validateReferenceFields(ko *svcapitypes.RouteTable) error { + if ko.Spec.VPCRef != nil && ko.Spec.VPCID != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("VPCID", "VPCRef") + } + if ko.Spec.VPCRef == nil && ko.Spec.VPCID == nil { + return ackerr.ResourceReferenceOrIDRequiredFor("VPCID", "VPCRef") + } return nil } // hasNonNilReferences returns true if resource contains a reference to another // resource func hasNonNilReferences(ko *svcapitypes.RouteTable) bool { - return false + return false || ko.Spec.VPCRef != nil +} + +// resolveReferenceForVPCID reads the resource referenced +// from VPCRef field and sets the VPCID +// from referenced resource +func resolveReferenceForVPCID( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.RouteTable, +) error { + if ko.Spec.VPCRef != nil && + ko.Spec.VPCRef.From != nil { + arr := ko.Spec.VPCRef.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.VPC{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "VPC", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "VPC", + namespace, *arr.Name) + } + if obj.Status.VPCID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "VPC", + namespace, *arr.Name, + "Status.VPCID") + } + ko.Spec.VPCID = obj.Status.VPCID + } + return nil } diff --git a/pkg/resource/security_group/delta.go b/pkg/resource/security_group/delta.go index 7b915bfd..5b6641aa 100644 --- a/pkg/resource/security_group/delta.go +++ b/pkg/resource/security_group/delta.go @@ -65,6 +65,9 @@ func newResourceDelta( delta.Add("Spec.VPCID", a.ko.Spec.VPCID, b.ko.Spec.VPCID) } } + if !reflect.DeepEqual(a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) { + delta.Add("Spec.VPCRef", a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) + } return delta } diff --git a/pkg/resource/security_group/references.go b/pkg/resource/security_group/references.go index ac27b185..ea159a01 100644 --- a/pkg/resource/security_group/references.go +++ b/pkg/resource/security_group/references.go @@ -17,8 +17,15 @@ package security_group import ( "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" @@ -36,17 +43,89 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, error) { - return res, nil + namespace := res.MetaObject().GetNamespace() + ko := rm.concreteResource(res).ko.DeepCopy() + err := validateReferenceFields(ko) + if err == nil { + err = resolveReferenceForVPCID(ctx, apiReader, namespace, ko) + } + + if hasNonNilReferences(ko) { + return ackcondition.WithReferencesResolvedCondition(&resource{ko}, err) + } + return &resource{ko}, err } // validateReferenceFields validates the reference field and corresponding // identifier field. func validateReferenceFields(ko *svcapitypes.SecurityGroup) error { + if ko.Spec.VPCRef != nil && ko.Spec.VPCID != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("VPCID", "VPCRef") + } + if ko.Spec.VPCRef == nil && ko.Spec.VPCID == nil { + return ackerr.ResourceReferenceOrIDRequiredFor("VPCID", "VPCRef") + } return nil } // hasNonNilReferences returns true if resource contains a reference to another // resource func hasNonNilReferences(ko *svcapitypes.SecurityGroup) bool { - return false + return false || ko.Spec.VPCRef != nil +} + +// resolveReferenceForVPCID reads the resource referenced +// from VPCRef field and sets the VPCID +// from referenced resource +func resolveReferenceForVPCID( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.SecurityGroup, +) error { + if ko.Spec.VPCRef != nil && + ko.Spec.VPCRef.From != nil { + arr := ko.Spec.VPCRef.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.VPC{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "VPC", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "VPC", + namespace, *arr.Name) + } + if obj.Status.VPCID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "VPC", + namespace, *arr.Name, + "Status.VPCID") + } + ko.Spec.VPCID = obj.Status.VPCID + } + return nil } diff --git a/pkg/resource/subnet/delta.go b/pkg/resource/subnet/delta.go index 2d807c02..db6365f4 100644 --- a/pkg/resource/subnet/delta.go +++ b/pkg/resource/subnet/delta.go @@ -86,6 +86,9 @@ func newResourceDelta( delta.Add("Spec.VPCID", a.ko.Spec.VPCID, b.ko.Spec.VPCID) } } + if !reflect.DeepEqual(a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) { + delta.Add("Spec.VPCRef", a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) + } return delta } diff --git a/pkg/resource/subnet/references.go b/pkg/resource/subnet/references.go index e8b782d5..b4f6e7c3 100644 --- a/pkg/resource/subnet/references.go +++ b/pkg/resource/subnet/references.go @@ -17,8 +17,15 @@ package subnet import ( "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" @@ -36,17 +43,89 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, error) { - return res, nil + namespace := res.MetaObject().GetNamespace() + ko := rm.concreteResource(res).ko.DeepCopy() + err := validateReferenceFields(ko) + if err == nil { + err = resolveReferenceForVPCID(ctx, apiReader, namespace, ko) + } + + if hasNonNilReferences(ko) { + return ackcondition.WithReferencesResolvedCondition(&resource{ko}, err) + } + return &resource{ko}, err } // validateReferenceFields validates the reference field and corresponding // identifier field. func validateReferenceFields(ko *svcapitypes.Subnet) error { + if ko.Spec.VPCRef != nil && ko.Spec.VPCID != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("VPCID", "VPCRef") + } + if ko.Spec.VPCRef == nil && ko.Spec.VPCID == nil { + return ackerr.ResourceReferenceOrIDRequiredFor("VPCID", "VPCRef") + } return nil } // hasNonNilReferences returns true if resource contains a reference to another // resource func hasNonNilReferences(ko *svcapitypes.Subnet) bool { - return false + return false || ko.Spec.VPCRef != nil +} + +// resolveReferenceForVPCID reads the resource referenced +// from VPCRef field and sets the VPCID +// from referenced resource +func resolveReferenceForVPCID( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.Subnet, +) error { + if ko.Spec.VPCRef != nil && + ko.Spec.VPCRef.From != nil { + arr := ko.Spec.VPCRef.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.VPC{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "VPC", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "VPC", + namespace, *arr.Name) + } + if obj.Status.VPCID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "VPC", + namespace, *arr.Name, + "Status.VPCID") + } + ko.Spec.VPCID = obj.Status.VPCID + } + return nil } diff --git a/pkg/resource/vpc_endpoint/delta.go b/pkg/resource/vpc_endpoint/delta.go index 82a1da3d..2ea6c0b0 100644 --- a/pkg/resource/vpc_endpoint/delta.go +++ b/pkg/resource/vpc_endpoint/delta.go @@ -65,9 +65,15 @@ func newResourceDelta( if !ackcompare.SliceStringPEqual(a.ko.Spec.RouteTableIDs, b.ko.Spec.RouteTableIDs) { delta.Add("Spec.RouteTableIDs", a.ko.Spec.RouteTableIDs, b.ko.Spec.RouteTableIDs) } + if !reflect.DeepEqual(a.ko.Spec.RouteTableRefs, b.ko.Spec.RouteTableRefs) { + delta.Add("Spec.RouteTableRefs", a.ko.Spec.RouteTableRefs, b.ko.Spec.RouteTableRefs) + } if !ackcompare.SliceStringPEqual(a.ko.Spec.SecurityGroupIDs, b.ko.Spec.SecurityGroupIDs) { delta.Add("Spec.SecurityGroupIDs", a.ko.Spec.SecurityGroupIDs, b.ko.Spec.SecurityGroupIDs) } + if !reflect.DeepEqual(a.ko.Spec.SecurityGroupRefs, b.ko.Spec.SecurityGroupRefs) { + delta.Add("Spec.SecurityGroupRefs", a.ko.Spec.SecurityGroupRefs, b.ko.Spec.SecurityGroupRefs) + } if ackcompare.HasNilDifference(a.ko.Spec.ServiceName, b.ko.Spec.ServiceName) { delta.Add("Spec.ServiceName", a.ko.Spec.ServiceName, b.ko.Spec.ServiceName) } else if a.ko.Spec.ServiceName != nil && b.ko.Spec.ServiceName != nil { @@ -78,6 +84,9 @@ func newResourceDelta( if !ackcompare.SliceStringPEqual(a.ko.Spec.SubnetIDs, b.ko.Spec.SubnetIDs) { delta.Add("Spec.SubnetIDs", a.ko.Spec.SubnetIDs, b.ko.Spec.SubnetIDs) } + if !reflect.DeepEqual(a.ko.Spec.SubnetRefs, b.ko.Spec.SubnetRefs) { + delta.Add("Spec.SubnetRefs", a.ko.Spec.SubnetRefs, b.ko.Spec.SubnetRefs) + } if !reflect.DeepEqual(a.ko.Spec.TagSpecifications, b.ko.Spec.TagSpecifications) { delta.Add("Spec.TagSpecifications", a.ko.Spec.TagSpecifications, b.ko.Spec.TagSpecifications) } @@ -95,6 +104,9 @@ func newResourceDelta( delta.Add("Spec.VPCID", a.ko.Spec.VPCID, b.ko.Spec.VPCID) } } + if !reflect.DeepEqual(a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) { + delta.Add("Spec.VPCRef", a.ko.Spec.VPCRef, b.ko.Spec.VPCRef) + } return delta } diff --git a/pkg/resource/vpc_endpoint/references.go b/pkg/resource/vpc_endpoint/references.go index bd24b927..eee6cbe0 100644 --- a/pkg/resource/vpc_endpoint/references.go +++ b/pkg/resource/vpc_endpoint/references.go @@ -17,8 +17,15 @@ package vpc_endpoint import ( "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" @@ -36,17 +43,290 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, error) { - return res, nil + namespace := res.MetaObject().GetNamespace() + ko := rm.concreteResource(res).ko.DeepCopy() + err := validateReferenceFields(ko) + if err == nil { + err = resolveReferenceForRouteTableIDs(ctx, apiReader, namespace, ko) + } + if err == nil { + err = resolveReferenceForSecurityGroupIDs(ctx, apiReader, namespace, ko) + } + if err == nil { + err = resolveReferenceForSubnetIDs(ctx, apiReader, namespace, ko) + } + if err == nil { + err = resolveReferenceForVPCID(ctx, apiReader, namespace, ko) + } + + if hasNonNilReferences(ko) { + return ackcondition.WithReferencesResolvedCondition(&resource{ko}, err) + } + return &resource{ko}, err } // validateReferenceFields validates the reference field and corresponding // identifier field. func validateReferenceFields(ko *svcapitypes.VPCEndpoint) error { + if ko.Spec.RouteTableRefs != nil && ko.Spec.RouteTableIDs != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("RouteTableIDs", "RouteTableRefs") + } + if ko.Spec.SecurityGroupRefs != nil && ko.Spec.SecurityGroupIDs != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("SecurityGroupIDs", "SecurityGroupRefs") + } + if ko.Spec.SubnetRefs != nil && ko.Spec.SubnetIDs != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("SubnetIDs", "SubnetRefs") + } + if ko.Spec.VPCRef != nil && ko.Spec.VPCID != nil { + return ackerr.ResourceReferenceAndIDNotSupportedFor("VPCID", "VPCRef") + } + if ko.Spec.VPCRef == nil && ko.Spec.VPCID == nil { + return ackerr.ResourceReferenceOrIDRequiredFor("VPCID", "VPCRef") + } return nil } // hasNonNilReferences returns true if resource contains a reference to another // resource func hasNonNilReferences(ko *svcapitypes.VPCEndpoint) bool { - return false + return false || ko.Spec.RouteTableRefs != nil || ko.Spec.SecurityGroupRefs != nil || ko.Spec.SubnetRefs != nil || ko.Spec.VPCRef != nil +} + +// resolveReferenceForRouteTableIDs reads the resource referenced +// from RouteTableRefs field and sets the RouteTableIDs +// from referenced resource +func resolveReferenceForRouteTableIDs( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.VPCEndpoint, +) error { + if ko.Spec.RouteTableRefs != nil && + len(ko.Spec.RouteTableRefs) > 0 { + resolvedReferences := []*string{} + for _, arrw := range ko.Spec.RouteTableRefs { + arr := arrw.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.RouteTable{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "RouteTable", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "RouteTable", + namespace, *arr.Name) + } + if obj.Status.RouteTableID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "RouteTable", + namespace, *arr.Name, + "Status.RouteTableID") + } + resolvedReferences = append(resolvedReferences, + obj.Status.RouteTableID) + } + ko.Spec.RouteTableIDs = resolvedReferences + } + return nil +} + +// resolveReferenceForSecurityGroupIDs reads the resource referenced +// from SecurityGroupRefs field and sets the SecurityGroupIDs +// from referenced resource +func resolveReferenceForSecurityGroupIDs( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.VPCEndpoint, +) error { + if ko.Spec.SecurityGroupRefs != nil && + len(ko.Spec.SecurityGroupRefs) > 0 { + resolvedReferences := []*string{} + for _, arrw := range ko.Spec.SecurityGroupRefs { + arr := arrw.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.SecurityGroup{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "SecurityGroup", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "SecurityGroup", + namespace, *arr.Name) + } + if obj.Status.ID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "SecurityGroup", + namespace, *arr.Name, + "Status.ID") + } + resolvedReferences = append(resolvedReferences, + obj.Status.ID) + } + ko.Spec.SecurityGroupIDs = resolvedReferences + } + return nil +} + +// resolveReferenceForSubnetIDs reads the resource referenced +// from SubnetRefs field and sets the SubnetIDs +// from referenced resource +func resolveReferenceForSubnetIDs( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.VPCEndpoint, +) error { + if ko.Spec.SubnetRefs != nil && + len(ko.Spec.SubnetRefs) > 0 { + resolvedReferences := []*string{} + for _, arrw := range ko.Spec.SubnetRefs { + arr := arrw.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.Subnet{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "Subnet", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "Subnet", + namespace, *arr.Name) + } + if obj.Status.SubnetID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "Subnet", + namespace, *arr.Name, + "Status.SubnetID") + } + resolvedReferences = append(resolvedReferences, + obj.Status.SubnetID) + } + ko.Spec.SubnetIDs = resolvedReferences + } + return nil +} + +// resolveReferenceForVPCID reads the resource referenced +// from VPCRef field and sets the VPCID +// from referenced resource +func resolveReferenceForVPCID( + ctx context.Context, + apiReader client.Reader, + namespace string, + ko *svcapitypes.VPCEndpoint, +) error { + if ko.Spec.VPCRef != nil && + ko.Spec.VPCRef.From != nil { + arr := ko.Spec.VPCRef.From + if arr == nil || arr.Name == nil || *arr.Name == "" { + return fmt.Errorf("provided resource reference is nil or empty") + } + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: *arr.Name, + } + obj := svcapitypes.VPC{} + err := apiReader.Get(ctx, namespacedName, &obj) + if err != nil { + return err + } + var refResourceSynced, refResourceTerminal bool + for _, cond := range obj.Status.Conditions { + if cond.Type == ackv1alpha1.ConditionTypeResourceSynced && + cond.Status == corev1.ConditionTrue { + refResourceSynced = true + } + if cond.Type == ackv1alpha1.ConditionTypeTerminal && + cond.Status == corev1.ConditionTrue { + refResourceTerminal = true + } + } + if refResourceTerminal { + return ackerr.ResourceReferenceTerminalFor( + "VPC", + namespace, *arr.Name) + } + if !refResourceSynced { + return ackerr.ResourceReferenceNotSyncedFor( + "VPC", + namespace, *arr.Name) + } + if obj.Status.VPCID == nil { + return ackerr.ResourceReferenceMissingTargetFieldFor( + "VPC", + namespace, *arr.Name, + "Status.VPCID") + } + ko.Spec.VPCID = obj.Status.VPCID + } + return nil }