diff --git a/api/v1alpha1/lvmcluster_types.go b/api/v1alpha1/lvmcluster_types.go index c0b920024..d850d0608 100644 --- a/api/v1alpha1/lvmcluster_types.go +++ b/api/v1alpha1/lvmcluster_types.go @@ -31,9 +31,9 @@ type LVMClusterSpec struct { // Tolerations to apply to nodes to act on // +optional Tolerations []corev1.Toleration `json:"tolerations,omitempty"` - // DeviceClasses are a rules that assign local storage devices to volumegroups that are used for creating lvm based PVs + // Storage describes the deviceClass configuration for local storage devices // +Optional - DeviceClasses []DeviceClass `json:"deviceClasses,omitempty"` + Storage Storage `json:"storage,omitempty"` } type DeviceClass struct { @@ -94,6 +94,12 @@ type DeviceClassStatus struct { NodeStatus []NodeStatus `json:"nodeStatus,omitempty"` } +type Storage struct { + // DeviceClasses are a rules that assign local storage devices to volumegroups that are used for creating lvm based PVs + // +Optional + DeviceClasses []DeviceClass `json:"deviceClasses,omitempty"` +} + // NodeStatus defines the observed state of the deviceclass on the node type NodeStatus struct { // Node is the name of the node diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d4c1a26c0..a25a96bad 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -156,13 +156,7 @@ func (in *LVMClusterSpec) DeepCopyInto(out *LVMClusterSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.DeviceClasses != nil { - in, out := &in.DeviceClasses, &out.DeviceClasses - *out = make([]DeviceClass, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + in.Storage.DeepCopyInto(&out.Storage) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LVMClusterSpec. @@ -412,6 +406,28 @@ func (in *NodeStatus) DeepCopy() *NodeStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Storage) DeepCopyInto(out *Storage) { + *out = *in + if in.DeviceClasses != nil { + in, out := &in.DeviceClasses, &out.DeviceClasses + *out = make([]DeviceClass, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Storage. +func (in *Storage) DeepCopy() *Storage { + if in == nil { + return nil + } + out := new(Storage) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VGStatus) DeepCopyInto(out *VGStatus) { *out = *in diff --git a/config/crd/bases/lvm.topolvm.io_lvmclusters.yaml b/config/crd/bases/lvm.topolvm.io_lvmclusters.yaml index 29e798349..686959d72 100644 --- a/config/crd/bases/lvm.topolvm.io_lvmclusters.yaml +++ b/config/crd/bases/lvm.topolvm.io_lvmclusters.yaml @@ -36,111 +36,121 @@ spec: spec: description: LVMClusterSpec defines the desired state of LVMCluster properties: - deviceClasses: - description: DeviceClasses are a rules that assign local storage devices - to volumegroups that are used for creating lvm based PVs - items: - properties: - deviceSelector: - description: DeviceSelector is a set of rules that should match - for a device to be included in the LVMCluster - type: object - name: - description: 'Name of the class, the VG and possibly the storageclass. - Validations to confirm that this field can be used as metadata.name - field in storageclass ref: https://github.com/kubernetes/apimachinery/blob/de7147/pkg/util/validation/validation.go#L209' - maxLength: 245 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - nodeSelector: - description: NodeSelector chooses nodes on which to create the - deviceclass + storage: + description: Storage describes the deviceClass configuration for local + storage devices + properties: + deviceClasses: + description: DeviceClasses are a rules that assign local storage + devices to volumegroups that are used for creating lvm based + PVs + items: properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The - terms are ORed. - items: - description: A null or empty node selector term matches - no objects. The requirements of them are ANDed. The - TopologySelectorTerm type implements a subset of the - NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: A node selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: 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. If the operator is Gt or Lt, the values - array must have a single element, which will - be interpreted as an integer. This array is - replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: A node selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: 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. If the operator is Gt or Lt, the values - array must have a single element, which will - be interpreted as an integer. This array is - replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - type: object - type: array - required: - - nodeSelectorTerms + deviceSelector: + description: DeviceSelector is a set of rules that should + match for a device to be included in the LVMCluster + type: object + name: + description: 'Name of the class, the VG and possibly the + storageclass. Validations to confirm that this field can + be used as metadata.name field in storageclass ref: https://github.com/kubernetes/apimachinery/blob/de7147/pkg/util/validation/validation.go#L209' + maxLength: 245 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + nodeSelector: + description: NodeSelector chooses nodes on which to create + the deviceclass + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: A null or empty node selector term matches + no objects. The requirements of them are ANDed. + The TopologySelectorTerm type implements a subset + of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: 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. If the operator is + Gt or Lt, the values array must have a + single element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: 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. If the operator is + Gt or Lt, the values array must have a + single element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object type: object - type: object - type: array + type: array + type: object tolerations: description: Tolerations to apply to nodes to act on items: diff --git a/config/samples/lvm_v1alpha1_lvmcluster.yaml b/config/samples/lvm_v1alpha1_lvmcluster.yaml index 915086a1d..07f0300ef 100644 --- a/config/samples/lvm_v1alpha1_lvmcluster.yaml +++ b/config/samples/lvm_v1alpha1_lvmcluster.yaml @@ -3,5 +3,6 @@ kind: LVMCluster metadata: name: lvmcluster-sample spec: - deviceClasses: - - name: vg1 + storage: + deviceClasses: + - name: vg1 diff --git a/controllers/lvm_volumegroup.go b/controllers/lvm_volumegroup.go index 3d45c427a..b19c9d09a 100644 --- a/controllers/lvm_volumegroup.go +++ b/controllers/lvm_volumegroup.go @@ -96,7 +96,7 @@ func (c lvmVG) getLvmVolumeGroups(r *LVMClusterReconciler, instance *lvmv1alpha1 lvmVolumeGroups := []*lvmv1alpha1.LVMVolumeGroup{} - deviceClasses := instance.Spec.DeviceClasses + deviceClasses := instance.Spec.Storage.DeviceClasses for _, deviceClass := range deviceClasses { lvmVolumeGroup := &lvmv1alpha1.LVMVolumeGroup{ ObjectMeta: metav1.ObjectMeta{ diff --git a/controllers/lvmcluster_controller_test.go b/controllers/lvmcluster_controller_test.go index 32495c4ef..06b712892 100644 --- a/controllers/lvmcluster_controller_test.go +++ b/controllers/lvmcluster_controller_test.go @@ -46,7 +46,9 @@ var _ = Describe("LVMCluster controller", func() { Namespace: testLvmClusterNamespace, }, Spec: lvmv1alpha1.LVMClusterSpec{ - DeviceClasses: []lvmv1alpha1.DeviceClass{{Name: testDeviceClassName}}, + Storage: lvmv1alpha1.Storage{ + DeviceClasses: []lvmv1alpha1.DeviceClass{{Name: testDeviceClassName}}, + }, }, } @@ -71,7 +73,7 @@ var _ = Describe("LVMCluster controller", func() { // Topolvm Storage Classes scNames := []types.NamespacedName{} - for _, deviceClass := range lvmClusterIn.Spec.DeviceClasses { + for _, deviceClass := range lvmClusterIn.Spec.Storage.DeviceClasses { scNames = append(scNames, types.NamespacedName{ Name: fmt.Sprintf("odf-lvm-%s", deviceClass.Name), }, diff --git a/controllers/topolvm_storageclass.go b/controllers/topolvm_storageclass.go index 0329c02fb..11022a282 100644 --- a/controllers/topolvm_storageclass.go +++ b/controllers/topolvm_storageclass.go @@ -49,7 +49,7 @@ func (s topolvmStorageClass) ensureDeleted(r *LVMClusterReconciler, ctx context. // construct name of storage class based on CR spec deviceClass field and // delete the corresponding storage class - for _, deviceClass := range lvmCluster.Spec.DeviceClasses { + for _, deviceClass := range lvmCluster.Spec.Storage.DeviceClasses { sc := &storagev1.StorageClass{} scName := fmt.Sprintf("odf-lvm-%s", deviceClass.Name) err := r.Client.Get(ctx, types.NamespacedName{Name: scName}, sc) @@ -90,7 +90,7 @@ func getTopolvmStorageClasses(lvmCluster *lvmv1alpha1.LVMCluster) []*storagev1.S allowVolumeExpansion := true volumeBindingMode := storagev1.VolumeBindingWaitForFirstConsumer - for _, deviceClass := range lvmCluster.Spec.DeviceClasses { + for _, deviceClass := range lvmCluster.Spec.Storage.DeviceClasses { storageClass := &storagev1.StorageClass{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("odf-lvm-%s", deviceClass.Name), diff --git a/controllers/utils.go b/controllers/utils.go index cf9e16cc4..fed38e5ff 100644 --- a/controllers/utils.go +++ b/controllers/utils.go @@ -30,7 +30,7 @@ func extractNodeSelectorAndTolerations(lvmCluster *lvmv1alpha1.LVMCluster) (*cor terms := make([]corev1.NodeSelectorTerm, 0) matchAllNodes := false - for _, deviceClass := range lvmCluster.Spec.DeviceClasses { + for _, deviceClass := range lvmCluster.Spec.Storage.DeviceClasses { if deviceClass.NodeSelector != nil { terms = append(terms, deviceClass.NodeSelector.NodeSelectorTerms...) diff --git a/controllers/vgmanager_test.go b/controllers/vgmanager_test.go index f8cd04bf7..0007b6ed5 100644 --- a/controllers/vgmanager_test.go +++ b/controllers/vgmanager_test.go @@ -54,9 +54,11 @@ func TestVGManagerEnsureCreated(t *testing.T) { { desc: "nil nodeSelector in any of the deviceClasses", lvmclusterSpec: lvmv1alpha1.LVMClusterSpec{ - DeviceClasses: []lvmv1alpha1.DeviceClass{ - {NodeSelector: nil}, - {}, + Storage: lvmv1alpha1.Storage{ + DeviceClasses: []lvmv1alpha1.DeviceClass{ + {NodeSelector: nil}, + {}, + }, }, }, expectedTolerations: []corev1.Toleration{},