diff --git a/api/v1alpha5/zz_generated.conversion.go b/api/v1alpha5/zz_generated.conversion.go index b10bd71be9..20646768bf 100644 --- a/api/v1alpha5/zz_generated.conversion.go +++ b/api/v1alpha5/zz_generated.conversion.go @@ -1074,7 +1074,7 @@ func autoConvert_v1alpha5_OpenStackMachineSpec_To_v1alpha8_OpenStackMachineSpec( } out.Trunk = in.Trunk out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) - out.ServerMetadata = *(*map[string]string)(unsafe.Pointer(&in.ServerMetadata)) + // WARNING: in.ServerMetadata requires manual conversion: inconvertible types (map[string]string vs []sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8.ServerMetadata) out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*v1alpha8.RootVolume)(unsafe.Pointer(in.RootVolume)) // WARNING: in.ServerGroupID requires manual conversion: does not exist in peer-type @@ -1113,7 +1113,7 @@ func autoConvert_v1alpha8_OpenStackMachineSpec_To_v1alpha5_OpenStackMachineSpec( } out.Trunk = in.Trunk out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) - out.ServerMetadata = *(*map[string]string)(unsafe.Pointer(&in.ServerMetadata)) + // WARNING: in.ServerMetadata requires manual conversion: inconvertible types ([]sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8.ServerMetadata vs map[string]string) out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*RootVolume)(unsafe.Pointer(in.RootVolume)) // WARNING: in.AdditionalBlockDevices requires manual conversion: does not exist in peer-type diff --git a/api/v1alpha6/conversion.go b/api/v1alpha6/conversion.go index c2170b980b..a01430e935 100644 --- a/api/v1alpha6/conversion.go +++ b/api/v1alpha6/conversion.go @@ -44,6 +44,24 @@ func restorev1alpha6MachineSpec(previous *OpenStackMachineSpec, dst *OpenStackMa // FloatingIP is removed from v1alpha7 with no replacement, so can't be // losslessly converted. Restore the previously stored value on down-conversion. dst.FloatingIP = previous.FloatingIP + + // Conversion to v1alpha8 truncates keys and values to 255 characters + for k, v := range previous.ServerMetadata { + kd := k + if len(k) > 255 { + kd = k[:255] + } + + vd := v + if len(v) > 255 { + vd = v[:255] + } + + if kd != k || vd != v { + delete(dst.ServerMetadata, kd) + dst.ServerMetadata[k] = v + } + } } func restorev1alpha6ClusterStatus(previous *OpenStackClusterStatus, dst *OpenStackClusterStatus) { @@ -425,6 +443,23 @@ func Convert_v1alpha6_OpenStackMachineSpec_To_v1alpha8_OpenStackMachineSpec(in * } out.Image = imageFilter + if len(in.ServerMetadata) > 0 { + serverMetadata := make([]infrav1.ServerMetadata, 0, len(in.ServerMetadata)) + for k, v := range in.ServerMetadata { + // Truncate key and value to 255 characters if required, as this + // was not validated prior to v1alpha8 + if len(k) > 255 { + k = k[:255] + } + if len(v) > 255 { + v = v[:255] + } + + serverMetadata = append(serverMetadata, infrav1.ServerMetadata{Key: k, Value: v}) + } + out.ServerMetadata = serverMetadata + } + return nil } @@ -776,6 +811,16 @@ func Convert_v1alpha8_OpenStackMachineSpec_To_v1alpha6_OpenStackMachineSpec(in * out.ImageUUID = in.Image.ID } + if len(in.ServerMetadata) > 0 { + serverMetadata := make(map[string]string, len(in.ServerMetadata)) + for i := range in.ServerMetadata { + key := in.ServerMetadata[i].Key + value := in.ServerMetadata[i].Value + serverMetadata[key] = value + } + out.ServerMetadata = serverMetadata + } + return nil } diff --git a/api/v1alpha6/conversion_test.go b/api/v1alpha6/conversion_test.go index 2099a1467d..5a2a9a6f6d 100644 --- a/api/v1alpha6/conversion_test.go +++ b/api/v1alpha6/conversion_test.go @@ -101,6 +101,37 @@ func TestFuzzyConversion(t *testing.T) { spec.Subnets = append(spec.Subnets, subnet) } }, + + func(spec *OpenStackMachineSpec, c fuzz.Continue) { + c.FuzzNoCustom(spec) + + // RandString() generates strings up to 20 + // characters long. To exercise truncation of + // long server metadata keys and values we need + // the possibility of strings > 255 chars. + genLongString := func() string { + var ret string + for len(ret) < 255 { + ret += c.RandString() + } + return ret + } + + // Existing server metadata keys will be short. Add a random number of long ones. + for c.RandBool() { + if spec.ServerMetadata == nil { + spec.ServerMetadata = map[string]string{} + } + spec.ServerMetadata[genLongString()] = c.RandString() + } + + // Randomly make some server metadata values long. + for k := range spec.ServerMetadata { + if c.RandBool() { + spec.ServerMetadata[k] = genLongString() + } + } + }, } } diff --git a/api/v1alpha6/zz_generated.conversion.go b/api/v1alpha6/zz_generated.conversion.go index 41761e8db2..0589be11fb 100644 --- a/api/v1alpha6/zz_generated.conversion.go +++ b/api/v1alpha6/zz_generated.conversion.go @@ -1097,7 +1097,7 @@ func autoConvert_v1alpha6_OpenStackMachineSpec_To_v1alpha8_OpenStackMachineSpec( } out.Trunk = in.Trunk out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) - out.ServerMetadata = *(*map[string]string)(unsafe.Pointer(&in.ServerMetadata)) + // WARNING: in.ServerMetadata requires manual conversion: inconvertible types (map[string]string vs []sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8.ServerMetadata) out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*v1alpha8.RootVolume)(unsafe.Pointer(in.RootVolume)) // WARNING: in.ServerGroupID requires manual conversion: does not exist in peer-type @@ -1136,7 +1136,7 @@ func autoConvert_v1alpha8_OpenStackMachineSpec_To_v1alpha6_OpenStackMachineSpec( } out.Trunk = in.Trunk out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) - out.ServerMetadata = *(*map[string]string)(unsafe.Pointer(&in.ServerMetadata)) + // WARNING: in.ServerMetadata requires manual conversion: inconvertible types ([]sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8.ServerMetadata vs map[string]string) out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*RootVolume)(unsafe.Pointer(in.RootVolume)) // WARNING: in.AdditionalBlockDevices requires manual conversion: does not exist in peer-type diff --git a/api/v1alpha7/conversion.go b/api/v1alpha7/conversion.go index e51c698e29..df31c7d81c 100644 --- a/api/v1alpha7/conversion.go +++ b/api/v1alpha7/conversion.go @@ -26,7 +26,20 @@ import ( var _ ctrlconversion.Convertible = &OpenStackCluster{} -var v1alpha7OpenStackClusterRestorer = conversion.RestorerFor[*OpenStackCluster]{} +func restorev1alpha7Bastion(previous **Bastion, dst **Bastion) { + if *previous != nil && *dst != nil { + restorev1alpha7MachineSpec(&(*previous).Instance, &(*dst).Instance) + } +} + +var v1alpha7OpenStackClusterRestorer = conversion.RestorerFor[*OpenStackCluster]{ + "bastion": conversion.HashedFieldRestorer( + func(c *OpenStackCluster) **Bastion { + return &c.Spec.Bastion + }, + restorev1alpha7Bastion, + ), +} var v1alpha8OpenStackClusterRestorer = conversion.RestorerFor[*infrav1.OpenStackCluster]{ "bastion": conversion.HashedFieldRestorer( @@ -67,6 +80,24 @@ var v1alpha8OpenStackClusterRestorer = conversion.RestorerFor[*infrav1.OpenStack func restorev1alpha7MachineSpec(previous *OpenStackMachineSpec, dst *OpenStackMachineSpec) { dst.FloatingIP = previous.FloatingIP + + // Conversion to v1alpha8 truncates keys and values to 255 characters + for k, v := range previous.ServerMetadata { + kd := k + if len(k) > 255 { + kd = k[:255] + } + + vd := v + if len(v) > 255 { + vd = v[:255] + } + + if kd != k || vd != v { + delete(dst.ServerMetadata, kd) + dst.ServerMetadata[k] = v + } + } } func restorev1alpha8MachineSpec(previous *infrav1.OpenStackMachineSpec, dst *infrav1.OpenStackMachineSpec) { @@ -139,12 +170,23 @@ func (r *OpenStackClusterList) ConvertFrom(srcRaw ctrlconversion.Hub) error { var _ ctrlconversion.Convertible = &OpenStackClusterTemplate{} +func restorev1alpha7ClusterTemplateSpec(previous *OpenStackClusterTemplateSpec, dst *OpenStackClusterTemplateSpec) { + restorev1alpha7Bastion(&previous.Template.Spec.Bastion, &dst.Template.Spec.Bastion) +} + func restorev1alpha8ClusterTemplateSpec(previous *infrav1.OpenStackClusterTemplateSpec, dst *infrav1.OpenStackClusterTemplateSpec) { restorev1alpha8Bastion(&previous.Template.Spec.Bastion, &dst.Template.Spec.Bastion) restorev1alpha8ClusterSpec(&previous.Template.Spec, &dst.Template.Spec) } -var v1alpha7OpenStackClusterTemplateRestorer = conversion.RestorerFor[*OpenStackClusterTemplate]{} +var v1alpha7OpenStackClusterTemplateRestorer = conversion.RestorerFor[*OpenStackClusterTemplate]{ + "spec": conversion.HashedFieldRestorer( + func(c *OpenStackClusterTemplate) *OpenStackClusterTemplateSpec { + return &c.Spec + }, + restorev1alpha7ClusterTemplateSpec, + ), +} var v1alpha8OpenStackClusterTemplateRestorer = conversion.RestorerFor[*infrav1.OpenStackClusterTemplate]{ "spec": conversion.HashedFieldRestorer( @@ -308,6 +350,16 @@ func Convert_v1alpha8_OpenStackMachineSpec_To_v1alpha7_OpenStackMachineSpec(in * out.ImageUUID = in.Image.ID } + if len(in.ServerMetadata) > 0 { + serverMetadata := make(map[string]string, len(in.ServerMetadata)) + for i := range in.ServerMetadata { + key := in.ServerMetadata[i].Key + value := in.ServerMetadata[i].Value + serverMetadata[key] = value + } + out.ServerMetadata = serverMetadata + } + return nil } @@ -332,6 +384,23 @@ func Convert_v1alpha7_OpenStackMachineSpec_To_v1alpha8_OpenStackMachineSpec(in * } out.Image = imageFilter + if len(in.ServerMetadata) > 0 { + serverMetadata := make([]infrav1.ServerMetadata, 0, len(in.ServerMetadata)) + for k, v := range in.ServerMetadata { + // Truncate key and value to 255 characters if required, as this + // was not validated prior to v1alpha8 + if len(k) > 255 { + k = k[:255] + } + if len(v) > 255 { + v = v[:255] + } + + serverMetadata = append(serverMetadata, infrav1.ServerMetadata{Key: k, Value: v}) + } + out.ServerMetadata = serverMetadata + } + return nil } diff --git a/api/v1alpha7/conversion_test.go b/api/v1alpha7/conversion_test.go index d26546a9d8..c57cc5d163 100644 --- a/api/v1alpha7/conversion_test.go +++ b/api/v1alpha7/conversion_test.go @@ -69,6 +69,37 @@ func TestFuzzyConversion(t *testing.T) { spec.Subnets = append(spec.Subnets, subnet) } }, + + func(spec *OpenStackMachineSpec, c fuzz.Continue) { + c.FuzzNoCustom(spec) + + // RandString() generates strings up to 20 + // characters long. To exercise truncation of + // long server metadata keys and values we need + // the possibility of strings > 255 chars. + genLongString := func() string { + var ret string + for len(ret) < 255 { + ret += c.RandString() + } + return ret + } + + // Existing server metadata keys will be short. Add a random number of long ones. + for c.RandBool() { + if spec.ServerMetadata == nil { + spec.ServerMetadata = map[string]string{} + } + spec.ServerMetadata[genLongString()] = c.RandString() + } + + // Randomly make some server metadata values long. + for k := range spec.ServerMetadata { + if c.RandBool() { + spec.ServerMetadata[k] = genLongString() + } + } + }, } } diff --git a/api/v1alpha7/zz_generated.conversion.go b/api/v1alpha7/zz_generated.conversion.go index 773d9892fd..42a17e16eb 100644 --- a/api/v1alpha7/zz_generated.conversion.go +++ b/api/v1alpha7/zz_generated.conversion.go @@ -1237,7 +1237,7 @@ func autoConvert_v1alpha7_OpenStackMachineSpec_To_v1alpha8_OpenStackMachineSpec( out.SecurityGroups = *(*[]v1alpha8.SecurityGroupFilter)(unsafe.Pointer(&in.SecurityGroups)) out.Trunk = in.Trunk out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) - out.ServerMetadata = *(*map[string]string)(unsafe.Pointer(&in.ServerMetadata)) + // WARNING: in.ServerMetadata requires manual conversion: inconvertible types (map[string]string vs []sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8.ServerMetadata) out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*v1alpha8.RootVolume)(unsafe.Pointer(in.RootVolume)) out.AdditionalBlockDevices = *(*[]v1alpha8.AdditionalBlockDevice)(unsafe.Pointer(&in.AdditionalBlockDevices)) @@ -1257,7 +1257,7 @@ func autoConvert_v1alpha8_OpenStackMachineSpec_To_v1alpha7_OpenStackMachineSpec( out.SecurityGroups = *(*[]SecurityGroupFilter)(unsafe.Pointer(&in.SecurityGroups)) out.Trunk = in.Trunk out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) - out.ServerMetadata = *(*map[string]string)(unsafe.Pointer(&in.ServerMetadata)) + // WARNING: in.ServerMetadata requires manual conversion: inconvertible types ([]sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8.ServerMetadata vs map[string]string) out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*RootVolume)(unsafe.Pointer(in.RootVolume)) out.AdditionalBlockDevices = *(*[]AdditionalBlockDevice)(unsafe.Pointer(&in.AdditionalBlockDevices)) diff --git a/api/v1alpha8/openstackmachine_types.go b/api/v1alpha8/openstackmachine_types.go index 61d29bad86..bc98e02a98 100644 --- a/api/v1alpha8/openstackmachine_types.go +++ b/api/v1alpha8/openstackmachine_types.go @@ -68,7 +68,9 @@ type OpenStackMachineSpec struct { Tags []string `json:"tags,omitempty"` // Metadata mapping. Allows you to create a map of key value pairs to add to the server instance. - ServerMetadata map[string]string `json:"serverMetadata,omitempty"` + // +listType=map + // +listMapKey=key + ServerMetadata []ServerMetadata `json:"serverMetadata,omitempty"` // Config Drive support ConfigDrive *bool `json:"configDrive,omitempty"` @@ -91,6 +93,16 @@ type OpenStackMachineSpec struct { IdentityRef *OpenStackIdentityReference `json:"identityRef,omitempty"` } +type ServerMetadata struct { + // Key is the server metadata key + // kubebuilder:validation:MaxLength:=255 + Key string `json:"key"` + + // Value is the server metadata value + // kubebuilder:validation:MaxLength:=255 + Value string `json:"value"` +} + // OpenStackMachineStatus defines the observed state of OpenStackMachine. type OpenStackMachineStatus struct { // Ready is true when the provider resource is ready. diff --git a/api/v1alpha8/zz_generated.deepcopy.go b/api/v1alpha8/zz_generated.deepcopy.go index eebb59993e..df370f8983 100644 --- a/api/v1alpha8/zz_generated.deepcopy.go +++ b/api/v1alpha8/zz_generated.deepcopy.go @@ -691,10 +691,8 @@ func (in *OpenStackMachineSpec) DeepCopyInto(out *OpenStackMachineSpec) { } if in.ServerMetadata != nil { in, out := &in.ServerMetadata, &out.ServerMetadata - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + *out = make([]ServerMetadata, len(*in)) + copy(*out, *in) } if in.ConfigDrive != nil { in, out := &in.ConfigDrive, &out.ConfigDrive @@ -1071,6 +1069,21 @@ func (in *ServerGroupFilter) DeepCopy() *ServerGroupFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerMetadata) DeepCopyInto(out *ServerMetadata) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerMetadata. +func (in *ServerMetadata) DeepCopy() *ServerMetadata { + if in == nil { + return nil + } + out := new(ServerMetadata) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Subnet) DeepCopyInto(out *Subnet) { *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 00b1ba6cc9..0b48da7dc2 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml @@ -5269,11 +5269,28 @@ spec: type: string type: object serverMetadata: - additionalProperties: - type: string description: Metadata mapping. Allows you to create a map of key value pairs to add to the server instance. - type: object + items: + properties: + key: + description: |- + Key is the server metadata key + kubebuilder:validation:MaxLength:=255 + type: string + value: + description: |- + Value is the server metadata value + kubebuilder:validation:MaxLength:=255 + type: string + required: + - key + - value + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map sshKeyName: description: The ssh key to inject in the instance type: string 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 cb56c31021..2cab684d19 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml @@ -2703,11 +2703,28 @@ spec: type: string type: object serverMetadata: - additionalProperties: - type: string description: Metadata mapping. Allows you to create a map of key value pairs to add to the server instance. - type: object + items: + properties: + key: + description: |- + Key is the server metadata key + kubebuilder:validation:MaxLength:=255 + type: string + value: + description: |- + Value is the server metadata value + kubebuilder:validation:MaxLength:=255 + type: string + required: + - key + - value + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map sshKeyName: description: The ssh key to inject in the instance type: string 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 340057cfef..e1a23d33be 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml @@ -2058,11 +2058,28 @@ spec: type: string type: object serverMetadata: - additionalProperties: - type: string description: Metadata mapping. Allows you to create a map of key value pairs to add to the server instance. - type: object + items: + properties: + key: + description: |- + Key is the server metadata key + kubebuilder:validation:MaxLength:=255 + type: string + value: + description: |- + Value is the server metadata value + kubebuilder:validation:MaxLength:=255 + type: string + required: + - key + - value + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map sshKeyName: description: The ssh key to inject in the instance 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 264c893e49..db63d9ade3 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml @@ -1738,11 +1738,28 @@ spec: type: string type: object serverMetadata: - additionalProperties: - type: string description: Metadata mapping. Allows you to create a map of key value pairs to add to the server instance. - type: object + items: + properties: + key: + description: |- + Key is the server metadata key + kubebuilder:validation:MaxLength:=255 + type: string + value: + description: |- + Value is the server metadata value + kubebuilder:validation:MaxLength:=255 + type: string + required: + - key + - value + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map sshKeyName: description: The ssh key to inject in the instance type: string diff --git a/controllers/openstackmachine_controller.go b/controllers/openstackmachine_controller.go index 56d195d8eb..5d6095177c 100644 --- a/controllers/openstackmachine_controller.go +++ b/controllers/openstackmachine_controller.go @@ -482,13 +482,20 @@ func (r *OpenStackMachineReconciler) getOrCreate(logger logr.Logger, cluster *cl } func machineToInstanceSpec(openStackCluster *infrav1.OpenStackCluster, machine *clusterv1.Machine, openStackMachine *infrav1.OpenStackMachine, userData string) *compute.InstanceSpec { + serverMetadata := make(map[string]string, len(openStackMachine.Spec.ServerMetadata)) + for i := range openStackMachine.Spec.ServerMetadata { + key := openStackMachine.Spec.ServerMetadata[i].Key + value := openStackMachine.Spec.ServerMetadata[i].Value + serverMetadata[key] = value + } + instanceSpec := compute.InstanceSpec{ Name: openStackMachine.Name, ImageID: openStackMachine.Status.ReferencedResources.ImageID, Flavor: openStackMachine.Spec.Flavor, SSHKeyName: openStackMachine.Spec.SSHKeyName, UserData: userData, - Metadata: openStackMachine.Spec.ServerMetadata, + Metadata: serverMetadata, ConfigDrive: openStackMachine.Spec.ConfigDrive != nil && *openStackMachine.Spec.ConfigDrive, RootVolume: openStackMachine.Spec.RootVolume, AdditionalBlockDevices: openStackMachine.Spec.AdditionalBlockDevices, diff --git a/controllers/openstackmachine_controller_test.go b/controllers/openstackmachine_controller_test.go index bc0c3b96c5..b204111708 100644 --- a/controllers/openstackmachine_controller_test.go +++ b/controllers/openstackmachine_controller_test.go @@ -86,8 +86,8 @@ func getDefaultOpenStackMachine() *infrav1.OpenStackMachine { Image: infrav1.ImageFilter{ID: imageUUID}, SSHKeyName: sshKeyName, Tags: []string{"test-tag"}, - ServerMetadata: map[string]string{ - "test-metadata": "test-value", + ServerMetadata: []infrav1.ServerMetadata{ + {Key: "test-metadata", Value: "test-value"}, }, ConfigDrive: pointer.Bool(true), SecurityGroups: []infrav1.SecurityGroupFilter{},