From 9ad02ed61d2a60d45302b41ae6792a5a37f3352a Mon Sep 17 00:00:00 2001 From: Matthew Booth Date: Mon, 25 Mar 2024 14:08:10 +0000 Subject: [PATCH] ImageFilter to ImageParam --- api/v1alpha5/conversion.go | 16 ++-- api/v1alpha5/zz_generated.conversion.go | 4 +- api/v1alpha6/openstackmachine_conversion.go | 16 ++-- api/v1alpha6/zz_generated.conversion.go | 4 +- api/v1alpha7/openstackmachine_conversion.go | 16 ++-- api/v1alpha7/zz_generated.conversion.go | 4 +- api/v1beta1/openstackmachine_types.go | 2 +- api/v1beta1/types.go | 28 +++++- api/v1beta1/zz_generated.deepcopy.go | 30 +++++- ...re.cluster.x-k8s.io_openstackclusters.yaml | 46 ++++++---- ...er.x-k8s.io_openstackclustertemplates.yaml | 49 +++++----- ...re.cluster.x-k8s.io_openstackmachines.yaml | 43 +++++---- ...er.x-k8s.io_openstackmachinetemplates.yaml | 46 ++++++---- .../openstackcluster_controller_test.go | 6 +- .../openstackmachine_controller_test.go | 2 +- docs/book/src/api/v1beta1/api.md | 65 ++++++++++--- .../v1beta1/default/cluster-template.yaml | 6 +- .../v1beta1/flatcar-sysext/patch-flatcar.yaml | 6 +- kustomize/v1beta1/flatcar/patch-flatcar.yaml | 6 +- pkg/cloud/services/compute/instance.go | 10 +- pkg/cloud/services/compute/instance_test.go | 38 ++++++-- .../compute/referenced_resources_test.go | 16 ++-- pkg/webhooks/openstackcluster_webhook_test.go | 24 ++++- .../openstackmachinetemplate_webhook_test.go | 48 ++++++++-- .../cluster-template-flatcar-sysext.yaml | 6 +- templates/cluster-template-flatcar.yaml | 6 +- templates/cluster-template-without-lb.yaml | 6 +- templates/cluster-template.yaml | 6 +- templates/clusterclass-dev-test.yaml | 4 +- .../cluster-prev1beta1/kustomization.yaml | 10 ++ .../patch-cluster.yaml | 0 .../common-patches/cluster/kustomization.yaml | 10 ++ .../common-patches/cluster/patch-cluster.yaml | 15 +++ .../common-patches/cni/kustomization.yaml | 4 - .../data/kustomize/default/kustomization.yaml | 1 + .../flatcar-sysext/kustomization.yaml | 1 + .../data/kustomize/flatcar/kustomization.yaml | 1 + .../k8s-upgrade/upgrade-from-template.yaml | 6 +- .../k8s-upgrade/upgrade-to-template.yaml | 6 +- .../kustomize/v1alpha6/kustomization.yaml | 1 + .../kustomize/v1alpha7/kustomization.yaml | 1 + .../kustomize/without-lb/kustomization.yaml | 1 + .../e2e/suites/apivalidations/filters_test.go | 92 +++++++++++-------- .../apivalidations/openstackcluster_test.go | 18 +++- .../apivalidations/openstackmachine_test.go | 6 +- test/e2e/suites/e2e/e2e_test.go | 12 ++- test/helpers/fuzzerfuncs.go | 4 + 47 files changed, 507 insertions(+), 241 deletions(-) create mode 100644 test/e2e/data/kustomize/common-patches/cluster-prev1beta1/kustomization.yaml rename test/e2e/data/kustomize/common-patches/{cni => cluster-prev1beta1}/patch-cluster.yaml (100%) create mode 100644 test/e2e/data/kustomize/common-patches/cluster/kustomization.yaml create mode 100644 test/e2e/data/kustomize/common-patches/cluster/patch-cluster.yaml diff --git a/api/v1alpha5/conversion.go b/api/v1alpha5/conversion.go index 50944701eb..b9439a54eb 100644 --- a/api/v1alpha5/conversion.go +++ b/api/v1alpha5/conversion.go @@ -356,13 +356,13 @@ func Convert_v1alpha5_OpenStackMachineSpec_To_v1beta1_OpenStackMachineSpec(in *O out.ServerGroup = &infrav1.ServerGroupFilter{} } - imageFilter := infrav1.ImageFilter{} + imageParam := infrav1.ImageParam{} if in.ImageUUID != "" { - imageFilter.ID = &in.ImageUUID + imageParam.ID = &in.ImageUUID } else if in.Image != "" { // Only add name when ID is not set, in v1beta1 it's not possible to set both. - imageFilter.Name = &in.Image + imageParam.Filter = &infrav1.ImageFilter{Name: &in.Image} } - out.Image = imageFilter + out.Image = imageParam if in.IdentityRef != nil { out.IdentityRef = &infrav1.OpenStackIdentityReference{Name: in.IdentityRef.Name} @@ -686,12 +686,10 @@ func Convert_v1beta1_OpenStackMachineSpec_To_v1alpha5_OpenStackMachineSpec(in *i out.ServerGroupID = in.ServerGroup.ID } - if in.Image.Name != nil && *in.Image.Name != "" { - out.Image = *in.Image.Name - } - - if in.Image.ID != nil && *in.Image.ID != "" { + if in.Image.ID != nil { out.ImageUUID = *in.Image.ID + } else if in.Image.Filter != nil && in.Image.Filter.Name != nil { + out.Image = *in.Image.Filter.Name } if in.IdentityRef != nil { diff --git a/api/v1alpha5/zz_generated.conversion.go b/api/v1alpha5/zz_generated.conversion.go index 2a335b80c5..2c5a688927 100644 --- a/api/v1alpha5/zz_generated.conversion.go +++ b/api/v1alpha5/zz_generated.conversion.go @@ -1142,7 +1142,7 @@ func autoConvert_v1alpha5_OpenStackMachineSpec_To_v1beta1_OpenStackMachineSpec(i out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) // WARNING: in.CloudName requires manual conversion: does not exist in peer-type out.Flavor = in.Flavor - // WARNING: in.Image requires manual conversion: inconvertible types (string vs sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageFilter) + // WARNING: in.Image requires manual conversion: inconvertible types (string vs sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageParam) // WARNING: in.ImageUUID requires manual conversion: does not exist in peer-type out.SSHKeyName = in.SSHKeyName // WARNING: in.Networks requires manual conversion: does not exist in peer-type @@ -1192,7 +1192,7 @@ func autoConvert_v1beta1_OpenStackMachineSpec_To_v1alpha5_OpenStackMachineSpec(i out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) out.Flavor = in.Flavor - // WARNING: in.Image requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageFilter vs string) + // WARNING: in.Image requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageParam vs string) out.SSHKeyName = in.SSHKeyName if in.Ports != nil { in, out := &in.Ports, &out.Ports diff --git a/api/v1alpha6/openstackmachine_conversion.go b/api/v1alpha6/openstackmachine_conversion.go index d8439d19f1..2b5864d818 100644 --- a/api/v1alpha6/openstackmachine_conversion.go +++ b/api/v1alpha6/openstackmachine_conversion.go @@ -272,13 +272,13 @@ func Convert_v1alpha6_OpenStackMachineSpec_To_v1beta1_OpenStackMachineSpec(in *O out.ServerGroup = nil } - imageFilter := infrav1.ImageFilter{} + imageParam := infrav1.ImageParam{} if in.ImageUUID != "" { - imageFilter.ID = &in.ImageUUID + imageParam.ID = &in.ImageUUID } else if in.Image != "" { // Only add name when ID is not set, in v1beta1 it's not possible to set both. - imageFilter.Name = &in.Image + imageParam.Filter = &infrav1.ImageFilter{Name: &in.Image} } - out.Image = imageFilter + out.Image = imageParam if len(in.ServerMetadata) > 0 { serverMetadata := make([]infrav1.ServerMetadata, 0, len(in.ServerMetadata)) @@ -320,12 +320,10 @@ func Convert_v1beta1_OpenStackMachineSpec_To_v1alpha6_OpenStackMachineSpec(in *i out.ServerGroupID = in.ServerGroup.ID } - if in.Image.Name != nil && *in.Image.Name != "" { - out.Image = *in.Image.Name - } - - if in.Image.ID != nil && *in.Image.ID != "" { + if in.Image.ID != nil { out.ImageUUID = *in.Image.ID + } else if in.Image.Filter != nil && in.Image.Filter.Name != nil { + out.Image = *in.Image.Filter.Name } if len(in.ServerMetadata) > 0 { diff --git a/api/v1alpha6/zz_generated.conversion.go b/api/v1alpha6/zz_generated.conversion.go index 2b98c9a0d8..8e33e36df6 100644 --- a/api/v1alpha6/zz_generated.conversion.go +++ b/api/v1alpha6/zz_generated.conversion.go @@ -1177,7 +1177,7 @@ func autoConvert_v1alpha6_OpenStackMachineSpec_To_v1beta1_OpenStackMachineSpec(i out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) // WARNING: in.CloudName requires manual conversion: does not exist in peer-type out.Flavor = in.Flavor - // WARNING: in.Image requires manual conversion: inconvertible types (string vs sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageFilter) + // WARNING: in.Image requires manual conversion: inconvertible types (string vs sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageParam) // WARNING: in.ImageUUID requires manual conversion: does not exist in peer-type out.SSHKeyName = in.SSHKeyName // WARNING: in.Networks requires manual conversion: does not exist in peer-type @@ -1227,7 +1227,7 @@ func autoConvert_v1beta1_OpenStackMachineSpec_To_v1alpha6_OpenStackMachineSpec(i out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) out.Flavor = in.Flavor - // WARNING: in.Image requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageFilter vs string) + // WARNING: in.Image requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageParam vs string) out.SSHKeyName = in.SSHKeyName if in.Ports != nil { in, out := &in.Ports, &out.Ports diff --git a/api/v1alpha7/openstackmachine_conversion.go b/api/v1alpha7/openstackmachine_conversion.go index 9ce17bbbd3..4731f7445c 100644 --- a/api/v1alpha7/openstackmachine_conversion.go +++ b/api/v1alpha7/openstackmachine_conversion.go @@ -170,13 +170,13 @@ func Convert_v1alpha7_OpenStackMachineSpec_To_v1beta1_OpenStackMachineSpec(in *O out.ServerGroup = nil } - imageFilter := infrav1.ImageFilter{} + imageParam := infrav1.ImageParam{} if in.ImageUUID != "" { - imageFilter.ID = &in.ImageUUID + imageParam.ID = &in.ImageUUID } else if in.Image != "" { // Only add name when ID is not set, in v1beta1 it's not possible to set both. - imageFilter.Name = &in.Image + imageParam.Filter = &infrav1.ImageFilter{Name: &in.Image} } - out.Image = imageFilter + out.Image = imageParam if len(in.ServerMetadata) > 0 { serverMetadata := make([]infrav1.ServerMetadata, 0, len(in.ServerMetadata)) @@ -215,12 +215,10 @@ func Convert_v1beta1_OpenStackMachineSpec_To_v1alpha7_OpenStackMachineSpec(in *i out.ServerGroupID = in.ServerGroup.ID } - if in.Image.Name != nil && *in.Image.Name != "" { - out.Image = *in.Image.Name - } - - if in.Image.ID != nil && *in.Image.ID != "" { + if in.Image.ID != nil { out.ImageUUID = *in.Image.ID + } else if in.Image.Filter != nil && in.Image.Filter.Name != nil { + out.Image = *in.Image.Filter.Name } if len(in.ServerMetadata) > 0 { diff --git a/api/v1alpha7/zz_generated.conversion.go b/api/v1alpha7/zz_generated.conversion.go index 6e00e14144..87bb5dc328 100644 --- a/api/v1alpha7/zz_generated.conversion.go +++ b/api/v1alpha7/zz_generated.conversion.go @@ -1364,7 +1364,7 @@ func autoConvert_v1alpha7_OpenStackMachineSpec_To_v1beta1_OpenStackMachineSpec(i out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) // WARNING: in.CloudName requires manual conversion: does not exist in peer-type out.Flavor = in.Flavor - // WARNING: in.Image requires manual conversion: inconvertible types (string vs sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageFilter) + // WARNING: in.Image requires manual conversion: inconvertible types (string vs sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageParam) // WARNING: in.ImageUUID requires manual conversion: does not exist in peer-type out.SSHKeyName = in.SSHKeyName if in.Ports != nil { @@ -1413,7 +1413,7 @@ func autoConvert_v1beta1_OpenStackMachineSpec_To_v1alpha7_OpenStackMachineSpec(i out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) out.Flavor = in.Flavor - // WARNING: in.Image requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageFilter vs string) + // WARNING: in.Image requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.ImageParam vs string) out.SSHKeyName = in.SSHKeyName if in.Ports != nil { in, out := &in.Ports, &out.Ports diff --git a/api/v1beta1/openstackmachine_types.go b/api/v1beta1/openstackmachine_types.go index 5a7b05c319..3f20a559ff 100644 --- a/api/v1beta1/openstackmachine_types.go +++ b/api/v1beta1/openstackmachine_types.go @@ -45,7 +45,7 @@ type OpenStackMachineSpec struct { // The image to use for your server instance. // If the rootVolume is specified, this will be used when creating the root volume. // +required - Image ImageFilter `json:"image"` + Image ImageParam `json:"image"` // The ssh key to inject in the instance SSHKeyName string `json:"sshKeyName,omitempty"` diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index ad67976e96..e9b9bbb2f6 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -28,22 +28,42 @@ type OpenStackMachineTemplateResource struct { Spec OpenStackMachineSpec `json:"spec"` } -// ImageFilter describes the data needed to identify which image to use. If ID is provided it is required that all other fields are unset. -// +kubebuilder:validation:XValidation:rule="(has(self.id) && !has(self.name) && !has(self.tags)) || !has(self.id)",message="when ID is set you cannot set other options" -type ImageFilter struct { - // The ID of the desired image. If ID is provided, the other filters cannot be provided. Must be in UUID format. +// ImageParam describes a glance image. It can be specified by ID or filter. +// +kubebuilder:validation:MaxProperties:=1 +// +kubebuilder:validation:MinProperties:=1 +type ImageParam struct { + // ID is the uuid of the image. ID will not be validated before use. // +kubebuilder:validation:Format:=uuid // +optional ID optional.String `json:"id,omitempty"` + + // Filter describes a query for an image. If specified, the combination + // of name and tags must return a single matching image or an error will + // be raised. + // +optional + Filter *ImageFilter `json:"filter,omitempty"` +} + +// ImageFilter describes a query for an image. +// +kubebuilder:validation:MinProperties:=1 +type ImageFilter struct { // The name of the desired image. If specified, the combination of name and tags must return a single matching image or an error will be raised. // +optional Name optional.String `json:"name,omitempty"` + // The tags associated with the desired image. If specified, the combination of name and tags must return a single matching image or an error will be raised. // +listType=set // +optional Tags []string `json:"tags,omitempty"` } +func (f *ImageFilter) IsZero() bool { + if f == nil { + return true + } + return f.Name == nil && len(f.Tags) == 0 +} + type ExternalRouterIPParam struct { // The FixedIP in the corresponding subnet FixedIP string `json:"fixedIP,omitempty"` diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index bbaa79118a..9c8f75f97f 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -307,11 +307,6 @@ func (in *FixedIP) DeepCopy() *FixedIP { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ImageFilter) DeepCopyInto(out *ImageFilter) { *out = *in - if in.ID != nil { - in, out := &in.ID, &out.ID - *out = new(string) - **out = **in - } if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) @@ -334,6 +329,31 @@ func (in *ImageFilter) DeepCopy() *ImageFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageParam) DeepCopyInto(out *ImageParam) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(ImageFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageParam. +func (in *ImageParam) DeepCopy() *ImageParam { + if in == nil { + return nil + } + out := new(ImageParam) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { *out = *in diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml index c4adc2b0b7..1490e10a21 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml @@ -5050,31 +5050,37 @@ spec: description: |- The image to use for your server instance. If the rootVolume is specified, this will be used when creating the root volume. + maxProperties: 1 + minProperties: 1 properties: + filter: + description: |- + Filter describes a query for an image. If specified, the combination + of name and tags must return a single matching image or an error will + be raised. + minProperties: 1 + properties: + name: + description: The name of the desired image. If specified, + the combination of name and tags must return a single + matching image or an error will be raised. + type: string + tags: + description: The tags associated with the desired + image. If specified, the combination of name and + tags must return a single matching image or an error + will be raised. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object id: - description: The ID of the desired image. If ID is provided, - the other filters cannot be provided. Must be in UUID - format. + description: ID is the uuid of the image. ID will not + be validated before use. format: uuid type: string - name: - description: The name of the desired image. If specified, - the combination of name and tags must return a single - matching image or an error will be raised. - type: string - tags: - description: The tags associated with the desired image. - If specified, the combination of name and tags must - return a single matching image or an error will be raised. - items: - type: string - type: array - x-kubernetes-list-type: set type: object - x-kubernetes-validations: - - message: when ID is set you cannot set other options - rule: (has(self.id) && !has(self.name) && !has(self.tags)) - || !has(self.id) instanceID: description: InstanceID is the OpenStack instance ID for this machine. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml index a6943b023a..c0a334ec4c 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml @@ -2477,33 +2477,38 @@ spec: description: |- The image to use for your server instance. If the rootVolume is specified, this will be used when creating the root volume. + maxProperties: 1 + minProperties: 1 properties: + filter: + description: |- + Filter describes a query for an image. If specified, the combination + of name and tags must return a single matching image or an error will + be raised. + minProperties: 1 + properties: + name: + description: The name of the desired image. + If specified, the combination of name and + tags must return a single matching image + or an error will be raised. + type: string + tags: + description: The tags associated with the + desired image. If specified, the combination + of name and tags must return a single matching + image or an error will be raised. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object id: - description: The ID of the desired image. If ID - is provided, the other filters cannot be provided. - Must be in UUID format. + description: ID is the uuid of the image. ID will + not be validated before use. format: uuid type: string - name: - description: The name of the desired image. If - specified, the combination of name and tags - must return a single matching image or an error - will be raised. - type: string - tags: - description: The tags associated with the desired - image. If specified, the combination of name - and tags must return a single matching image - or an error will be raised. - items: - type: string - type: array - x-kubernetes-list-type: set type: object - x-kubernetes-validations: - - message: when ID is set you cannot set other options - rule: (has(self.id) && !has(self.name) && !has(self.tags)) - || !has(self.id) instanceID: description: InstanceID is the OpenStack instance ID for this machine. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml index 40ce3c87fd..1ea294dcb1 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml @@ -1831,29 +1831,36 @@ spec: description: |- The image to use for your server instance. If the rootVolume is specified, this will be used when creating the root volume. + maxProperties: 1 + minProperties: 1 properties: + filter: + description: |- + Filter describes a query for an image. If specified, the combination + of name and tags must return a single matching image or an error will + be raised. + minProperties: 1 + properties: + name: + description: The name of the desired image. If specified, + the combination of name and tags must return a single matching + image or an error will be raised. + type: string + tags: + description: The tags associated with the desired image. If + specified, the combination of name and tags must return + a single matching image or an error will be raised. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object id: - description: The ID of the desired image. If ID is provided, the - other filters cannot be provided. Must be in UUID format. + description: ID is the uuid of the image. ID will not be validated + before use. format: uuid type: string - name: - description: The name of the desired image. If specified, the - combination of name and tags must return a single matching image - or an error will be raised. - type: string - tags: - description: The tags associated with the desired image. If specified, - the combination of name and tags must return a single matching - image or an error will be raised. - items: - type: string - type: array - x-kubernetes-list-type: set type: object - x-kubernetes-validations: - - message: when ID is set you cannot set other options - rule: (has(self.id) && !has(self.name) && !has(self.tags)) || !has(self.id) instanceID: description: InstanceID is the OpenStack instance ID for this machine. type: string diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml index e2c222712a..4c1b1abb98 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml @@ -1504,31 +1504,37 @@ spec: description: |- The image to use for your server instance. If the rootVolume is specified, this will be used when creating the root volume. + maxProperties: 1 + minProperties: 1 properties: + filter: + description: |- + Filter describes a query for an image. If specified, the combination + of name and tags must return a single matching image or an error will + be raised. + minProperties: 1 + properties: + name: + description: The name of the desired image. If specified, + the combination of name and tags must return a single + matching image or an error will be raised. + type: string + tags: + description: The tags associated with the desired + image. If specified, the combination of name and + tags must return a single matching image or an error + will be raised. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object id: - description: The ID of the desired image. If ID is provided, - the other filters cannot be provided. Must be in UUID - format. + description: ID is the uuid of the image. ID will not + be validated before use. format: uuid type: string - name: - description: The name of the desired image. If specified, - the combination of name and tags must return a single - matching image or an error will be raised. - type: string - tags: - description: The tags associated with the desired image. - If specified, the combination of name and tags must - return a single matching image or an error will be raised. - items: - type: string - type: array - x-kubernetes-list-type: set type: object - x-kubernetes-validations: - - message: when ID is set you cannot set other options - rule: (has(self.id) && !has(self.name) && !has(self.tags)) - || !has(self.id) instanceID: description: InstanceID is the OpenStack instance ID for this machine. diff --git a/controllers/openstackcluster_controller_test.go b/controllers/openstackcluster_controller_test.go index 0b6fe63784..c2a602ec31 100644 --- a/controllers/openstackcluster_controller_test.go +++ b/controllers/openstackcluster_controller_test.go @@ -62,8 +62,10 @@ var _ = Describe("OpenStackCluster controller", func() { testClusterName := "test-cluster" testNum := 0 bastionSpec := infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{ - Name: pointer.String("fake-name"), + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("fake-name"), + }, }, } diff --git a/controllers/openstackmachine_controller_test.go b/controllers/openstackmachine_controller_test.go index d57848f80f..53c504e05c 100644 --- a/controllers/openstackmachine_controller_test.go +++ b/controllers/openstackmachine_controller_test.go @@ -84,7 +84,7 @@ func getDefaultOpenStackMachine() *infrav1.OpenStackMachine { // FloatingIP is only used by the cluster controller for the Bastion // TODO: Test Networks, Ports, Subnet, and Trunk separately Flavor: flavorName, - Image: infrav1.ImageFilter{ID: pointer.String(imageUUID)}, + Image: infrav1.ImageParam{ID: pointer.String(imageUUID)}, SSHKeyName: sshKeyName, Tags: []string{"test-tag"}, ServerMetadata: []infrav1.ServerMetadata{ diff --git a/docs/book/src/api/v1beta1/api.md b/docs/book/src/api/v1beta1/api.md index ecc495a928..581f7326ef 100644 --- a/docs/book/src/api/v1beta1/api.md +++ b/docs/book/src/api/v1beta1/api.md @@ -587,8 +587,8 @@ string image
- -ImageFilter + +ImageParam @@ -1580,10 +1580,10 @@ address in any subnet of the port’s network.

(Appears on: -OpenStackMachineSpec) +ImageParam)

-

ImageFilter describes the data needed to identify which image to use. If ID is provided it is required that all other fields are unset.

+

ImageFilter describes a query for an image.

@@ -1595,38 +1595,73 @@ address in any subnet of the port’s network.

+ + + +
-id
+name
string
(Optional) -

The ID of the desired image. If ID is provided, the other filters cannot be provided. Must be in UUID format.

+

The name of the desired image. If specified, the combination of name and tags must return a single matching image or an error will be raised.

-name
+tags
+ +[]string + +
+(Optional) +

The tags associated with the desired image. If specified, the combination of name and tags must return a single matching image or an error will be raised.

+
+

ImageParam +

+

+(Appears on: +OpenStackMachineSpec) +

+

+

ImageParam describes a glance image. It can be specified by ID or filter.

+

+ + + + + + + + + + @@ -3101,8 +3136,8 @@ string @@ -3473,8 +3508,8 @@ string diff --git a/kustomize/v1beta1/default/cluster-template.yaml b/kustomize/v1beta1/default/cluster-template.yaml index 52ab6c2f88..ae7db083cf 100644 --- a/kustomize/v1beta1/default/cluster-template.yaml +++ b/kustomize/v1beta1/default/cluster-template.yaml @@ -97,7 +97,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- apiVersion: cluster.x-k8s.io/v1beta1 @@ -133,7 +134,8 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 diff --git a/kustomize/v1beta1/flatcar-sysext/patch-flatcar.yaml b/kustomize/v1beta1/flatcar-sysext/patch-flatcar.yaml index 0c60d2e460..6c143c853c 100644 --- a/kustomize/v1beta1/flatcar-sysext/patch-flatcar.yaml +++ b/kustomize/v1beta1/flatcar-sysext/patch-flatcar.yaml @@ -170,7 +170,8 @@ spec: template: spec: image: - name: ${FLATCAR_IMAGE_NAME} + filter: + name: ${FLATCAR_IMAGE_NAME} --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: OpenStackMachineTemplate @@ -180,4 +181,5 @@ spec: template: spec: image: - name: ${FLATCAR_IMAGE_NAME} + filter: + name: ${FLATCAR_IMAGE_NAME} diff --git a/kustomize/v1beta1/flatcar/patch-flatcar.yaml b/kustomize/v1beta1/flatcar/patch-flatcar.yaml index d95991efc9..a702429646 100644 --- a/kustomize/v1beta1/flatcar/patch-flatcar.yaml +++ b/kustomize/v1beta1/flatcar/patch-flatcar.yaml @@ -94,7 +94,8 @@ spec: template: spec: image: - name: ${OPENSTACK_FLATCAR_IMAGE_NAME} + filter: + name: ${OPENSTACK_FLATCAR_IMAGE_NAME} --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: OpenStackMachineTemplate @@ -104,4 +105,5 @@ spec: template: spec: image: - name: ${OPENSTACK_FLATCAR_IMAGE_NAME} + filter: + name: ${OPENSTACK_FLATCAR_IMAGE_NAME} diff --git a/pkg/cloud/services/compute/instance.go b/pkg/cloud/services/compute/instance.go index eebfd9278d..ac0b377bed 100644 --- a/pkg/cloud/services/compute/instance.go +++ b/pkg/cloud/services/compute/instance.go @@ -18,6 +18,7 @@ package compute import ( "context" + "errors" "fmt" "os" "strconv" @@ -332,12 +333,17 @@ func applyServerGroupID(opts servers.CreateOptsBuilder, serverGroupID string) se } // Helper function for getting image ID from name, ID, or tags. -func (s *Service) GetImageID(image infrav1.ImageFilter) (string, error) { +func (s *Service) GetImageID(image infrav1.ImageParam) (string, error) { if image.ID != nil { return *image.ID, nil } - listOpts := filterconvert.ImageFilterToListOpts(&image) + if image.Filter == nil { + // Should have been caught by validation + return "", errors.New("image id and filter are both nil") + } + + listOpts := filterconvert.ImageFilterToListOpts(image.Filter) allImages, err := s.getImageClient().ListImages(listOpts) if err != nil { return "", err diff --git a/pkg/cloud/services/compute/instance_test.go b/pkg/cloud/services/compute/instance_test.go index af9214e8a7..b571b25021 100644 --- a/pkg/cloud/services/compute/instance_test.go +++ b/pkg/cloud/services/compute/instance_test.go @@ -47,22 +47,26 @@ func TestService_getImageID(t *testing.T) { tests := []struct { testName string - image infrav1.ImageFilter + image infrav1.ImageParam expect func(m *mock.MockImageClientMockRecorder) want string wantErr bool }{ { testName: "Return image ID when ID given", - image: infrav1.ImageFilter{ID: &imageID}, + image: infrav1.ImageParam{ID: &imageID}, want: imageID, expect: func(m *mock.MockImageClientMockRecorder) {}, wantErr: false, }, { testName: "Return image ID when name given", - image: infrav1.ImageFilter{Name: &imageName}, - want: imageID, + image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: &imageName, + }, + }, + want: imageID, expect: func(m *mock.MockImageClientMockRecorder) { m.ListImages(images.ListOpts{Name: imageName}).Return( []images.Image{{ID: imageID, Name: imageName}}, @@ -72,8 +76,12 @@ func TestService_getImageID(t *testing.T) { }, { testName: "Return image ID when tags given", - image: infrav1.ImageFilter{Tags: imageTags}, - want: imageID, + image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Tags: imageTags, + }, + }, + want: imageID, expect: func(m *mock.MockImageClientMockRecorder) { m.ListImages(images.ListOpts{Tags: imageTags}).Return( []images.Image{{ID: imageID, Name: imageName, Tags: imageTags}}, @@ -83,7 +91,11 @@ func TestService_getImageID(t *testing.T) { }, { testName: "Return no results", - image: infrav1.ImageFilter{Name: &imageName}, + image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: &imageName, + }, + }, expect: func(m *mock.MockImageClientMockRecorder) { m.ListImages(images.ListOpts{Name: imageName}).Return( []images.Image{}, @@ -94,7 +106,11 @@ func TestService_getImageID(t *testing.T) { }, { testName: "Return multiple results", - image: infrav1.ImageFilter{Name: &imageName}, + image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: &imageName, + }, + }, expect: func(m *mock.MockImageClientMockRecorder) { m.ListImages(images.ListOpts{Name: "test-image"}).Return( []images.Image{ @@ -107,7 +123,11 @@ func TestService_getImageID(t *testing.T) { }, { testName: "OpenStack returns error", - image: infrav1.ImageFilter{Name: &imageName}, + image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: &imageName, + }, + }, expect: func(m *mock.MockImageClientMockRecorder) { m.ListImages(images.ListOpts{Name: "test-image"}).Return( nil, diff --git a/pkg/cloud/services/compute/referenced_resources_test.go b/pkg/cloud/services/compute/referenced_resources_test.go index 035bdaf824..b4419b691d 100644 --- a/pkg/cloud/services/compute/referenced_resources_test.go +++ b/pkg/cloud/services/compute/referenced_resources_test.go @@ -68,7 +68,7 @@ func Test_ResolveMachineSpec(t *testing.T) { testName: "Resources ID passed", spec: infrav1.OpenStackMachineSpec{ ServerGroup: &infrav1.ServerGroupFilter{ID: serverGroupID1}, - Image: infrav1.ImageFilter{ID: pointer.String(imageID1)}, + Image: infrav1.ImageParam{ID: pointer.String(imageID1)}, }, want: &infrav1.ResolvedMachineSpec{ ImageID: imageID1, @@ -79,7 +79,7 @@ func Test_ResolveMachineSpec(t *testing.T) { { testName: "Only image ID passed: want image id and default ports", spec: infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{ID: pointer.String(imageID1)}, + Image: infrav1.ImageParam{ID: pointer.String(imageID1)}, }, want: &infrav1.ResolvedMachineSpec{ ImageID: imageID1, @@ -89,7 +89,7 @@ func Test_ResolveMachineSpec(t *testing.T) { { testName: "Server group empty", spec: infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{ID: pointer.String(imageID1)}, + Image: infrav1.ImageParam{ID: pointer.String(imageID1)}, ServerGroup: &infrav1.ServerGroupFilter{}, }, want: &infrav1.ResolvedMachineSpec{ @@ -100,7 +100,7 @@ func Test_ResolveMachineSpec(t *testing.T) { { testName: "Server group by Name not found", spec: infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{ID: pointer.String(imageID1)}, + Image: infrav1.ImageParam{ID: pointer.String(imageID1)}, ServerGroup: &infrav1.ServerGroupFilter{Name: "test-server-group"}, }, expectComputeMock: func(m *mock.MockComputeClientMockRecorder) { @@ -114,7 +114,11 @@ func Test_ResolveMachineSpec(t *testing.T) { { testName: "Image by Name not found", spec: infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{Name: pointer.String("test-image")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("test-image"), + }, + }, }, expectImageMock: func(m *mock.MockImageClientMockRecorder) { m.ListImages(images.ListOpts{Name: "test-image"}).Return([]images.Image{}, nil) @@ -125,7 +129,7 @@ func Test_ResolveMachineSpec(t *testing.T) { { testName: "Ports set", spec: infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{ID: pointer.String(imageID1)}, + Image: infrav1.ImageParam{ID: pointer.String(imageID1)}, Ports: []infrav1.PortOpts{ { Network: &infrav1.NetworkParam{ diff --git a/pkg/webhooks/openstackcluster_webhook_test.go b/pkg/webhooks/openstackcluster_webhook_test.go index 3d65376486..09c18dcc70 100644 --- a/pkg/webhooks/openstackcluster_webhook_test.go +++ b/pkg/webhooks/openstackcluster_webhook_test.go @@ -85,7 +85,11 @@ func TestOpenStackCluster_ValidateUpdate(t *testing.T) { }, Bastion: &infrav1.Bastion{ Spec: &infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{Name: pointer.String("foobar")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("foobar"), + }, + }, Flavor: "minimal", }, Enabled: true, @@ -105,7 +109,11 @@ func TestOpenStackCluster_ValidateUpdate(t *testing.T) { }, Bastion: &infrav1.Bastion{ Spec: &infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{Name: pointer.String("foobarbaz")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("foobarbaz"), + }, + }, Flavor: "medium", }, Enabled: true, @@ -454,7 +462,11 @@ func TestOpenStackCluster_ValidateUpdate(t *testing.T) { Enabled: true, Spec: &infrav1.OpenStackMachineSpec{ Flavor: "m1.small", - Image: infrav1.ImageFilter{Name: pointer.String("ubuntu")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("ubuntu"), + }, + }, }, }, }, @@ -481,7 +493,11 @@ func TestOpenStackCluster_ValidateUpdate(t *testing.T) { Enabled: false, Spec: &infrav1.OpenStackMachineSpec{ Flavor: "m1.small", - Image: infrav1.ImageFilter{Name: pointer.String("ubuntu")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("ubuntu"), + }, + }, }, }, }, diff --git a/pkg/webhooks/openstackmachinetemplate_webhook_test.go b/pkg/webhooks/openstackmachinetemplate_webhook_test.go index 899cf509f1..6b148f3bfa 100644 --- a/pkg/webhooks/openstackmachinetemplate_webhook_test.go +++ b/pkg/webhooks/openstackmachinetemplate_webhook_test.go @@ -47,7 +47,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("bar")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + }, + }, }, }, }, @@ -57,7 +61,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("NewImage")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("NewImage"), + }, + }, }, }, }, @@ -72,7 +80,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("bar")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + }, + }, }, }, }, @@ -85,7 +97,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("bar")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + }, + }, }, }, }, @@ -102,7 +118,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("bar")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + }, + }, }, }, }, @@ -112,7 +132,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("NewImage")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("NewImage"), + }, + }, }, }, }, @@ -127,7 +151,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("bar")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + }, + }, }, }, }, @@ -142,7 +170,11 @@ func TestOpenStackMachineTemplate_ValidateUpdate(t *testing.T) { Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: "foo", - Image: infrav1.ImageFilter{Name: pointer.String("NewImage")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("NewImage"), + }, + }, }, }, }, diff --git a/templates/cluster-template-flatcar-sysext.yaml b/templates/cluster-template-flatcar-sysext.yaml index 9cbef933cc..ec33bdeff2 100644 --- a/templates/cluster-template-flatcar-sysext.yaml +++ b/templates/cluster-template-flatcar-sysext.yaml @@ -268,7 +268,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${FLATCAR_IMAGE_NAME} + filter: + name: ${FLATCAR_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 @@ -280,5 +281,6 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${FLATCAR_IMAGE_NAME} + filter: + name: ${FLATCAR_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/templates/cluster-template-flatcar.yaml b/templates/cluster-template-flatcar.yaml index 3d3f92ba23..4282265943 100644 --- a/templates/cluster-template-flatcar.yaml +++ b/templates/cluster-template-flatcar.yaml @@ -192,7 +192,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_FLATCAR_IMAGE_NAME} + filter: + name: ${OPENSTACK_FLATCAR_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 @@ -204,5 +205,6 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_FLATCAR_IMAGE_NAME} + filter: + name: ${OPENSTACK_FLATCAR_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/templates/cluster-template-without-lb.yaml b/templates/cluster-template-without-lb.yaml index 35acfdbdf1..6dbf7a72d1 100644 --- a/templates/cluster-template-without-lb.yaml +++ b/templates/cluster-template-without-lb.yaml @@ -144,7 +144,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 @@ -156,5 +157,6 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/templates/cluster-template.yaml b/templates/cluster-template.yaml index bc8c8aab8c..3508d37e26 100644 --- a/templates/cluster-template.yaml +++ b/templates/cluster-template.yaml @@ -146,7 +146,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 @@ -158,5 +159,6 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/templates/clusterclass-dev-test.yaml b/templates/clusterclass-dev-test.yaml index 2cd3a38531..5743a6367d 100644 --- a/templates/clusterclass-dev-test.yaml +++ b/templates/clusterclass-dev-test.yaml @@ -43,7 +43,7 @@ spec: controlPlane: true jsonPatches: - op: add - path: /spec/template/spec/image/name + path: /spec/template/spec/image/filter/name valueFrom: template: | ubuntu-2204-kube-{{ .builtin.controlPlane.version }} @@ -59,7 +59,7 @@ spec: - default-worker jsonPatches: - op: add - path: /spec/template/spec/image/name + path: /spec/template/spec/image/filter/name valueFrom: template: | ubuntu-2204-kube-{{ .builtin.machineDeployment.version }} diff --git a/test/e2e/data/kustomize/common-patches/cluster-prev1beta1/kustomization.yaml b/test/e2e/data/kustomize/common-patches/cluster-prev1beta1/kustomization.yaml new file mode 100644 index 0000000000..7136e9600d --- /dev/null +++ b/test/e2e/data/kustomize/common-patches/cluster-prev1beta1/kustomization.yaml @@ -0,0 +1,10 @@ +# Modifications to release templates common to all e2e test scenarios +--- +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +patches: +- target: + kind: OpenStackCluster + name: \${CLUSTER_NAME} + path: patch-cluster.yaml diff --git a/test/e2e/data/kustomize/common-patches/cni/patch-cluster.yaml b/test/e2e/data/kustomize/common-patches/cluster-prev1beta1/patch-cluster.yaml similarity index 100% rename from test/e2e/data/kustomize/common-patches/cni/patch-cluster.yaml rename to test/e2e/data/kustomize/common-patches/cluster-prev1beta1/patch-cluster.yaml diff --git a/test/e2e/data/kustomize/common-patches/cluster/kustomization.yaml b/test/e2e/data/kustomize/common-patches/cluster/kustomization.yaml new file mode 100644 index 0000000000..7136e9600d --- /dev/null +++ b/test/e2e/data/kustomize/common-patches/cluster/kustomization.yaml @@ -0,0 +1,10 @@ +# Modifications to release templates common to all e2e test scenarios +--- +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +patches: +- target: + kind: OpenStackCluster + name: \${CLUSTER_NAME} + path: patch-cluster.yaml diff --git a/test/e2e/data/kustomize/common-patches/cluster/patch-cluster.yaml b/test/e2e/data/kustomize/common-patches/cluster/patch-cluster.yaml new file mode 100644 index 0000000000..b6d9564506 --- /dev/null +++ b/test/e2e/data/kustomize/common-patches/cluster/patch-cluster.yaml @@ -0,0 +1,15 @@ +--- +- op: add + path: /spec/bastion + value: + enabled: true + spec: + flavor: ${OPENSTACK_BASTION_MACHINE_FLAVOR} + image: + filter: + name: ${OPENSTACK_BASTION_IMAGE_NAME} + sshKeyName: ${OPENSTACK_SSH_KEY_NAME} +- op: add + path: /spec/controlPlaneAvailabilityZones + value: + - ${OPENSTACK_FAILURE_DOMAIN} diff --git a/test/e2e/data/kustomize/common-patches/cni/kustomization.yaml b/test/e2e/data/kustomize/common-patches/cni/kustomization.yaml index 60fe867342..0f10084b63 100644 --- a/test/e2e/data/kustomize/common-patches/cni/kustomization.yaml +++ b/test/e2e/data/kustomize/common-patches/cni/kustomization.yaml @@ -7,8 +7,4 @@ resources: - cni.yaml patches: -- target: - kind: OpenStackCluster - name: \${CLUSTER_NAME} - path: patch-cluster.yaml - path: patch-cni.yaml diff --git a/test/e2e/data/kustomize/default/kustomization.yaml b/test/e2e/data/kustomize/default/kustomization.yaml index 30f2c9d85d..e85e60a623 100644 --- a/test/e2e/data/kustomize/default/kustomization.yaml +++ b/test/e2e/data/kustomize/default/kustomization.yaml @@ -3,6 +3,7 @@ kind: Kustomization resources: - ../../../../../kustomize/v1beta1/default components: +- ../common-patches/cluster - ../common-patches/cni - ../upgrade-patches - ../common-patches/ccm diff --git a/test/e2e/data/kustomize/flatcar-sysext/kustomization.yaml b/test/e2e/data/kustomize/flatcar-sysext/kustomization.yaml index 6738cde3a8..63c5035c15 100644 --- a/test/e2e/data/kustomize/flatcar-sysext/kustomization.yaml +++ b/test/e2e/data/kustomize/flatcar-sysext/kustomization.yaml @@ -3,6 +3,7 @@ resources: - ../../../../../kustomize/v1beta1/flatcar-sysext components: +- ../common-patches/cluster - ../common-patches/cni - ../common-patches/ccm - ../common-patches/externalNetworkByName diff --git a/test/e2e/data/kustomize/flatcar/kustomization.yaml b/test/e2e/data/kustomize/flatcar/kustomization.yaml index 2de905e98e..ca872d20cb 100644 --- a/test/e2e/data/kustomize/flatcar/kustomization.yaml +++ b/test/e2e/data/kustomize/flatcar/kustomization.yaml @@ -4,6 +4,7 @@ resources: - ../../../../../kustomize/v1beta1/flatcar components: +- ../common-patches/cluster - ../common-patches/cni - ../common-patches/ccm - ../common-patches/externalNetworkByName diff --git a/test/e2e/data/kustomize/k8s-upgrade/upgrade-from-template.yaml b/test/e2e/data/kustomize/k8s-upgrade/upgrade-from-template.yaml index 6e9098977b..d49208116d 100644 --- a/test/e2e/data/kustomize/k8s-upgrade/upgrade-from-template.yaml +++ b/test/e2e/data/kustomize/k8s-upgrade/upgrade-from-template.yaml @@ -8,7 +8,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME_UPGRADE_FROM} + filter: + name: ${OPENSTACK_IMAGE_NAME_UPGRADE_FROM} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} tags: - control-plane @@ -22,7 +23,8 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME_UPGRADE_FROM} + filter: + name: ${OPENSTACK_IMAGE_NAME_UPGRADE_FROM} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} tags: - machine diff --git a/test/e2e/data/kustomize/k8s-upgrade/upgrade-to-template.yaml b/test/e2e/data/kustomize/k8s-upgrade/upgrade-to-template.yaml index 39272254fd..466cb7931b 100644 --- a/test/e2e/data/kustomize/k8s-upgrade/upgrade-to-template.yaml +++ b/test/e2e/data/kustomize/k8s-upgrade/upgrade-to-template.yaml @@ -15,7 +15,8 @@ spec: spec: flavor: ${OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} tags: - control-plane @@ -31,7 +32,8 @@ spec: spec: flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: - name: ${OPENSTACK_IMAGE_NAME} + filter: + name: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} tags: - machine diff --git a/test/e2e/data/kustomize/v1alpha6/kustomization.yaml b/test/e2e/data/kustomize/v1alpha6/kustomization.yaml index 9f7ac4445d..f2035ba071 100644 --- a/test/e2e/data/kustomize/v1alpha6/kustomization.yaml +++ b/test/e2e/data/kustomize/v1alpha6/kustomization.yaml @@ -4,6 +4,7 @@ resources: - ../../../../../kustomize/v1alpha6/external-cloud-provider components: +- ../common-patches/cluster-prev1beta1 - ../common-patches/cni - ../common-patches/ccm diff --git a/test/e2e/data/kustomize/v1alpha7/kustomization.yaml b/test/e2e/data/kustomize/v1alpha7/kustomization.yaml index ed5685505c..9bcee09929 100644 --- a/test/e2e/data/kustomize/v1alpha7/kustomization.yaml +++ b/test/e2e/data/kustomize/v1alpha7/kustomization.yaml @@ -4,6 +4,7 @@ resources: - ../../../../../kustomize/v1alpha6/external-cloud-provider components: +- ../common-patches/cluster-prev1beta1 - ../common-patches/cni - ../common-patches/ccm diff --git a/test/e2e/data/kustomize/without-lb/kustomization.yaml b/test/e2e/data/kustomize/without-lb/kustomization.yaml index 7f3842e60c..2d88085bde 100644 --- a/test/e2e/data/kustomize/without-lb/kustomization.yaml +++ b/test/e2e/data/kustomize/without-lb/kustomization.yaml @@ -4,6 +4,7 @@ resources: - ../../../../../kustomize/v1beta1/without-lb components: +- ../common-patches/cluster - ../common-patches/cni - ../common-patches/ccm - ../common-patches/externalNetworkByName diff --git a/test/e2e/suites/apivalidations/filters_test.go b/test/e2e/suites/apivalidations/filters_test.go index a6001c3ab2..e2bad140a5 100644 --- a/test/e2e/suites/apivalidations/filters_test.go +++ b/test/e2e/suites/apivalidations/filters_test.go @@ -36,7 +36,11 @@ var _ = Describe("Filter API validations", func() { namespace = createNamespace() // Initialise a basic machine object in the correct namespace - machine = &infrav1.OpenStackMachine{} + machine = &infrav1.OpenStackMachine{ + Spec: infrav1.OpenStackMachineSpec{ + Image: infrav1.ImageParam{Filter: &infrav1.ImageFilter{Name: pointer.String("test-image")}}, + }, + } machine.Namespace = namespace.Name machine.GenerateName = "machine-" @@ -179,49 +183,59 @@ var _ = Describe("Filter API validations", func() { }), ) - const imageUUID = "5a78f794-cdc3-48d2-8d9f-0fd472fdd743" + Context("ImageParam", func() { + const imageUUID = "5a78f794-cdc3-48d2-8d9f-0fd472fdd743" - It("should not allow both ID and Name of ImageFilter to be set", func() { - By("Creating a machine") - machine.Spec.Image = infrav1.ImageFilter{ - ID: pointer.String(imageUUID), - Name: pointer.String("bar"), - } - Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") - }) + It("should not allow both ID and Filter to be set", func() { + machine.Spec.Image = infrav1.ImageParam{ + ID: pointer.String(imageUUID), + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + }, + } + Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") + }) - It("should not allow both ID and Tags of ImageFilter to be set", func() { - By("Creating a machine") - machine.Spec.Image = infrav1.ImageFilter{ - ID: pointer.String(imageUUID), - Tags: []string{"bar", "baz"}, - } - Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") - }) + It("should not allow both ID and Tags of ImageFilter to be set", func() { + machine.Spec.Image = infrav1.ImageParam{ + ID: pointer.String(imageUUID), + Filter: &infrav1.ImageFilter{ + Tags: []string{"bar", "baz"}, + }, + } + Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") + }) - It("should allow UUID ID of ImageFilter to be set", func() { - By("Creating a machine") - machine.Spec.Image = infrav1.ImageFilter{ - ID: pointer.String(imageUUID), - } - Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "OpenStackMachine creation should succeed") - }) + It("should allow UUID ID of ImageFilter to be set", func() { + machine.Spec.Image = infrav1.ImageParam{ + ID: pointer.String(imageUUID), + } + Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "OpenStackMachine creation should succeed") + }) - It("should not allow non-UUID ID of ImageFilter to be set", func() { - By("Creating a machine") - machine.Spec.Image = infrav1.ImageFilter{ - ID: pointer.String("foo"), - } - Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") - }) + It("should not allow non-UUID ID of ImageFilter to be set", func() { + machine.Spec.Image = infrav1.ImageParam{ + ID: pointer.String("foo"), + } + Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") + }) - It("should allow Name and Tags of ImageFilter to be set", func() { - By("Creating a machine") - machine.Spec.Image = infrav1.ImageFilter{ - Name: pointer.String("bar"), - Tags: []string{"bar", "baz"}, - } - Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "OpenStackMachine creation should succeed") + It("should allow Name and Tags of ImageFilter to be set", func() { + machine.Spec.Image = infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("bar"), + Tags: []string{"bar", "baz"}, + }, + } + Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "OpenStackMachine creation should succeed") + }) + + It("should not allow a non-nil, empty image filter", func() { + machine.Spec.Image = infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{}, + } + Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail") + }) }) Context("NetworkParam", func() { diff --git a/test/e2e/suites/apivalidations/openstackcluster_test.go b/test/e2e/suites/apivalidations/openstackcluster_test.go index f84e1d13d7..947f9b7b84 100644 --- a/test/e2e/suites/apivalidations/openstackcluster_test.go +++ b/test/e2e/suites/apivalidations/openstackcluster_test.go @@ -92,7 +92,11 @@ var _ = Describe("OpenStackCluster API validations", func() { cluster.Spec.Bastion = &infrav1.Bastion{ Enabled: true, Spec: &infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{Name: pointer.String("fake-image")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("fake-image"), + }, + }, }, } Expect(k8sClient.Create(ctx, cluster)).To(Succeed(), "OpenStackCluster creation should succeed") @@ -120,7 +124,11 @@ var _ = Describe("OpenStackCluster API validations", func() { cluster.Spec.Bastion = &infrav1.Bastion{ Enabled: true, Spec: &infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{Name: pointer.String("fake-image")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("fake-image"), + }, + }, }, FloatingIP: pointer.String("10.0.0.0"), } @@ -131,7 +139,11 @@ var _ = Describe("OpenStackCluster API validations", func() { cluster.Spec.Bastion = &infrav1.Bastion{ Enabled: true, Spec: &infrav1.OpenStackMachineSpec{ - Image: infrav1.ImageFilter{Name: pointer.String("fake-image")}, + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String("fake-image"), + }, + }, }, FloatingIP: pointer.String("foobar"), } diff --git a/test/e2e/suites/apivalidations/openstackmachine_test.go b/test/e2e/suites/apivalidations/openstackmachine_test.go index c984ab1e61..4e888a3a41 100644 --- a/test/e2e/suites/apivalidations/openstackmachine_test.go +++ b/test/e2e/suites/apivalidations/openstackmachine_test.go @@ -35,7 +35,11 @@ var _ = Describe("OpenStackMachine API validations", func() { namespace = createNamespace() // Initialise a basic machine object in the correct namespace - machine = &infrav1.OpenStackMachine{} + machine = &infrav1.OpenStackMachine{ + Spec: infrav1.OpenStackMachineSpec{ + Image: infrav1.ImageParam{Filter: &infrav1.ImageFilter{Name: pointer.String("test-image")}}, + }, + } machine.Namespace = namespace.Name machine.GenerateName = "machine-" }) diff --git a/test/e2e/suites/e2e/e2e_test.go b/test/e2e/suites/e2e/e2e_test.go index fadae81131..37422eb33f 100644 --- a/test/e2e/suites/e2e/e2e_test.go +++ b/test/e2e/suites/e2e/e2e_test.go @@ -859,8 +859,10 @@ func makeOpenStackMachineTemplate(namespace, clusterName, name string) *infrav1. Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: e2eCtx.E2EConfig.GetVariable(shared.OpenStackNodeMachineFlavor), - Image: infrav1.ImageFilter{ - Name: pointer.String(e2eCtx.E2EConfig.GetVariable(shared.OpenStackImageName)), + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String(e2eCtx.E2EConfig.GetVariable(shared.OpenStackImageName)), + }, }, SSHKeyName: shared.DefaultSSHKeyPairName, IdentityRef: &infrav1.OpenStackIdentityReference{ @@ -883,8 +885,10 @@ func makeOpenStackMachineTemplateWithPortOptions(namespace, clusterName, name st Template: infrav1.OpenStackMachineTemplateResource{ Spec: infrav1.OpenStackMachineSpec{ Flavor: e2eCtx.E2EConfig.GetVariable(shared.OpenStackNodeMachineFlavor), - Image: infrav1.ImageFilter{ - Name: pointer.String(e2eCtx.E2EConfig.GetVariable(shared.OpenStackImageName)), + Image: infrav1.ImageParam{ + Filter: &infrav1.ImageFilter{ + Name: pointer.String(e2eCtx.E2EConfig.GetVariable(shared.OpenStackImageName)), + }, }, SSHKeyName: shared.DefaultSSHKeyPairName, IdentityRef: &infrav1.OpenStackIdentityReference{ diff --git a/test/helpers/fuzzerfuncs.go b/test/helpers/fuzzerfuncs.go index 2c3a0fe188..36ee8baa85 100644 --- a/test/helpers/fuzzerfuncs.go +++ b/test/helpers/fuzzerfuncs.go @@ -141,5 +141,9 @@ func InfraV1FuzzerFuncs() []interface{} { func(param *infrav1.SecurityGroupParam, c fuzz.Continue) { fuzzFilterParam(¶m.ID, ¶m.Filter, c) }, + + func(param *infrav1.ImageParam, c fuzz.Continue) { + fuzzFilterParam(¶m.ID, ¶m.Filter, c) + }, } }
FieldDescription
+id
string
(Optional) -

The name of the desired image. If specified, the combination of name and tags must return a single matching image or an error will be raised.

+

ID is the uuid of the image. ID will not be validated before use.

-tags
+filter
-[]string + +ImageFilter +
(Optional) -

The tags associated with the desired image. If specified, the combination of name and tags must return a single matching image or an error will be raised.

+

Filter describes a query for an image. If specified, the combination +of name and tags must return a single matching image or an error will +be raised.

image
- -ImageFilter + +ImageParam
image
- -ImageFilter + +ImageParam