diff --git a/api/v1alpha1/flavor_types.go b/api/v1alpha1/flavor_types.go
index 991133619..4ebbeccf9 100644
--- a/api/v1alpha1/flavor_types.go
+++ b/api/v1alpha1/flavor_types.go
@@ -24,6 +24,14 @@ type FlavorResourceSpec struct {
// +optional
Name *OpenStackName `json:"name,omitempty"`
+ // id will be the id of the created resource. If not specified, a random
+ // UUID will be generated by OpenStack.
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:MaxLength=255
+ // +kubebuilder:validation:Pattern=^[a-zA-Z0-9._-]([a-zA-Z0-9. _-]*[a-zA-Z0-9._-])?$
+ // +optional
+ ID string `json:"id,omitempty"` //nolint:kubeapilinter // intentionally allow raw ID
+
// description contains a free form description of the flavor.
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:MaxLength:=65535
diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go
index 2e346c070..46cb8f82b 100644
--- a/cmd/models-schema/zz_generated.openapi.go
+++ b/cmd/models-schema/zz_generated.openapi.go
@@ -2845,6 +2845,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceSpec(ref
Format: "",
},
},
+ "id": {
+ SchemaProps: spec.SchemaProps{
+ Description: "id will be the id of the created resource. If not specified, a random UUID will be generated by OpenStack.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
"description": {
SchemaProps: spec.SchemaProps{
Description: "description contains a free form description of the flavor.",
diff --git a/config/crd/bases/openstack.k-orc.cloud_flavors.yaml b/config/crd/bases/openstack.k-orc.cloud_flavors.yaml
index e2e9c08c6..d85dd72f1 100644
--- a/config/crd/bases/openstack.k-orc.cloud_flavors.yaml
+++ b/config/crd/bases/openstack.k-orc.cloud_flavors.yaml
@@ -189,6 +189,14 @@ spec:
format: int32
minimum: 0
type: integer
+ id:
+ description: |-
+ id will be the id of the created resource. If not specified, a random
+ UUID will be generated by OpenStack.
+ maxLength: 255
+ minLength: 1
+ pattern: ^[a-zA-Z0-9._-]([a-zA-Z0-9. _-]*[a-zA-Z0-9._-])?$
+ type: string
isPublic:
description: isPublic flags a flavor as being available to all
projects or not.
diff --git a/internal/controllers/flavor/actuator.go b/internal/controllers/flavor/actuator.go
index 16eb9c73b..f80146268 100644
--- a/internal/controllers/flavor/actuator.go
+++ b/internal/controllers/flavor/actuator.go
@@ -152,6 +152,7 @@ func (actuator flavorActuator) CreateResource(ctx context.Context, obj orcObject
IsPublic: resource.IsPublic,
Ephemeral: ptr.To(int(resource.Ephemeral)),
Description: ptr.Deref(resource.Description, ""),
+ ID: resource.ID,
}
osResource, err := actuator.osClient.CreateFlavor(ctx, createOpts)
diff --git a/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml b/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml
index 2074a3ece..dd94b805e 100644
--- a/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml
+++ b/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml
@@ -4,6 +4,7 @@ kind: Flavor
metadata:
name: flavor-create-full
status:
+ id: testId-123
resource:
name: flavor-create-full-override
description: Flavor from "create full" test
@@ -12,4 +13,4 @@ status:
disk: 20
swap: 2
isPublic: false
- ephemeral: 1
+ ephemeral: 1
\ No newline at end of file
diff --git a/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml b/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml
index f705c1af5..470180d72 100644
--- a/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml
+++ b/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml
@@ -17,3 +17,4 @@ spec:
swap: 2
isPublic: false
ephemeral: 1
+ id: testId-123
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go
index 335f722a6..4fc4161e0 100644
--- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go
@@ -26,6 +26,7 @@ import (
// with apply.
type FlavorResourceSpecApplyConfiguration struct {
Name *apiv1alpha1.OpenStackName `json:"name,omitempty"`
+ ID *string `json:"id,omitempty"`
Description *string `json:"description,omitempty"`
RAM *int32 `json:"ram,omitempty"`
Vcpus *int32 `json:"vcpus,omitempty"`
@@ -49,6 +50,14 @@ func (b *FlavorResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenSt
return b
}
+// WithID sets the ID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ID field is set to the value of the last call.
+func (b *FlavorResourceSpecApplyConfiguration) WithID(value string) *FlavorResourceSpecApplyConfiguration {
+ b.ID = &value
+ return b
+}
+
// WithDescription sets the Description field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Description field is set to the value of the last call.
diff --git a/pkg/clients/applyconfiguration/internal/internal.go b/pkg/clients/applyconfiguration/internal/internal.go
index 34d65a029..73b1cfa3c 100644
--- a/pkg/clients/applyconfiguration/internal/internal.go
+++ b/pkg/clients/applyconfiguration/internal/internal.go
@@ -678,6 +678,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: ephemeral
type:
scalar: numeric
+ - name: id
+ type:
+ scalar: string
- name: isPublic
type:
scalar: boolean
diff --git a/test/apivalidations/flavor_test.go b/test/apivalidations/flavor_test.go
index dd30e2f10..847af3a15 100644
--- a/test/apivalidations/flavor_test.go
+++ b/test/apivalidations/flavor_test.go
@@ -137,7 +137,6 @@ var _ = Describe("ORC Flavor API validations", func() {
maxString := strings.Repeat("a", 65536)
patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithRAM(1).WithVcpus(1).WithDescription(maxString))
Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.description: Too long")))
-
})
It("should reject import filter with value less than minimal", func(ctx context.Context) {
@@ -149,4 +148,20 @@ var _ = Describe("ORC Flavor API validations", func() {
WithFilter(applyconfigv1alpha1.FlavorFilter().WithRAM(0)))
Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.import.filter.ram in body should be greater than or equal to 1")))
})
+
+ It("should reject flavor IDs which are not according to the specified regex", func(ctx context.Context) {
+ flavor := flavorStub(namespace)
+ patch := baseFlavorPatch(flavor)
+ maxString := strings.Repeat("a", 256)
+ patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID(" test").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1))
+ Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id: Invalid value")))
+ patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID("test ").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1))
+ Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id: Invalid value")))
+ patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID(maxString).WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1))
+ Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id: Too long")))
+ patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID("").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1))
+ Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id in body should be at least 1 chars long")))
+ patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID("test.id -123_").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1))
+ Expect(applyObj(ctx, flavor, patch)).To(Succeed())
+ })
})
diff --git a/website/docs/crd-reference.md b/website/docs/crd-reference.md
index 3db974f26..84e90d35a 100644
--- a/website/docs/crd-reference.md
+++ b/website/docs/crd-reference.md
@@ -1016,6 +1016,7 @@ _Appears in:_
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
|
+| `id` _string_ | id will be the id of the created resource. If not specified, a random
UUID will be generated by OpenStack. | | MaxLength: 255
MinLength: 1
Pattern: `^[a-zA-Z0-9._-]([a-zA-Z0-9. _-]*[a-zA-Z0-9._-])?$`
Optional: \{\}
|
| `description` _string_ | description contains a free form description of the flavor. | | MaxLength: 65535
MinLength: 1
Optional: \{\}
|
| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | Minimum: 1
Required: \{\}
|
| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | Minimum: 1
Required: \{\}
|