From 0e0a42caa3c5b5a8218af5f76fb8379a2317ad44 Mon Sep 17 00:00:00 2001 From: Ekaterina Kazakova Date: Wed, 11 Sep 2024 14:39:00 +0400 Subject: [PATCH 1/3] Add TemplateManagement CRD --- api/v1alpha1/templatemanagement_types.go | 95 +++++++ api/v1alpha1/zz_generated.deepcopy.go | 150 +++++++++++ .../hmc.mirantis.com_templatemanagements.yaml | 244 ++++++++++++++++++ 3 files changed, 489 insertions(+) create mode 100644 api/v1alpha1/templatemanagement_types.go create mode 100644 templates/provider/hmc/templates/crds/hmc.mirantis.com_templatemanagements.yaml diff --git a/api/v1alpha1/templatemanagement_types.go b/api/v1alpha1/templatemanagement_types.go new file mode 100644 index 000000000..d779ade88 --- /dev/null +++ b/api/v1alpha1/templatemanagement_types.go @@ -0,0 +1,95 @@ +// Copyright 2024 +// +// 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" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName=tm,scope=Cluster + +// TemplateManagement is the Schema for the template management API +type TemplateManagement struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TemplateManagementSpec `json:"spec,omitempty"` + Status TemplateManagementStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// TemplateManagementList contains a list of TemplateManagement +type TemplateManagementList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TemplateManagement `json:"items"` +} + +// TemplateManagementSpec defines the desired state of TemplateManagement +type TemplateManagementSpec struct { + // AccessRules is the list of access rules. Each AccessRule enforces + // Templates distribution to the TargetNamespaces. + AccessRules []AccessRule `json:"accessRules,omitempty"` +} + +// AccessRule is the definition of the TemplateManagement access rule. Each AccessRule enforces +// Templates distribution to the TargetNamespaces +type AccessRule struct { + // TargetNamespaces defines the namespaces where selected Templates will be distributed. + // Templates will be distributed to all namespaces if unset. + // +optional + TargetNamespaces TargetNamespaces `json:"targetNamespaces,omitempty"` + // ClusterTemplateChains lists the names of ClusterTemplateChains whose ClusterTemplates + // will be distributed to all namespaces specified in TargetNamespaces. + // +optional + ClusterTemplateChains []string `json:"clusterTemplateChains,omitempty"` + // ServiceTemplateChains lists the names of ServiceTemplateChains whose ServiceTemplates + // will be distributed to all namespaces specified in TargetNamespaces. + // +optional + ServiceTemplateChains []string `json:"serviceTemplateChains,omitempty"` +} + +// +kubebuilder:validation:XValidation:rule="((has(self.stringSelector) ? 1 : 0) + (has(self.selector) ? 1 : 0) + (has(self.list) ? 1 : 0)) <= 1", message="only one of spec.targetNamespaces.selector or spec.targetNamespaces.stringSelector spec.targetNamespaces.list can be specified" + +// TargetNamespaces defines the list of namespaces or the label selector to select namespaces +type TargetNamespaces struct { + // StringSelector is a label query to select namespaces. + // Mutually exclusive with Selector. + // +optional + StringSelector string `json:"stringSelector,omitempty"` + // Selector is a structured label query to select namespaces. + // Mutually exclusive with StringSelector. + // +optional + Selector metav1.LabelSelector `json:"selector,omitempty"` + // List is the list of namespaces to select. + // +optional + List []string `json:"list,omitempty"` +} + +// TemplateManagementStatus defines the observed state of TemplateManagement +type TemplateManagementStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + // Current reflects the applied access rules configuration. + Current []AccessRule `json:"current,omitempty"` +} + +func init() { + SchemeBuilder.Register(&TemplateManagement{}, &TemplateManagementList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ff5d2092a..369582bc7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -25,6 +25,32 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AccessRule) DeepCopyInto(out *AccessRule) { + *out = *in + in.TargetNamespaces.DeepCopyInto(&out.TargetNamespaces) + if in.ClusterTemplateChains != nil { + in, out := &in.ClusterTemplateChains, &out.ClusterTemplateChains + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ServiceTemplateChains != nil { + in, out := &in.ServiceTemplateChains, &out.ServiceTemplateChains + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessRule. +func (in *AccessRule) DeepCopy() *AccessRule { + if in == nil { + return nil + } + out := new(AccessRule) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterTemplate) DeepCopyInto(out *ClusterTemplate) { *out = *in @@ -610,6 +636,130 @@ func (in *ServiceTemplateStatus) DeepCopy() *ServiceTemplateStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetNamespaces) DeepCopyInto(out *TargetNamespaces) { + *out = *in + in.Selector.DeepCopyInto(&out.Selector) + if in.List != nil { + in, out := &in.List, &out.List + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetNamespaces. +func (in *TargetNamespaces) DeepCopy() *TargetNamespaces { + if in == nil { + return nil + } + out := new(TargetNamespaces) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateManagement) DeepCopyInto(out *TemplateManagement) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateManagement. +func (in *TemplateManagement) DeepCopy() *TemplateManagement { + if in == nil { + return nil + } + out := new(TemplateManagement) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TemplateManagement) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateManagementList) DeepCopyInto(out *TemplateManagementList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TemplateManagement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateManagementList. +func (in *TemplateManagementList) DeepCopy() *TemplateManagementList { + if in == nil { + return nil + } + out := new(TemplateManagementList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TemplateManagementList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateManagementSpec) DeepCopyInto(out *TemplateManagementSpec) { + *out = *in + if in.AccessRules != nil { + in, out := &in.AccessRules, &out.AccessRules + *out = make([]AccessRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateManagementSpec. +func (in *TemplateManagementSpec) DeepCopy() *TemplateManagementSpec { + if in == nil { + return nil + } + out := new(TemplateManagementSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateManagementStatus) DeepCopyInto(out *TemplateManagementStatus) { + *out = *in + if in.Current != nil { + in, out := &in.Current, &out.Current + *out = make([]AccessRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateManagementStatus. +func (in *TemplateManagementStatus) DeepCopy() *TemplateManagementStatus { + if in == nil { + return nil + } + out := new(TemplateManagementStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TemplateSpecMixin) DeepCopyInto(out *TemplateSpecMixin) { *out = *in diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_templatemanagements.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_templatemanagements.yaml new file mode 100644 index 000000000..da5ef175f --- /dev/null +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_templatemanagements.yaml @@ -0,0 +1,244 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: templatemanagements.hmc.mirantis.com +spec: + group: hmc.mirantis.com + names: + kind: TemplateManagement + listKind: TemplateManagementList + plural: templatemanagements + shortNames: + - tm + singular: templatemanagement + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: TemplateManagement is the Schema for the template management + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TemplateManagementSpec defines the desired state of TemplateManagement + properties: + accessRules: + description: |- + AccessRules is the list of access rules. Each AccessRule enforces + Templates distribution to the TargetNamespaces. + items: + description: |- + AccessRule is the definition of the TemplateManagement access rule. Each AccessRule enforces + Templates distribution to the TargetNamespaces + properties: + clusterTemplateChains: + description: |- + ClusterTemplateChains lists the names of ClusterTemplateChains whose ClusterTemplates + will be distributed to all namespaces specified in TargetNamespaces. + items: + type: string + type: array + serviceTemplateChains: + description: |- + ServiceTemplateChains lists the names of ServiceTemplateChains whose ServiceTemplates + will be distributed to all namespaces specified in TargetNamespaces. + items: + type: string + type: array + targetNamespaces: + description: |- + TargetNamespaces defines the namespaces where selected Templates will be distributed. + Templates will be distributed to all namespaces if unset. + properties: + list: + description: List is the list of namespaces to select. + items: + type: string + type: array + selector: + description: |- + Selector is a structured label query to select namespaces. + Mutually exclusive with StringSelector. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + stringSelector: + description: |- + StringSelector is a label query to select namespaces. + Mutually exclusive with Selector. + type: string + type: object + x-kubernetes-validations: + - message: only one of spec.targetNamespaces.selector or spec.targetNamespaces.stringSelector + spec.targetNamespaces.list can be specified + rule: '((has(self.stringSelector) ? 1 : 0) + (has(self.selector) + ? 1 : 0) + (has(self.list) ? 1 : 0)) <= 1' + type: object + type: array + type: object + status: + description: TemplateManagementStatus defines the observed state of TemplateManagement + properties: + current: + description: Current reflects the applied access rules configuration. + items: + description: |- + AccessRule is the definition of the TemplateManagement access rule. Each AccessRule enforces + Templates distribution to the TargetNamespaces + properties: + clusterTemplateChains: + description: |- + ClusterTemplateChains lists the names of ClusterTemplateChains whose ClusterTemplates + will be distributed to all namespaces specified in TargetNamespaces. + items: + type: string + type: array + serviceTemplateChains: + description: |- + ServiceTemplateChains lists the names of ServiceTemplateChains whose ServiceTemplates + will be distributed to all namespaces specified in TargetNamespaces. + items: + type: string + type: array + targetNamespaces: + description: |- + TargetNamespaces defines the namespaces where selected Templates will be distributed. + Templates will be distributed to all namespaces if unset. + properties: + list: + description: List is the list of namespaces to select. + items: + type: string + type: array + selector: + description: |- + Selector is a structured label query to select namespaces. + Mutually exclusive with StringSelector. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + stringSelector: + description: |- + StringSelector is a label query to select namespaces. + Mutually exclusive with Selector. + type: string + type: object + x-kubernetes-validations: + - message: only one of spec.targetNamespaces.selector or spec.targetNamespaces.stringSelector + spec.targetNamespaces.list can be specified + rule: '((has(self.stringSelector) ? 1 : 0) + (has(self.selector) + ? 1 : 0) + (has(self.list) ? 1 : 0)) <= 1' + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} From cdc9405ab2c1a972e3e08e48d37d3c55a18d3d40 Mon Sep 17 00:00:00 2001 From: Ekaterina Kazakova Date: Wed, 11 Sep 2024 14:44:26 +0400 Subject: [PATCH 2/3] Add Cluster and Service TemplateChain CRDs --- api/v1alpha1/templatechain_types.go | 86 +++++++++ api/v1alpha1/zz_generated.deepcopy.go | 173 ++++++++++++++++++ ...mc.mirantis.com_clustertemplatechains.yaml | 75 ++++++++ ...mc.mirantis.com_servicetemplatechains.yaml | 75 ++++++++ 4 files changed, 409 insertions(+) create mode 100644 api/v1alpha1/templatechain_types.go create mode 100644 templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplatechains.yaml create mode 100644 templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplatechains.yaml diff --git a/api/v1alpha1/templatechain_types.go b/api/v1alpha1/templatechain_types.go new file mode 100644 index 000000000..41bedc524 --- /dev/null +++ b/api/v1alpha1/templatechain_types.go @@ -0,0 +1,86 @@ +// Copyright 2024 +// +// 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" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// ClusterTemplateChain is the Schema for the cluster template chain API +type ClusterTemplateChain struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TemplateChainSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// ClusterTemplateChainList contains a list of ClusterTemplateChain +type ClusterTemplateChainList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterTemplateChain `json:"items"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// ServiceTemplateChain is the Schema for the service template chain API +type ServiceTemplateChain struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TemplateChainSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// ServiceTemplateChainList contains a list of ServiceTemplateChain +type ServiceTemplateChainList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ServiceTemplateChain `json:"items"` +} + +// TemplateChainSpec defines the observed state of TemplateChain +type TemplateChainSpec struct { + // SupportedTemplates is the list of supported Templates definitions and all available upgrade sequences for it. + // +optional + SupportedTemplates []SupportedTemplate `json:"supportedTemplates,omitempty"` +} + +// SupportedTemplate is the supported Template definition and all available upgrade sequences for it +type SupportedTemplate struct { + // Name is the name of the Template. + Name string `json:"name"` + // AvailableUpgrades is the list of available upgrades for the specified Template. + // +optional + AvailableUpgrades []AvailableUpgrade `json:"availableUpgrades,omitempty"` +} + +// AvailableUpgrade is the definition of the available upgrade for the Template +type AvailableUpgrade struct { + // Name is the name of the Template to which the upgrade is available. + Name string `json:"name"` +} + +func init() { + SchemeBuilder.Register(&ClusterTemplateChain{}, &ClusterTemplateChainList{}) + SchemeBuilder.Register(&ServiceTemplateChain{}, &ServiceTemplateChainList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 369582bc7..ddabceb72 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -51,6 +51,21 @@ func (in *AccessRule) DeepCopy() *AccessRule { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AvailableUpgrade) DeepCopyInto(out *AvailableUpgrade) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AvailableUpgrade. +func (in *AvailableUpgrade) DeepCopy() *AvailableUpgrade { + if in == nil { + return nil + } + out := new(AvailableUpgrade) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterTemplate) DeepCopyInto(out *ClusterTemplate) { *out = *in @@ -78,6 +93,64 @@ func (in *ClusterTemplate) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTemplateChain) DeepCopyInto(out *ClusterTemplateChain) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplateChain. +func (in *ClusterTemplateChain) DeepCopy() *ClusterTemplateChain { + if in == nil { + return nil + } + out := new(ClusterTemplateChain) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTemplateChain) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTemplateChainList) DeepCopyInto(out *ClusterTemplateChainList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTemplateChain, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplateChainList. +func (in *ClusterTemplateChainList) DeepCopy() *ClusterTemplateChainList { + if in == nil { + return nil + } + out := new(ClusterTemplateChainList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTemplateChainList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterTemplateList) DeepCopyInto(out *ClusterTemplateList) { *out = *in @@ -572,6 +645,64 @@ func (in *ServiceTemplate) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceTemplateChain) DeepCopyInto(out *ServiceTemplateChain) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceTemplateChain. +func (in *ServiceTemplateChain) DeepCopy() *ServiceTemplateChain { + if in == nil { + return nil + } + out := new(ServiceTemplateChain) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceTemplateChain) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceTemplateChainList) DeepCopyInto(out *ServiceTemplateChainList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ServiceTemplateChain, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceTemplateChainList. +func (in *ServiceTemplateChainList) DeepCopy() *ServiceTemplateChainList { + if in == nil { + return nil + } + out := new(ServiceTemplateChainList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceTemplateChainList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceTemplateList) DeepCopyInto(out *ServiceTemplateList) { *out = *in @@ -636,6 +767,26 @@ func (in *ServiceTemplateStatus) DeepCopy() *ServiceTemplateStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SupportedTemplate) DeepCopyInto(out *SupportedTemplate) { + *out = *in + if in.AvailableUpgrades != nil { + in, out := &in.AvailableUpgrades, &out.AvailableUpgrades + *out = make([]AvailableUpgrade, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SupportedTemplate. +func (in *SupportedTemplate) DeepCopy() *SupportedTemplate { + if in == nil { + return nil + } + out := new(SupportedTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TargetNamespaces) DeepCopyInto(out *TargetNamespaces) { *out = *in @@ -657,6 +808,28 @@ func (in *TargetNamespaces) DeepCopy() *TargetNamespaces { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateChainSpec) DeepCopyInto(out *TemplateChainSpec) { + *out = *in + if in.SupportedTemplates != nil { + in, out := &in.SupportedTemplates, &out.SupportedTemplates + *out = make([]SupportedTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateChainSpec. +func (in *TemplateChainSpec) DeepCopy() *TemplateChainSpec { + if in == nil { + return nil + } + out := new(TemplateChainSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TemplateManagement) DeepCopyInto(out *TemplateManagement) { *out = *in diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplatechains.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplatechains.yaml new file mode 100644 index 000000000..c6c52f993 --- /dev/null +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplatechains.yaml @@ -0,0 +1,75 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: clustertemplatechains.hmc.mirantis.com +spec: + group: hmc.mirantis.com + names: + kind: ClusterTemplateChain + listKind: ClusterTemplateChainList + plural: clustertemplatechains + singular: clustertemplatechain + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterTemplateChain is the Schema for the cluster template chain + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TemplateChainSpec defines the observed state of TemplateChain + properties: + supportedTemplates: + description: SupportedTemplates is the list of supported Templates + definitions and all available upgrade sequences for it. + items: + description: SupportedTemplate is the supported Template definition + and all available upgrade sequences for it + properties: + availableUpgrades: + description: AvailableUpgrades is the list of available upgrades + for the specified Template. + items: + description: AvailableUpgrade is the definition of the available + upgrade for the Template + properties: + name: + description: Name is the name of the Template to which + the upgrade is available. + type: string + required: + - name + type: object + type: array + name: + description: Name is the name of the Template. + type: string + required: + - name + type: object + type: array + type: object + type: object + served: true + storage: true diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplatechains.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplatechains.yaml new file mode 100644 index 000000000..d6120df77 --- /dev/null +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplatechains.yaml @@ -0,0 +1,75 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: servicetemplatechains.hmc.mirantis.com +spec: + group: hmc.mirantis.com + names: + kind: ServiceTemplateChain + listKind: ServiceTemplateChainList + plural: servicetemplatechains + singular: servicetemplatechain + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ServiceTemplateChain is the Schema for the service template chain + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TemplateChainSpec defines the observed state of TemplateChain + properties: + supportedTemplates: + description: SupportedTemplates is the list of supported Templates + definitions and all available upgrade sequences for it. + items: + description: SupportedTemplate is the supported Template definition + and all available upgrade sequences for it + properties: + availableUpgrades: + description: AvailableUpgrades is the list of available upgrades + for the specified Template. + items: + description: AvailableUpgrade is the definition of the available + upgrade for the Template + properties: + name: + description: Name is the name of the Template to which + the upgrade is available. + type: string + required: + - name + type: object + type: array + name: + description: Name is the name of the Template. + type: string + required: + - name + type: object + type: array + type: object + type: object + served: true + storage: true From 47ae3a90b2bd2a8be94de096f28f6057305a29df Mon Sep 17 00:00:00 2001 From: Ekaterina Kazakova Date: Thu, 12 Sep 2024 13:15:20 +0400 Subject: [PATCH 3/3] Add base code for the TemplateManagement reconciler --- cmd/main.go | 9 +++ .../templatemanagement_controller.go | 59 ++++++++++++++ .../templatemanagement_controller_test.go | 80 +++++++++++++++++++ .../provider/hmc/templates/rbac/roles.yaml | 19 ++++- 4 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 internal/controller/templatemanagement_controller.go create mode 100644 internal/controller/templatemanagement_controller_test.go diff --git a/cmd/main.go b/cmd/main.go index 81504348d..1a9914ef9 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -220,6 +220,15 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Management") os.Exit(1) } + if err = (&controller.TemplateManagementReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Config: mgr.GetConfig(), + SystemNamespace: currentNamespace, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "TemplateManagement") + os.Exit(1) + } if err = mgr.Add(&controller.Poller{ Client: mgr.GetClient(), Config: mgr.GetConfig(), diff --git a/internal/controller/templatemanagement_controller.go b/internal/controller/templatemanagement_controller.go new file mode 100644 index 000000000..092b34f44 --- /dev/null +++ b/internal/controller/templatemanagement_controller.go @@ -0,0 +1,59 @@ +// Copyright 2024 +// +// 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 controller + +import ( + "context" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + hmc "github.com/Mirantis/hmc/api/v1alpha1" +) + +// TemplateManagementReconciler reconciles a TemplateManagement object +type TemplateManagementReconciler struct { + client.Client + Scheme *runtime.Scheme + Config *rest.Config + SystemNamespace string +} + +func (r *TemplateManagementReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx).WithValues("TemplateManagementController", req.NamespacedName) + log.IntoContext(ctx, l) + l.Info("Reconciling TemplateManagement") + templateMgmt := &hmc.TemplateManagement{} + if err := r.Get(ctx, req.NamespacedName, templateMgmt); err != nil { + if apierrors.IsNotFound(err) { + l.Info("TemplateManagement not found, ignoring since object must be deleted") + return ctrl.Result{}, nil + } + l.Error(err, "Failed to get TemplateManagement") + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TemplateManagementReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&hmc.TemplateManagement{}). + Complete(r) +} diff --git a/internal/controller/templatemanagement_controller_test.go b/internal/controller/templatemanagement_controller_test.go new file mode 100644 index 000000000..73a5968de --- /dev/null +++ b/internal/controller/templatemanagement_controller_test.go @@ -0,0 +1,80 @@ +// Copyright 2024 +// +// 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 controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + hmcmirantiscomv1alpha1 "github.com/Mirantis/hmc/api/v1alpha1" +) + +var _ = Describe("Template Management Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + } + templateMgmt := &hmcmirantiscomv1alpha1.TemplateManagement{} + + BeforeEach(func() { + By("creating the custom resource for the Kind TemplateManagement") + err := k8sClient.Get(ctx, typeNamespacedName, templateMgmt) + if err != nil && errors.IsNotFound(err) { + resource := &hmcmirantiscomv1alpha1.TemplateManagement{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &hmcmirantiscomv1alpha1.TemplateManagement{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance TemplateManagement") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &TemplateManagementReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/templates/provider/hmc/templates/rbac/roles.yaml b/templates/provider/hmc/templates/rbac/roles.yaml index 4a72d9312..96c613214 100644 --- a/templates/provider/hmc/templates/rbac/roles.yaml +++ b/templates/provider/hmc/templates/rbac/roles.yaml @@ -6,12 +6,12 @@ metadata: {{- include "hmc.labels" . | nindent 4 }} rules: - apiGroups: - - cluster.x-k8s.io + - cluster.x-k8s.io resources: - - clusters + - clusters verbs: - - get - - list + - get + - list - apiGroups: - helm.toolkit.fluxcd.io resources: @@ -62,6 +62,16 @@ rules: - patch - update - watch +- apiGroups: + - hmc.mirantis.com + resources: + - templatemanagements + verbs: + - get + - list + - patch + - update + - watch - apiGroups: - hmc.mirantis.com resources: @@ -72,6 +82,7 @@ rules: - hmc.mirantis.com resources: - managements/status + - templatemanagements/status verbs: - get - patch