diff --git a/api/v1beta1/awscluster_conversion.go b/api/v1beta1/awscluster_conversion.go index 805d60856e..4b52c8a135 100644 --- a/api/v1beta1/awscluster_conversion.go +++ b/api/v1beta1/awscluster_conversion.go @@ -150,6 +150,9 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error { } } + // Restore V1Beta2 status from annotations. + dst.Status.V1Beta2 = restored.Status.V1Beta2 + return nil } @@ -230,3 +233,10 @@ func (r *AWSClusterList) ConvertFrom(srcRaw conversion.Hub) error { func Convert_v1beta2_SubnetSpec_To_v1beta1_SubnetSpec(in *infrav1.SubnetSpec, out *SubnetSpec, s apiconversion.Scope) error { return autoConvert_v1beta2_SubnetSpec_To_v1beta1_SubnetSpec(in, out, s) } + +// Convert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus handles the V1Beta2 field +// that doesn't exist in v1beta1. The V1Beta2 conditions are dropped during down-conversion +// and will be restored from annotations during up-conversion. +func Convert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(in *infrav1.AWSClusterStatus, out *AWSClusterStatus, s apiconversion.Scope) error { + return autoConvert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(in, out, s) +} diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go index 44f2227f38..2b05e26c4d 100644 --- a/api/v1beta1/zz_generated.conversion.go +++ b/api/v1beta1/zz_generated.conversion.go @@ -179,11 +179,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta2.AWSClusterStatus)(nil), (*AWSClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(a.(*v1beta2.AWSClusterStatus), b.(*AWSClusterStatus), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*AWSClusterTemplate)(nil), (*v1beta2.AWSClusterTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_AWSClusterTemplate_To_v1beta2_AWSClusterTemplate(a.(*AWSClusterTemplate), b.(*v1beta2.AWSClusterTemplate), scope) }); err != nil { @@ -529,6 +524,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta2.AWSClusterStatus)(nil), (*AWSClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(a.(*v1beta2.AWSClusterStatus), b.(*AWSClusterStatus), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta2.AWSLoadBalancerSpec)(nil), (*AWSLoadBalancerSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_AWSLoadBalancerSpec_To_v1beta1_AWSLoadBalancerSpec(a.(*v1beta2.AWSLoadBalancerSpec), b.(*AWSLoadBalancerSpec), scope) }); err != nil { @@ -1065,14 +1065,10 @@ func autoConvert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(in *v1beta out.Bastion = nil } out.Conditions = *(*corev1beta1.Conditions)(unsafe.Pointer(&in.Conditions)) + // WARNING: in.V1Beta2 requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus is an autogenerated conversion function. -func Convert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(in *v1beta2.AWSClusterStatus, out *AWSClusterStatus, s conversion.Scope) error { - return autoConvert_v1beta2_AWSClusterStatus_To_v1beta1_AWSClusterStatus(in, out, s) -} - func autoConvert_v1beta1_AWSClusterTemplate_To_v1beta2_AWSClusterTemplate(in *AWSClusterTemplate, out *v1beta2.AWSClusterTemplate, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1beta1_AWSClusterTemplateSpec_To_v1beta2_AWSClusterTemplateSpec(&in.Spec, &out.Spec, s); err != nil { diff --git a/api/v1beta2/awscluster_types.go b/api/v1beta2/awscluster_types.go index 184ef9de43..acbebdbeb6 100644 --- a/api/v1beta2/awscluster_types.go +++ b/api/v1beta2/awscluster_types.go @@ -281,6 +281,23 @@ type AWSClusterStatus struct { FailureDomains clusterv1beta1.FailureDomains `json:"failureDomains,omitempty"` Bastion *Instance `json:"bastion,omitempty"` Conditions clusterv1beta1.Conditions `json:"conditions,omitempty"` + + // v1beta2 groups all the fields that will be added or modified in AWSCluster's status with the V1Beta2 CAPI contract version. + // +optional + V1Beta2 *AWSClusterV1Beta2Status `json:"v1beta2,omitempty"` +} + +// AWSClusterV1Beta2Status groups all the fields that will be added or modified in AWSCluster with the V1Beta2 CAPI contract version. +// See https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20240916-improve-status-in-CAPI-resources.md for more context. +type AWSClusterV1Beta2Status struct { + // Conditions represents the observations of an AWSCluster's current state. + // Known condition types are Ready, VpcReady, SubnetsReady, InternetGatewayReady, NatGatewaysReady, + // RouteTablesReady, ClusterSecurityGroupsReady, BastionHostReady, LoadBalancerReady, and Paused. + // +optional + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MaxItems=32 + Conditions []metav1.Condition `json:"conditions,omitempty"` } // S3Bucket defines a supporting S3 bucket for the cluster, currently can be optionally used for Ignition. @@ -355,6 +372,24 @@ func (r *AWSCluster) SetConditions(conditions clusterv1beta1.Conditions) { r.Status.Conditions = conditions } +// GetV1Beta2Conditions returns the set of conditions for this object. +// Note: GetV1Beta2Conditions will be renamed to GetConditions in a later stage of the transition to CAPI contract V1Beta2. +func (r *AWSCluster) GetV1Beta2Conditions() []metav1.Condition { + if r.Status.V1Beta2 == nil { + return nil + } + return r.Status.V1Beta2.Conditions +} + +// SetV1Beta2Conditions sets conditions for an API object. +// Note: SetV1Beta2Conditions will be renamed to SetConditions in a later stage of the transition to CAPI contract V1Beta2. +func (r *AWSCluster) SetV1Beta2Conditions(conditions []metav1.Condition) { + if r.Status.V1Beta2 == nil { + r.Status.V1Beta2 = &AWSClusterV1Beta2Status{} + } + r.Status.V1Beta2.Conditions = conditions +} + func init() { SchemeBuilder.Register(&AWSCluster{}, &AWSClusterList{}) } diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 1293074cb5..9c34d3dc68 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -432,6 +432,11 @@ func (in *AWSClusterStatus) DeepCopyInto(out *AWSClusterStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.V1Beta2 != nil { + in, out := &in.V1Beta2, &out.V1Beta2 + *out = new(AWSClusterV1Beta2Status) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSClusterStatus. @@ -535,6 +540,28 @@ func (in *AWSClusterTemplateSpec) DeepCopy() *AWSClusterTemplateSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSClusterV1Beta2Status) DeepCopyInto(out *AWSClusterV1Beta2Status) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSClusterV1Beta2Status. +func (in *AWSClusterV1Beta2Status) DeepCopy() *AWSClusterV1Beta2Status { + if in == nil { + return nil + } + out := new(AWSClusterV1Beta2Status) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSIdentityReference) DeepCopyInto(out *AWSIdentityReference) { *out = *in diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml index 2b317498fe..050ff1379d 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml @@ -3159,6 +3159,76 @@ spec: ready: default: false type: boolean + v1beta2: + description: v1beta2 groups all the fields that will be added or modified + in AWSCluster's status with the V1Beta2 CAPI contract version. + properties: + conditions: + description: |- + Conditions represents the observations of an AWSCluster's current state. + Known condition types are Ready, VpcReady, SubnetsReady, InternetGatewayReady, NatGatewaysReady, + RouteTablesReady, ClusterSecurityGroupsReady, BastionHostReady, LoadBalancerReady, and Paused. + items: + description: Condition contains details for one aspect of the + current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object required: - ready type: object