From aef6e2a95e3b1bf89beb22bce5cc631f4979e80c Mon Sep 17 00:00:00 2001 From: Matthew Booth Date: Tue, 22 Oct 2024 10:45:31 +0100 Subject: [PATCH 1/3] ORC: Move main.go under cmd/manager --- orc/cmd/{ => manager}/main.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename orc/cmd/{ => manager}/main.go (100%) diff --git a/orc/cmd/main.go b/orc/cmd/manager/main.go similarity index 100% rename from orc/cmd/main.go rename to orc/cmd/manager/main.go From ffa8010934163ee71227eac65d6d0f2f47431cc8 Mon Sep 17 00:00:00 2001 From: Matthew Booth Date: Tue, 22 Oct 2024 10:53:10 +0100 Subject: [PATCH 2/3] ORC: Fix bootstrapping of applyconfigurations codegen depends on interfaces generated by controller-gen. However, controller-gen will fail during code inspection if the applyconfiguration package does not already exist because it is imported by the code being inspected. This is a bootstrapping problem. We ensure the applyconfiguration package exists by adding a doc.go. --- .../applyconfiguration/api/v1alpha1/doc.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 orc/pkg/clients/applyconfiguration/api/v1alpha1/doc.go diff --git a/orc/pkg/clients/applyconfiguration/api/v1alpha1/doc.go b/orc/pkg/clients/applyconfiguration/api/v1alpha1/doc.go new file mode 100644 index 0000000000..baa165c4de --- /dev/null +++ b/orc/pkg/clients/applyconfiguration/api/v1alpha1/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2024 The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 From 5d4c506054363d78616b238d5cf868b7ca30fe4a Mon Sep 17 00:00:00 2001 From: Matthew Booth Date: Tue, 22 Oct 2024 11:01:49 +0100 Subject: [PATCH 3/3] ORC: Generate common parts of resource API --- orc/Makefile | 6 +- orc/api/v1alpha1/image_types.go | 139 +-------------- orc/api/v1alpha1/zz_generated.deepcopy.go | 22 ++- .../v1alpha1/zz_generated.image-resource.go | 158 +++++++++++++++++ orc/cmd/resource-generator/data/api.template | 161 ++++++++++++++++++ orc/cmd/resource-generator/main.go | 90 ++++++++++ .../bases/openstack.k-orc.cloud_images.yaml | 38 ++--- .../codegen/openapi/zz_generated.openapi.go | 44 +++-- .../api/v1alpha1/imagestatus.go | 8 +- .../api/v1alpha1/imagestatusextra.go | 39 +++++ orc/pkg/clients/applyconfiguration/utils.go | 2 + 11 files changed, 530 insertions(+), 177 deletions(-) create mode 100644 orc/api/v1alpha1/zz_generated.image-resource.go create mode 100644 orc/cmd/resource-generator/data/api.template create mode 100644 orc/cmd/resource-generator/main.go create mode 100644 orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go diff --git a/orc/Makefile b/orc/Makefile index 4c9221b96a..5cb4aa7f81 100644 --- a/orc/Makefile +++ b/orc/Makefile @@ -53,7 +53,11 @@ modules: cd hack/codegen; go work sync; go mod tidy .PHONY: generate -generate: modules manifests generate-controller-gen generate-codegen generate-go +generate: generate-resources generate-controller-gen generate-codegen generate-go modules manifests + +.PHONY: generate-resources +generate-resources: + go run ./cmd/resource-generator .PHONY: generate-controller-gen generate-controller-gen: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. diff --git a/orc/api/v1alpha1/image_types.go b/orc/api/v1alpha1/image_types.go index 85e5a29601..e570296137 100644 --- a/orc/api/v1alpha1/image_types.go +++ b/orc/api/v1alpha1/image_types.go @@ -16,10 +16,6 @@ limitations under the License. package v1alpha1 -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - // GlanceTag is the name of the go field tag in properties structs used to specify the Glance property name. const GlanceTag = "glance" @@ -318,65 +314,6 @@ type ImageFilter struct { Name *string `json:"name,omitempty"` } -// ImageImport specifies an existing image which will be imported instead of -// creating a new image -// +kubebuilder:validation:MinProperties:=1 -// +kubebuilder:validation:MaxProperties:=1 -type ImageImport struct { - // ID contains the unique identifier of an existing Glance image. Note that - // when specifying an image import by ID, the image MUST already exist. The - // Image will enter an error state if the image does not exist. - // +optional - // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` - - // Filter contains an image query which is expected to return a single - // result. The controller will continue to retry if filter returns no - // results. If filter returns multiple results the controller will set an - // error state and will not continue to retry. - // +optional - Filter *ImageFilter `json:"filter,omitempty"` -} - -// ImageSpec defines the desired state of an Image. -// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" -// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" -// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" -// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" -// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" -// +kubebuilder:validation:XValidation:rule="!has(self.__import__) ? has(self.resource.content) : true",message="resource content must be specified when not importing" -type ImageSpec struct { - // Import refers to an existing image which will be imported instead of - // creating a new image. - // +optional - Import *ImageImport `json:"import,omitempty"` - - // Resource specifies the desired state of the Glance image. - // - // Resource may not be specified if the management policy is `unmanaged`. - // - // Resource must be specified when the management policy is `managed`. - // +optional - Resource *ImageResourceSpec `json:"resource,omitempty"` - - // ManagementPolicy defines how ORC will treat the object. Valid values are - // `managed`: ORC will create, update, and delete the resource; `unmanaged`: - // ORC will import an existing image, and will not apply updates to it or - // delete it. - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" - // +kubebuilder:default:=managed - // +optional - ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` - - // ManagedOptions specifies options which may be applied to managed objects. - // +optional - ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` - - // CloudCredentialsRef points to a secret containing OpenStack credentials - // +kubebuilder:validation:Required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` -} - // ImageResourceStatus represents the observed state of a Glance image type ImageResourceStatus struct { // Status is the image status as reported by Glance @@ -400,82 +337,8 @@ type ImageResourceStatus struct { VirtualSizeB *int64 `json:"virtualSizeB,omitempty"` } -// ImageStatus defines the observed state of an Image. -type ImageStatus struct { - // Conditions represents the observed status of the object. - // Known .status.conditions.type are: "Available", "Progressing" - // - // Available represents the availability of the Glance image. If it is - // true then the image is ready for use in Glance, and its hash has been - // verified. - // - // Progressing indicates the state of the Glance image does not currently - // reflect the desired state, but that reconciliation is progressing. - // Progressing will be False either because the desired state has been - // achieved, or some terminal error prevents it from being achieved and the - // controller is no longer attempting to reconcile. - // - // +patchMergeKey=type - // +patchStrategy=merge - // +listType=map - // +listMapKey=type - Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` - - // ID is the unique identifier of the Glance image - // +optional - ID *string `json:"id,omitempty"` - - // Resource contains the observed state of the Glance image - // +optional - Resource *ImageResourceStatus `json:"resource,omitempty"` - +type ImageStatusExtra struct { // DownloadAttempts is the number of times the controller has attempted to download the image contents // +optional DownloadAttempts *int `json:"downloadAttempts,omitempty"` } - -var _ ObjectWithConditions = &Image{} - -func (i *Image) GetConditions() []metav1.Condition { - return i.Status.Conditions -} - -// +genclient -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Glance image ID" -// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of image" -// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Available')].message",description="Message describing current availability status" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation" - -// Image is the Schema for the ORC images API. -type Image struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ImageSpec `json:"spec,omitempty"` - Status ImageStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// ImageList contains a list of Image. -type ImageList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Image `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Image{}, &ImageList{}) -} - -func (i *Image) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { - if i == nil { - return nil, nil - } - - return &i.Namespace, &i.Spec.CloudCredentialsRef -} - -var _ CloudCredentialsRefProvider = &Image{} diff --git a/orc/api/v1alpha1/zz_generated.deepcopy.go b/orc/api/v1alpha1/zz_generated.deepcopy.go index 8daca744aa..3ae986c9c0 100644 --- a/orc/api/v1alpha1/zz_generated.deepcopy.go +++ b/orc/api/v1alpha1/zz_generated.deepcopy.go @@ -420,6 +420,22 @@ func (in *ImageStatus) DeepCopyInto(out *ImageStatus) { *out = new(ImageResourceStatus) (*in).DeepCopyInto(*out) } + in.ImageStatusExtra.DeepCopyInto(&out.ImageStatusExtra) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatus. +func (in *ImageStatus) DeepCopy() *ImageStatus { + if in == nil { + return nil + } + out := new(ImageStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageStatusExtra) DeepCopyInto(out *ImageStatusExtra) { + *out = *in if in.DownloadAttempts != nil { in, out := &in.DownloadAttempts, &out.DownloadAttempts *out = new(int) @@ -427,12 +443,12 @@ func (in *ImageStatus) DeepCopyInto(out *ImageStatus) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatus. -func (in *ImageStatus) DeepCopy() *ImageStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatusExtra. +func (in *ImageStatusExtra) DeepCopy() *ImageStatusExtra { if in == nil { return nil } - out := new(ImageStatus) + out := new(ImageStatusExtra) in.DeepCopyInto(out) return out } diff --git a/orc/api/v1alpha1/zz_generated.image-resource.go b/orc/api/v1alpha1/zz_generated.image-resource.go new file mode 100644 index 0000000000..c607e7a153 --- /dev/null +++ b/orc/api/v1alpha1/zz_generated.image-resource.go @@ -0,0 +1,158 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ImageImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type ImageImport struct { + // ID contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +optional + // +kubebuilder:validation:Format:=uuid + ID *string `json:"id,omitempty"` + + // Filter contains an resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *ImageFilter `json:"filter,omitempty"` +} + +// ImageSpec defines the desired state of a ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +// +kubebuilder:validation:XValidation:rule="!has(self.__import__) ? has(self.resource.content) : true",message="resource content must be specified when not importing" +type ImageSpec struct { + // Import refers to an existing ORC object which will be imported instead of + // creating a new resource. + // +optional + Import *ImageImport `json:"import,omitempty"` + + // Resource specifies the desired state of the resource. + // + // Resource may not be specified if the management policy is `unmanaged`. + // + // Resource must be specified when the management policy is `managed`. + // +optional + Resource *ImageResourceSpec `json:"resource,omitempty"` + + // ManagementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // ManagedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // CloudCredentialsRef points to a secret containing OpenStack credentials + // +kubebuilder:validation:Required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` +} + +// ImageStatus defines the observed state of an ORC resource. +type ImageStatus struct { + // Conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates the state of the OpenStack resource not currently + // reflect the desired state, but that reconciliation is progressing. + // Progressing will be False either because the desired state has been + // achieved, or some terminal error prevents it from being achieved and the + // controller is no longer attempting to reconcile. + // + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // ID is the unique identifier of the OpenStack resource. + // +optional + ID *string `json:"id,omitempty"` + + // Resource contains the observed state of the OpenStack resource. + // +optional + Resource *ImageResourceStatus `json:"resource,omitempty"` + + ImageStatusExtra `json:",inline"` +} + +var _ ObjectWithConditions = &Image{} + +func (i *Image) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Available')].message",description="Message describing current availability status" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation" + +// Image is the Schema for an ORC resource. +type Image struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ImageSpec `json:"spec,omitempty"` + Status ImageStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ImageList contains a list of Image. +type ImageList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Image `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Image{}, &ImageList{}) +} + +func (i *Image) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &Image{} diff --git a/orc/cmd/resource-generator/data/api.template b/orc/cmd/resource-generator/data/api.template new file mode 100644 index 0000000000..8cb39635ef --- /dev/null +++ b/orc/cmd/resource-generator/data/api.template @@ -0,0 +1,161 @@ +/* +Copyright {{ .Year }} The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package {{ .APIVersion }} + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// {{ .Name }}Import specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type {{ .Name }}Import struct { + // ID contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +optional + // +kubebuilder:validation:Format:=uuid + ID *string `json:"id,omitempty"` + + // Filter contains an resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *{{ .Name }}Filter `json:"filter,omitempty"` +} + +// {{ .Name }}Spec defines the desired state of a ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +{{- range .SpecExtraValidations }} +// +kubebuilder:validation:XValidation:rule="{{ .Rule }}",message="{{ .Message }}" +{{ end -}} +type {{ .Name }}Spec struct { + // Import refers to an existing ORC object which will be imported instead of + // creating a new resource. + // +optional + Import *{{ .Name }}Import `json:"import,omitempty"` + + // Resource specifies the desired state of the resource. + // + // Resource may not be specified if the management policy is `unmanaged`. + // + // Resource must be specified when the management policy is `managed`. + // +optional + Resource *{{ .Name }}ResourceSpec `json:"resource,omitempty"` + + // ManagementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // ManagedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // CloudCredentialsRef points to a secret containing OpenStack credentials + // +kubebuilder:validation:Required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` +} + +// {{ .Name }}Status defines the observed state of an ORC resource. +type {{ .Name }}Status struct { + // Conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates the state of the OpenStack resource not currently + // reflect the desired state, but that reconciliation is progressing. + // Progressing will be False either because the desired state has been + // achieved, or some terminal error prevents it from being achieved and the + // controller is no longer attempting to reconcile. + // + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // ID is the unique identifier of the OpenStack resource. + // +optional + ID *string `json:"id,omitempty"` + + // Resource contains the observed state of the OpenStack resource. + // +optional + Resource *{{ .Name }}ResourceStatus `json:"resource,omitempty"` +{{- if .StatusExtraType }} + + {{ .StatusExtraType }} `json:",inline"` +{{- end }} +} + +var _ ObjectWithConditions = &{{ .Name }}{} + +func (i *{{ .Name }}) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Available')].message",description="Message describing current availability status" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation" + +// {{ .Name }} is the Schema for an ORC resource. +type {{ .Name }} struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec {{ .Name }}Spec `json:"spec,omitempty"` + Status {{ .Name }}Status `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// {{ .Name }}List contains a list of {{ .Name }}. +type {{ .Name }}List struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []{{ .Name }} `json:"items"` +} + +func init() { + SchemeBuilder.Register(&{{ .Name }}{}, &{{ .Name }}List{}) +} + +func (i *{{ .Name }}) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &{{ .Name }}{} diff --git a/orc/cmd/resource-generator/main.go b/orc/cmd/resource-generator/main.go new file mode 100644 index 0000000000..d628a63e7b --- /dev/null +++ b/orc/cmd/resource-generator/main.go @@ -0,0 +1,90 @@ +package main + +import ( + _ "embed" + "os" + "path/filepath" + "strings" + "text/template" +) + +const ( + defaultYear = "2024" + defaultAPIVersion = "v1alpha1" +) + +//go:embed data/api.template +var api_template string + +type specExtraValidation struct { + Rule string + Message string +} + +type templateFields struct { + APIVersion string + Year string + Name string + StatusExtraType string + SpecExtraValidations []specExtraValidation +} + +var allResources []templateFields = []templateFields{ + { + Name: "Image", + APIVersion: "v1alpha1", + SpecExtraValidations: []specExtraValidation{ + { + Rule: "!has(self.__import__) ? has(self.resource.content) : true", + Message: "resource content must be specified when not importing", + }, + }, + StatusExtraType: "ImageStatusExtra", + }, +} + +func main() { + apiTemplate := template.Must(template.New("api").Parse(api_template)) + + for i := range allResources { + resource := &allResources[i] + + if resource.Year == "" { + resource.Year = defaultYear + } + + if resource.APIVersion == "" { + resource.APIVersion = defaultAPIVersion + } + + resourceLower := strings.ToLower(resource.Name) + + apiPath := filepath.Join("api", resource.APIVersion, "zz_generated."+resourceLower+"-resource.go") + apiFile, err := os.Create(apiPath) + if err != nil { + panic(err) + } + defer func() { + err := apiFile.Close() + if err != nil { + panic(err) + } + }() + + err = writeAutogeneratedHeader(apiFile) + if err != nil { + panic(err) + } + + err = apiTemplate.Execute(apiFile, resource) + if err != nil { + panic(err) + } + } +} + +func writeAutogeneratedHeader(f *os.File) error { + _, err := f.WriteString("// Code generated by resource-generator. DO NOT EDIT.\n") + + return err +} diff --git a/orc/config/crd/bases/openstack.k-orc.cloud_images.yaml b/orc/config/crd/bases/openstack.k-orc.cloud_images.yaml index 07c33154b5..ff5181c34e 100644 --- a/orc/config/crd/bases/openstack.k-orc.cloud_images.yaml +++ b/orc/config/crd/bases/openstack.k-orc.cloud_images.yaml @@ -15,11 +15,11 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Glance image ID + - description: Resource ID jsonPath: .status.id name: ID type: string - - description: Availability status of image + - description: Availability status of resource jsonPath: .status.conditions[?(@.type=='Available')].status name: Available type: string @@ -34,7 +34,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Image is the Schema for the ORC images API. + description: Image is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -54,7 +54,7 @@ spec: metadata: type: object spec: - description: ImageSpec defines the desired state of an Image. + description: ImageSpec defines the desired state of a ORC object. properties: cloudCredentialsRef: description: CloudCredentialsRef points to a secret containing OpenStack @@ -80,14 +80,14 @@ spec: type: object import: description: |- - Import refers to an existing image which will be imported instead of - creating a new image. + Import refers to an existing ORC object which will be imported instead of + creating a new resource. maxProperties: 1 minProperties: 1 properties: filter: description: |- - Filter contains an image query which is expected to return a single + Filter contains an resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry. @@ -101,9 +101,9 @@ spec: type: object id: description: |- - ID contains the unique identifier of an existing Glance image. Note that - when specifying an image import by ID, the image MUST already exist. The - Image will enter an error state if the image does not exist. + ID contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. format: uuid type: string type: object @@ -128,7 +128,7 @@ spec: description: |- ManagementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: - ORC will import an existing image, and will not apply updates to it or + ORC will import an existing resource, and will not apply updates to it or delete it. enum: - managed @@ -139,7 +139,7 @@ spec: rule: self == oldSelf resource: description: |- - Resource specifies the desired state of the Glance image. + Resource specifies the desired state of the resource. Resource may not be specified if the management policy is `unmanaged`. @@ -454,18 +454,17 @@ spec: - message: resource content must be specified when not importing rule: '!has(self.__import__) ? has(self.resource.content) : true' status: - description: ImageStatus defines the observed state of an Image. + description: ImageStatus defines the observed state of an ORC resource. properties: conditions: description: |- Conditions represents the observed status of the object. Known .status.conditions.type are: "Available", "Progressing" - Available represents the availability of the Glance image. If it is - true then the image is ready for use in Glance, and its hash has been - verified. + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. - Progressing indicates the state of the Glance image does not currently + Progressing indicates the state of the OpenStack resource not currently reflect the desired state, but that reconciliation is progressing. Progressing will be False either because the desired state has been achieved, or some terminal error prevents it from being achieved and the @@ -533,10 +532,11 @@ spec: has attempted to download the image contents type: integer id: - description: ID is the unique identifier of the Glance image + description: ID is the unique identifier of the OpenStack resource. type: string resource: - description: Resource contains the observed state of the Glance image + description: Resource contains the observed state of the OpenStack + resource. properties: hash: description: |- diff --git a/orc/hack/codegen/openapi/zz_generated.openapi.go b/orc/hack/codegen/openapi/zz_generated.openapi.go index 74e09ac2ca..1b0067714d 100644 --- a/orc/hack/codegen/openapi/zz_generated.openapi.go +++ b/orc/hack/codegen/openapi/zz_generated.openapi.go @@ -43,6 +43,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageResourceStatus": schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageResourceStatus(ref), "github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageSpec": schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageSpec(ref), "github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageStatus": schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatus(ref), + "github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageStatusExtra": schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatusExtra(ref), "github.com/k-orc/openstack-resource-controller/api/v1alpha1.ManagedOptions": schema_k_orc_openstack_resource_controller_api_v1alpha1_ManagedOptions(ref), "k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource": schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref), "k8s.io/api/core/v1.Affinity": schema_k8sio_api_core_v1_Affinity(ref), @@ -357,7 +358,7 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_Image(ref common.Re return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Image is the Schema for the ORC images API.", + Description: "Image is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -525,19 +526,19 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageImport(ref com return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageImport specifies an existing image which will be imported instead of creating a new image", + Description: "ImageImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ "id": { SchemaProps: spec.SchemaProps{ - Description: "ID contains the unique identifier of an existing Glance image. Note that when specifying an image import by ID, the image MUST already exist. The Image will enter an error state if the image does not exist.", + Description: "ID contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, "filter": { SchemaProps: spec.SchemaProps{ - Description: "Filter contains an image query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Description: "Filter contains an resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", Ref: ref("github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageFilter"), }, }, @@ -821,24 +822,24 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageSpec(ref commo return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageSpec defines the desired state of an Image.", + Description: "ImageSpec defines the desired state of a ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ - Description: "Import refers to an existing image which will be imported instead of creating a new image.", + Description: "Import refers to an existing ORC object which will be imported instead of creating a new resource.", Ref: ref("github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ - Description: "Resource specifies the desired state of the Glance image.\n\nResource may not be specified if the management policy is `unmanaged`.\n\nResource must be specified when the management policy is `managed`.", + Description: "Resource specifies the desired state of the resource.\n\nResource may not be specified if the management policy is `unmanaged`.\n\nResource must be specified when the management policy is `managed`.", Ref: ref("github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageResourceSpec"), }, }, "managementPolicy": { SchemaProps: spec.SchemaProps{ - Description: "ManagementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing image, and will not apply updates to it or delete it.", + Description: "ManagementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", Type: []string{"string"}, Format: "", }, @@ -869,7 +870,7 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatus(ref com return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageStatus defines the observed state of an Image.", + Description: "ImageStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -884,7 +885,7 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatus(ref com }, }, SchemaProps: spec.SchemaProps{ - Description: "Conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the Glance image. If it is true then the image is ready for use in Glance, and its hash has been verified.\n\nProgressing indicates the state of the Glance image does not currently reflect the desired state, but that reconciliation is progressing. Progressing will be False either because the desired state has been achieved, or some terminal error prevents it from being achieved and the controller is no longer attempting to reconcile.", + Description: "Conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates the state of the OpenStack resource not currently reflect the desired state, but that reconciliation is progressing. Progressing will be False either because the desired state has been achieved, or some terminal error prevents it from being achieved and the controller is no longer attempting to reconcile.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -898,14 +899,14 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatus(ref com }, "id": { SchemaProps: spec.SchemaProps{ - Description: "ID is the unique identifier of the Glance image", + Description: "ID is the unique identifier of the OpenStack resource.", Type: []string{"string"}, Format: "", }, }, "resource": { SchemaProps: spec.SchemaProps{ - Description: "Resource contains the observed state of the Glance image", + Description: "Resource contains the observed state of the OpenStack resource.", Ref: ref("github.com/k-orc/openstack-resource-controller/api/v1alpha1.ImageResourceStatus"), }, }, @@ -924,6 +925,25 @@ func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatus(ref com } } +func schema_k_orc_openstack_resource_controller_api_v1alpha1_ImageStatusExtra(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "downloadAttempts": { + SchemaProps: spec.SchemaProps{ + Description: "DownloadAttempts is the number of times the controller has attempted to download the image contents", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + func schema_k_orc_openstack_resource_controller_api_v1alpha1_ManagedOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go b/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go index cfaf3f8d28..520e06d0b9 100644 --- a/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go +++ b/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go @@ -25,10 +25,10 @@ import ( // ImageStatusApplyConfiguration represents an declarative configuration of the ImageStatus type for use // with apply. type ImageStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *ImageResourceStatusApplyConfiguration `json:"resource,omitempty"` - DownloadAttempts *int `json:"downloadAttempts,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ImageResourceStatusApplyConfiguration `json:"resource,omitempty"` + ImageStatusExtraApplyConfiguration `json:",inline"` } // ImageStatusApplyConfiguration constructs an declarative configuration of the ImageStatus type for use with diff --git a/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go b/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go new file mode 100644 index 0000000000..eebba38c8d --- /dev/null +++ b/orc/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go @@ -0,0 +1,39 @@ +/* +Copyright 2024 The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ImageStatusExtraApplyConfiguration represents an declarative configuration of the ImageStatusExtra type for use +// with apply. +type ImageStatusExtraApplyConfiguration struct { + DownloadAttempts *int `json:"downloadAttempts,omitempty"` +} + +// ImageStatusExtraApplyConfiguration constructs an declarative configuration of the ImageStatusExtra type for use with +// apply. +func ImageStatusExtra() *ImageStatusExtraApplyConfiguration { + return &ImageStatusExtraApplyConfiguration{} +} + +// WithDownloadAttempts sets the DownloadAttempts 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 DownloadAttempts field is set to the value of the last call. +func (b *ImageStatusExtraApplyConfiguration) WithDownloadAttempts(value int) *ImageStatusExtraApplyConfiguration { + b.DownloadAttempts = &value + return b +} diff --git a/orc/pkg/clients/applyconfiguration/utils.go b/orc/pkg/clients/applyconfiguration/utils.go index b173fa0e02..982d4c9431 100644 --- a/orc/pkg/clients/applyconfiguration/utils.go +++ b/orc/pkg/clients/applyconfiguration/utils.go @@ -55,6 +55,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.ImageSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ImageStatus"): return &apiv1alpha1.ImageStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ImageStatusExtra"): + return &apiv1alpha1.ImageStatusExtraApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ManagedOptions"): return &apiv1alpha1.ManagedOptionsApplyConfiguration{}