diff --git a/api/v1/types.go b/api/v1/types.go index e9c0152d..daed0186 100644 --- a/api/v1/types.go +++ b/api/v1/types.go @@ -177,7 +177,7 @@ type Driver struct { // CSIDriverSpec is the specification for CSIDriver // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="CSI Driver Spec" - CSIDriverSpec CSIDriverSpec `json:"csiDriverSpec" yaml:"csiDriverSpec"` + CSIDriverSpec *CSIDriverSpec `json:"csiDriverSpec" yaml:"csiDriverSpec"` // ConfigVersion is the configuration version of the driver // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Config Version" @@ -185,6 +185,7 @@ type Driver struct { // Replicas is the count of controllers for Controller plugin // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Controller count" + // +kubebuilder:default=2 Replicas int32 `json:"replicas" yaml:"replicas"` // DNSPolicy is the dnsPolicy of the daemonset for Node plugin @@ -193,15 +194,15 @@ type Driver struct { // Common is the common specification for both controller and node plugins // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Common specification" - Common ContainerTemplate `json:"common" yaml:"common"` + Common *ContainerTemplate `json:"common" yaml:"common"` // Controller is the specification for Controller plugin only // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Controller Specification" - Controller ContainerTemplate `json:"controller,omitempty" yaml:"controller"` + Controller *ContainerTemplate `json:"controller,omitempty" yaml:"controller"` // Node is the specification for Node plugin only // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Node specification" - Node ContainerTemplate `json:"node,omitempty" yaml:"node"` + Node *ContainerTemplate `json:"node,omitempty" yaml:"node"` // SideCars is the specification for CSI sidecar containers // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="CSI SideCars specification" diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index f7c974bb..0e7fbdf2 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -236,10 +236,26 @@ func (in *Credkey) DeepCopy() *Credkey { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Driver) DeepCopyInto(out *Driver) { *out = *in - out.CSIDriverSpec = in.CSIDriverSpec - in.Common.DeepCopyInto(&out.Common) - in.Controller.DeepCopyInto(&out.Controller) - in.Node.DeepCopyInto(&out.Node) + if in.CSIDriverSpec != nil { + in, out := &in.CSIDriverSpec, &out.CSIDriverSpec + *out = new(CSIDriverSpec) + **out = **in + } + if in.Common != nil { + in, out := &in.Common, &out.Common + *out = new(ContainerTemplate) + (*in).DeepCopyInto(*out) + } + if in.Controller != nil { + in, out := &in.Controller, &out.Controller + *out = new(ContainerTemplate) + (*in).DeepCopyInto(*out) + } + if in.Node != nil { + in, out := &in.Node, &out.Node + *out = new(ContainerTemplate) + (*in).DeepCopyInto(*out) + } if in.SideCars != nil { in, out := &in.SideCars, &out.SideCars *out = make([]ContainerTemplate, len(*in)) diff --git a/config/crd/bases/storage.dell.com_containerstoragemodules.yaml b/config/crd/bases/storage.dell.com_containerstoragemodules.yaml index 206505e8..b27d17e8 100644 --- a/config/crd/bases/storage.dell.com_containerstoragemodules.yaml +++ b/config/crd/bases/storage.dell.com_containerstoragemodules.yaml @@ -35,40 +35,55 @@ spec: name: v1 schema: openAPIV3Schema: - description: + description: >- ContainerStorageModule is the Schema for the containerstoragemodules 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 + 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 + + 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. + 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 + + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object spec: - description: ContainerStorageModuleSpec defines the desired state of ContainerStorageModule + description: >- + ContainerStorageModuleSpec defines the desired state of + ContainerStorageModule properties: driver: description: Driver is a CSI Drivers for Dell Technologies properties: authSecret: - description: - AuthSecret is the name of the credentials secret - for the driver + description: >- + AuthSecret is the name of the credentials secret for the + driver type: string common: - description: + description: >- Common is the common specification for both controller and node plugins properties: @@ -78,62 +93,62 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag for - the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: - CertificateAuthority is a certificate authority - used to validate a certificate + description: >- + CertificateAuthority is a certificate authority used + to validate a certificate type: string commander: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: + description: >- The interval which the reconcile of each controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: + description: >- CreateWithInstall is used to indicate wether or not to create a secret for objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: - SecretContents contains credentials to - access objectstore + description: >- + SecretContents contains credentials to access + objectstore properties: aws_access_key_id: - description: - AccessKeyID is a name of key ID to - access objectstore + description: >- + AccessKeyID is a name of key ID to access + objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -141,43 +156,57 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: - Enabled is used to indicate wether or not to - deploy a module + description: >- + Enabled is used to indicate wether or not to deploy + a module type: boolean envs: - description: - Envs is the set of environment variables for - the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be a + C_IDENTIFIER. type: string value: - description: |- + description: >- Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: + description: >- Source for the environment variable's value. Cannot be used if value is not empty. properties: @@ -188,95 +217,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap or - its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select in - the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: only + resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are currently + supported. properties: containerName: - description: - "Container name: required for volumes, - optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: + description: >- Selects a key of a secret in the pod's namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret or its - key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -294,17 +346,19 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy for - the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: + description: >- LeaderElection is boolean flag to enable leader election type: boolean licenseName: - description: LicenseName is the name of the license for app-mobility + description: >- + LicenseName is the name of the license for + app-mobility type: string name: description: Name is the name of Container @@ -312,14 +366,17 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true for + the pod to fit on a node. + + Selector which must match a node's labels for the + pod to be scheduled on that node. type: object objectStoreSecretName: - description: - ObjectStoreSecretName is the name of the secret - for the object store for app-mobility + description: >- + ObjectStoreSecretName is the name of the secret for + the object store for app-mobility type: string opa: description: Opa is the image tag for the Container @@ -328,30 +385,31 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of the + OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: - ProxyServerIngress is the authorization proxy - server ingress configuration + description: >- + ProxyServerIngress is the authorization proxy server + ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key value - map that stores additional annotations for the ingress + description: >- + Annotations is an unstructured key value map + that stores additional annotations for the + ingress type: object hosts: description: Hosts is the hosts rules for the ingress @@ -367,9 +425,9 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: - ProxyServiceReplicas is the number of replicas - for the proxy service deployment + description: >- + ProxyServiceReplicas is the number of replicas for + the proxy service deployment type: integer redis: description: Redis is the image tag for the Container @@ -381,7 +439,7 @@ spec: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: + description: >- RedisReplicas is the number of replicas for the redis deployment type: integer @@ -392,15 +450,15 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: - RoleServiceReplicas is the number of replicas - for the role service deployment + description: >- + RoleServiceReplicas is the number of replicas for + the role service deployment type: integer sentinel: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: + description: >- skipCertificateValidation is the flag to skip certificate validation type: boolean @@ -408,73 +466,99 @@ spec: description: StorageService is the image tag for the Container type: string storageServiceReplicas: - description: - StorageServiceReplicas is the number of replicas - for storage service deployment + description: >- + StorageServiceReplicas is the number of replicas for + storage service deployment type: integer storageclass: - description: - RedisStorageClass is the authorization proxy - server redis storage class for persistence + description: >- + RedisStorageClass is the authorization proxy server + redis storage class for persistence type: string tenantService: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: - TenantServiceReplicas is the number of replicas - for the tenant service deployment + description: >- + TenantServiceReplicas is the number of replicas for + the tenant service deployment type: integer tolerations: - description: + description: >- Tolerations is the list of tolerations for the driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to tolerates + any taint that matches + + the triple using the matching + operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to match. + Empty means match all taint effects. + + When specified, allowed values are NoSchedule, + PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint keys. + + If the key is empty, operator must be Exists; + this combination means to match all values and + all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can + description: >- + Operator represents a key's relationship to + the value. + + Valid operators are Exists and Equal. Defaults + to Equal. + + Exists is equivalent to wildcard for value, so + that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field is + ignored) tolerates the taint. By default, + + it is not set, which means tolerate the taint + forever (do not evict). Zero and + + negative values will be treated as 0 (evict + immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value should be + empty, otherwise just a regular string. type: string type: object type: array useVolumeSnapshot: - description: - UseSnapshot is to check whether volume snapshot - is enabled under velero component + description: >- + UseSnapshot is to check whether volume snapshot is + enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -482,17 +566,18 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault certificate + certificate authority for validaitng the vault + certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string @@ -503,25 +588,23 @@ spec: description: Role is the role for this vault type: string skipCertificateValidation: - description: - SkipCertificateValidation validates the - vault server certificate or not + description: >- + SkipCertificateValidation validates the vault + server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object configVersion: - description: - ConfigVersion is the configuration version of the - driver + description: ConfigVersion is the configuration version of the driver type: string controller: - description: + description: >- Controller is the specification for Controller plugin only properties: @@ -531,62 +614,62 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag for - the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: - CertificateAuthority is a certificate authority - used to validate a certificate + description: >- + CertificateAuthority is a certificate authority used + to validate a certificate type: string commander: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: + description: >- The interval which the reconcile of each controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: + description: >- CreateWithInstall is used to indicate wether or not to create a secret for objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: - SecretContents contains credentials to - access objectstore + description: >- + SecretContents contains credentials to access + objectstore properties: aws_access_key_id: - description: - AccessKeyID is a name of key ID to - access objectstore + description: >- + AccessKeyID is a name of key ID to access + objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -594,43 +677,57 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: - Enabled is used to indicate wether or not to - deploy a module + description: >- + Enabled is used to indicate wether or not to deploy + a module type: boolean envs: - description: - Envs is the set of environment variables for - the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be a + C_IDENTIFIER. type: string value: - description: |- + description: >- Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: + description: >- Source for the environment variable's value. Cannot be used if value is not empty. properties: @@ -641,95 +738,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap or - its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select in - the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: only + resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are currently + supported. properties: containerName: - description: - "Container name: required for volumes, - optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: + description: >- Selects a key of a secret in the pod's namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret or its - key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -747,17 +867,19 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy for - the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: + description: >- LeaderElection is boolean flag to enable leader election type: boolean licenseName: - description: LicenseName is the name of the license for app-mobility + description: >- + LicenseName is the name of the license for + app-mobility type: string name: description: Name is the name of Container @@ -765,14 +887,17 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true for + the pod to fit on a node. + + Selector which must match a node's labels for the + pod to be scheduled on that node. type: object objectStoreSecretName: - description: - ObjectStoreSecretName is the name of the secret - for the object store for app-mobility + description: >- + ObjectStoreSecretName is the name of the secret for + the object store for app-mobility type: string opa: description: Opa is the image tag for the Container @@ -781,30 +906,31 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of the + OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: - ProxyServerIngress is the authorization proxy - server ingress configuration + description: >- + ProxyServerIngress is the authorization proxy server + ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key value - map that stores additional annotations for the ingress + description: >- + Annotations is an unstructured key value map + that stores additional annotations for the + ingress type: object hosts: description: Hosts is the hosts rules for the ingress @@ -820,9 +946,9 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: - ProxyServiceReplicas is the number of replicas - for the proxy service deployment + description: >- + ProxyServiceReplicas is the number of replicas for + the proxy service deployment type: integer redis: description: Redis is the image tag for the Container @@ -834,7 +960,7 @@ spec: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: + description: >- RedisReplicas is the number of replicas for the redis deployment type: integer @@ -845,15 +971,15 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: - RoleServiceReplicas is the number of replicas - for the role service deployment + description: >- + RoleServiceReplicas is the number of replicas for + the role service deployment type: integer sentinel: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: + description: >- skipCertificateValidation is the flag to skip certificate validation type: boolean @@ -861,73 +987,99 @@ spec: description: StorageService is the image tag for the Container type: string storageServiceReplicas: - description: - StorageServiceReplicas is the number of replicas - for storage service deployment + description: >- + StorageServiceReplicas is the number of replicas for + storage service deployment type: integer storageclass: - description: - RedisStorageClass is the authorization proxy - server redis storage class for persistence + description: >- + RedisStorageClass is the authorization proxy server + redis storage class for persistence type: string tenantService: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: - TenantServiceReplicas is the number of replicas - for the tenant service deployment + description: >- + TenantServiceReplicas is the number of replicas for + the tenant service deployment type: integer tolerations: - description: + description: >- Tolerations is the list of tolerations for the driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to tolerates + any taint that matches + + the triple using the matching + operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to match. + Empty means match all taint effects. + + When specified, allowed values are NoSchedule, + PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint keys. + + If the key is empty, operator must be Exists; + this combination means to match all values and + all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can + description: >- + Operator represents a key's relationship to + the value. + + Valid operators are Exists and Equal. Defaults + to Equal. + + Exists is equivalent to wildcard for value, so + that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field is + ignored) tolerates the taint. By default, + + it is not set, which means tolerate the taint + forever (do not evict). Zero and + + negative values will be treated as 0 (evict + immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value should be + empty, otherwise just a regular string. type: string type: object type: array useVolumeSnapshot: - description: - UseSnapshot is to check whether volume snapshot - is enabled under velero component + description: >- + UseSnapshot is to check whether volume snapshot is + enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -935,17 +1087,18 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault certificate + certificate authority for validaitng the vault + certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string @@ -956,16 +1109,16 @@ spec: description: Role is the role for this vault type: string skipCertificateValidation: - description: - SkipCertificateValidation validates the - vault server certificate or not + description: >- + SkipCertificateValidation validates the vault + server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object csiDriverSpec: @@ -977,22 +1130,24 @@ spec: type: boolean type: object csiDriverType: - description: - CSIDriverType is the CSI Driver type for Dell Technologies - - e.g, powermax, powerflex,... + description: >- + CSIDriverType is the CSI Driver type for Dell + Technologies - e.g, powermax, powerflex,... type: string dnsPolicy: - description: + description: >- DNSPolicy is the dnsPolicy of the daemonset for Node plugin type: string forceRemoveDriver: - description: + description: >- ForceRemoveDriver is the boolean flag used to remove driver deployment when CR is deleted type: boolean initContainers: - description: InitContainers is the specification for Driver InitContainers + description: >- + InitContainers is the specification for Driver + InitContainers items: description: ContainerTemplate template properties: @@ -1002,22 +1157,23 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag for - the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller + deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: + description: >- CertificateAuthority is a certificate authority used to validate a certificate type: string @@ -1025,39 +1181,39 @@ spec: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: - The interval which the reconcile of each controller - is run + description: >- + The interval which the reconcile of each + controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: - CreateWithInstall is used to indicate - wether or not to create a secret for objectstore + description: >- + CreateWithInstall is used to indicate wether + or not to create a secret for objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: + description: >- SecretContents contains credentials to access objectstore properties: aws_access_key_id: - description: + description: >- AccessKeyID is a name of key ID to access objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -1065,45 +1221,59 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: + description: >- Enabled is used to indicate wether or not to deploy a module type: boolean envs: - description: - Envs is the set of environment variables for - the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be a + C_IDENTIFIER. type: string value: - description: |- + description: >- Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: - Source for the environment variable's - value. Cannot be used if value is not empty. + description: >- + Source for the environment variable's value. + Cannot be used if value is not empty. properties: configMapKeyRef: description: Selects a key of a ConfigMap. @@ -1112,95 +1282,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap - or its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select in - the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: + only resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are + currently supported. properties: containerName: - description: - "Container name: required for - volumes, optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: - Selects a key of a secret in the - pod's namespace + description: >- + Selects a key of a secret in the pod's + namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret or - its key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -1212,7 +1405,7 @@ spec: type: object type: array hostname: - description: + description: >- Hostname is the authorization proxy server hostname type: string @@ -1220,17 +1413,17 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy for - the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: + description: >- LeaderElection is boolean flag to enable leader election type: boolean licenseName: - description: + description: >- LicenseName is the name of the license for app-mobility type: string @@ -1240,12 +1433,15 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true for + the pod to fit on a node. + + Selector which must match a node's labels for the + pod to be scheduled on that node. type: object objectStoreSecretName: - description: + description: >- ObjectStoreSecretName is the name of the secret for the object store for app-mobility type: string @@ -1256,30 +1452,31 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of + the OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: + description: >- ProxyServerIngress is the authorization proxy server ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key value - map that stores additional annotations for the ingress + description: >- + Annotations is an unstructured key value map + that stores additional annotations for the + ingress type: object hosts: description: Hosts is the hosts rules for the ingress @@ -1295,9 +1492,9 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: - ProxyServiceReplicas is the number of replicas - for the proxy service deployment + description: >- + ProxyServiceReplicas is the number of replicas for + the proxy service deployment type: integer redis: description: Redis is the image tag for the Container @@ -1309,9 +1506,9 @@ spec: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: - RedisReplicas is the number of replicas for - the redis deployment + description: >- + RedisReplicas is the number of replicas for the + redis deployment type: integer replicaCount: description: ReplicaCount is the replica count for app mobility @@ -1320,15 +1517,15 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: - RoleServiceReplicas is the number of replicas - for the role service deployment + description: >- + RoleServiceReplicas is the number of replicas for + the role service deployment type: integer sentinel: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: + description: >- skipCertificateValidation is the flag to skip certificate validation type: boolean @@ -1336,12 +1533,12 @@ spec: description: StorageService is the image tag for the Container type: string storageServiceReplicas: - description: + description: >- StorageServiceReplicas is the number of replicas for storage service deployment type: integer storageclass: - description: + description: >- RedisStorageClass is the authorization proxy server redis storage class for persistence type: string @@ -1349,60 +1546,88 @@ spec: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: + description: >- TenantServiceReplicas is the number of replicas for the tenant service deployment type: integer tolerations: - description: - Tolerations is the list of tolerations for - the driver pods + description: >- + Tolerations is the list of tolerations for the + driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to tolerates + any taint that matches + + the triple using the matching + operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to match. + Empty means match all taint effects. + + When specified, allowed values are + NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint + keys. + + If the key is empty, operator must be + Exists; this combination means to match all + values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. + description: >- + Operator represents a key's relationship to + the value. + + Valid operators are Exists and Equal. + Defaults to Equal. + + Exists is equivalent to wildcard for value, + so that a pod can + + tolerate all taints of a particular + category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field is + ignored) tolerates the taint. By default, + + it is not set, which means tolerate the + taint forever (do not evict). Zero and + + negative values will be treated as 0 (evict + immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value should + be empty, otherwise just a regular string. type: string type: object type: array useVolumeSnapshot: - description: - UseSnapshot is to check whether volume snapshot - is enabled under velero component + description: >- + UseSnapshot is to check whether volume snapshot is + enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -1410,39 +1635,38 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault certificate + certificate authority for validaitng the + vault certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string identifier: - description: - Identifier is the identifier for this - vault + description: Identifier is the identifier for this vault type: string role: description: Role is the role for this vault type: string skipCertificateValidation: - description: + description: >- SkipCertificateValidation validates the vault server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object type: array @@ -1455,62 +1679,62 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag for - the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: - CertificateAuthority is a certificate authority - used to validate a certificate + description: >- + CertificateAuthority is a certificate authority used + to validate a certificate type: string commander: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: + description: >- The interval which the reconcile of each controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: + description: >- CreateWithInstall is used to indicate wether or not to create a secret for objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: - SecretContents contains credentials to - access objectstore + description: >- + SecretContents contains credentials to access + objectstore properties: aws_access_key_id: - description: - AccessKeyID is a name of key ID to - access objectstore + description: >- + AccessKeyID is a name of key ID to access + objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -1518,43 +1742,57 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: - Enabled is used to indicate wether or not to - deploy a module + description: >- + Enabled is used to indicate wether or not to deploy + a module type: boolean envs: - description: - Envs is the set of environment variables for - the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be a + C_IDENTIFIER. type: string value: - description: |- + description: >- Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: + description: >- Source for the environment variable's value. Cannot be used if value is not empty. properties: @@ -1565,95 +1803,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap or - its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select in - the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: only + resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are currently + supported. properties: containerName: - description: - "Container name: required for volumes, - optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: + description: >- Selects a key of a secret in the pod's namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret or its - key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -1671,17 +1932,19 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy for - the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: + description: >- LeaderElection is boolean flag to enable leader election type: boolean licenseName: - description: LicenseName is the name of the license for app-mobility + description: >- + LicenseName is the name of the license for + app-mobility type: string name: description: Name is the name of Container @@ -1689,14 +1952,17 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true for + the pod to fit on a node. + + Selector which must match a node's labels for the + pod to be scheduled on that node. type: object objectStoreSecretName: - description: - ObjectStoreSecretName is the name of the secret - for the object store for app-mobility + description: >- + ObjectStoreSecretName is the name of the secret for + the object store for app-mobility type: string opa: description: Opa is the image tag for the Container @@ -1705,30 +1971,31 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of the + OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: - ProxyServerIngress is the authorization proxy - server ingress configuration + description: >- + ProxyServerIngress is the authorization proxy server + ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key value - map that stores additional annotations for the ingress + description: >- + Annotations is an unstructured key value map + that stores additional annotations for the + ingress type: object hosts: description: Hosts is the hosts rules for the ingress @@ -1744,9 +2011,9 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: - ProxyServiceReplicas is the number of replicas - for the proxy service deployment + description: >- + ProxyServiceReplicas is the number of replicas for + the proxy service deployment type: integer redis: description: Redis is the image tag for the Container @@ -1758,7 +2025,7 @@ spec: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: + description: >- RedisReplicas is the number of replicas for the redis deployment type: integer @@ -1769,15 +2036,15 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: - RoleServiceReplicas is the number of replicas - for the role service deployment + description: >- + RoleServiceReplicas is the number of replicas for + the role service deployment type: integer sentinel: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: + description: >- skipCertificateValidation is the flag to skip certificate validation type: boolean @@ -1785,73 +2052,99 @@ spec: description: StorageService is the image tag for the Container type: string storageServiceReplicas: - description: - StorageServiceReplicas is the number of replicas - for storage service deployment + description: >- + StorageServiceReplicas is the number of replicas for + storage service deployment type: integer storageclass: - description: - RedisStorageClass is the authorization proxy - server redis storage class for persistence + description: >- + RedisStorageClass is the authorization proxy server + redis storage class for persistence type: string tenantService: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: - TenantServiceReplicas is the number of replicas - for the tenant service deployment + description: >- + TenantServiceReplicas is the number of replicas for + the tenant service deployment type: integer tolerations: - description: + description: >- Tolerations is the list of tolerations for the driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to tolerates + any taint that matches + + the triple using the matching + operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to match. + Empty means match all taint effects. + + When specified, allowed values are NoSchedule, + PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint keys. + + If the key is empty, operator must be Exists; + this combination means to match all values and + all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can + description: >- + Operator represents a key's relationship to + the value. + + Valid operators are Exists and Equal. Defaults + to Equal. + + Exists is equivalent to wildcard for value, so + that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field is + ignored) tolerates the taint. By default, + + it is not set, which means tolerate the taint + forever (do not evict). Zero and + + negative values will be treated as 0 (evict + immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value should be + empty, otherwise just a regular string. type: string type: object type: array useVolumeSnapshot: - description: - UseSnapshot is to check whether volume snapshot - is enabled under velero component + description: >- + UseSnapshot is to check whether volume snapshot is + enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -1859,17 +2152,18 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault certificate + certificate authority for validaitng the vault + certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string @@ -1880,20 +2174,21 @@ spec: description: Role is the role for this vault type: string skipCertificateValidation: - description: - SkipCertificateValidation validates the - vault server certificate or not + description: >- + SkipCertificateValidation validates the vault + server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object replicas: - description: + default: 2 + description: >- Replicas is the count of controllers for Controller plugin format: int32 @@ -1909,22 +2204,23 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag for - the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller + deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: + description: >- CertificateAuthority is a certificate authority used to validate a certificate type: string @@ -1932,39 +2228,39 @@ spec: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: - The interval which the reconcile of each controller - is run + description: >- + The interval which the reconcile of each + controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: - CreateWithInstall is used to indicate - wether or not to create a secret for objectstore + description: >- + CreateWithInstall is used to indicate wether + or not to create a secret for objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: + description: >- SecretContents contains credentials to access objectstore properties: aws_access_key_id: - description: + description: >- AccessKeyID is a name of key ID to access objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -1972,45 +2268,59 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: + description: >- Enabled is used to indicate wether or not to deploy a module type: boolean envs: - description: - Envs is the set of environment variables for - the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be a + C_IDENTIFIER. type: string value: - description: |- + description: >- Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: - Source for the environment variable's - value. Cannot be used if value is not empty. + description: >- + Source for the environment variable's value. + Cannot be used if value is not empty. properties: configMapKeyRef: description: Selects a key of a ConfigMap. @@ -2019,95 +2329,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap - or its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select in - the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: + only resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are + currently supported. properties: containerName: - description: - "Container name: required for - volumes, optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: - Selects a key of a secret in the - pod's namespace + description: >- + Selects a key of a secret in the pod's + namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret or - its key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -2119,7 +2452,7 @@ spec: type: object type: array hostname: - description: + description: >- Hostname is the authorization proxy server hostname type: string @@ -2127,17 +2460,17 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy for - the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: + description: >- LeaderElection is boolean flag to enable leader election type: boolean licenseName: - description: + description: >- LicenseName is the name of the license for app-mobility type: string @@ -2147,12 +2480,15 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true for + the pod to fit on a node. + + Selector which must match a node's labels for the + pod to be scheduled on that node. type: object objectStoreSecretName: - description: + description: >- ObjectStoreSecretName is the name of the secret for the object store for app-mobility type: string @@ -2163,30 +2499,31 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of + the OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: + description: >- ProxyServerIngress is the authorization proxy server ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key value - map that stores additional annotations for the ingress + description: >- + Annotations is an unstructured key value map + that stores additional annotations for the + ingress type: object hosts: description: Hosts is the hosts rules for the ingress @@ -2202,9 +2539,9 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: - ProxyServiceReplicas is the number of replicas - for the proxy service deployment + description: >- + ProxyServiceReplicas is the number of replicas for + the proxy service deployment type: integer redis: description: Redis is the image tag for the Container @@ -2216,9 +2553,9 @@ spec: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: - RedisReplicas is the number of replicas for - the redis deployment + description: >- + RedisReplicas is the number of replicas for the + redis deployment type: integer replicaCount: description: ReplicaCount is the replica count for app mobility @@ -2227,15 +2564,15 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: - RoleServiceReplicas is the number of replicas - for the role service deployment + description: >- + RoleServiceReplicas is the number of replicas for + the role service deployment type: integer sentinel: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: + description: >- skipCertificateValidation is the flag to skip certificate validation type: boolean @@ -2243,12 +2580,12 @@ spec: description: StorageService is the image tag for the Container type: string storageServiceReplicas: - description: + description: >- StorageServiceReplicas is the number of replicas for storage service deployment type: integer storageclass: - description: + description: >- RedisStorageClass is the authorization proxy server redis storage class for persistence type: string @@ -2256,60 +2593,88 @@ spec: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: + description: >- TenantServiceReplicas is the number of replicas for the tenant service deployment type: integer tolerations: - description: - Tolerations is the list of tolerations for - the driver pods + description: >- + Tolerations is the list of tolerations for the + driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to tolerates + any taint that matches + + the triple using the matching + operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to match. + Empty means match all taint effects. + + When specified, allowed values are + NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint + keys. + + If the key is empty, operator must be + Exists; this combination means to match all + values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. + description: >- + Operator represents a key's relationship to + the value. + + Valid operators are Exists and Equal. + Defaults to Equal. + + Exists is equivalent to wildcard for value, + so that a pod can + + tolerate all taints of a particular + category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field is + ignored) tolerates the taint. By default, + + it is not set, which means tolerate the + taint forever (do not evict). Zero and + + negative values will be treated as 0 (evict + immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value should + be empty, otherwise just a regular string. type: string type: object type: array useVolumeSnapshot: - description: - UseSnapshot is to check whether volume snapshot - is enabled under velero component + description: >- + UseSnapshot is to check whether volume snapshot is + enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -2317,39 +2682,38 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault certificate + certificate authority for validaitng the + vault certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string identifier: - description: - Identifier is the identifier for this - vault + description: Identifier is the identifier for this vault type: string role: description: Role is the role for this vault type: string skipCertificateValidation: - description: + description: >- SkipCertificateValidation validates the vault server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object type: array @@ -2364,7 +2728,7 @@ spec: parameters: additionalProperties: type: string - description: + description: >- Parameters is a map of driver specific parameters for snapshot class type: object @@ -2375,14 +2739,16 @@ spec: type: string type: object modules: - description: - Modules is list of Container Storage Module modules you - want to deploy + description: >- + Modules is list of Container Storage Module modules you want + to deploy items: - description: Module defines the desired state of a ContainerStorageModule + description: >- + Module defines the desired state of a + ContainerStorageModule properties: components: - description: + description: >- Components is the specification for CSM components containers items: @@ -2394,22 +2760,23 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag - for the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller + deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: + description: >- CertificateAuthority is a certificate authority used to validate a certificate type: string @@ -2417,39 +2784,40 @@ spec: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: + description: >- The interval which the reconcile of each controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: + description: >- CreateWithInstall is used to indicate - wether or not to create a secret for objectstore + wether or not to create a secret for + objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: - SecretContents contains credentials - to access objectstore + description: >- + SecretContents contains credentials to + access objectstore properties: aws_access_key_id: - description: - AccessKeyID is a name of key ID - to access objectstore + description: >- + AccessKeyID is a name of key ID to + access objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -2457,45 +2825,61 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: - Enabled is used to indicate wether or not - to deploy a module + description: >- + Enabled is used to indicate wether or not to + deploy a module type: boolean envs: - description: - Envs is the set of environment variables - for the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be + a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + description: >- + Variable references $(VAR_NAME) are + expanded + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: + description: >- Source for the environment variable's - value. Cannot be used if value is not empty. + value. Cannot be used if value is not + empty. properties: configMapKeyRef: description: Selects a key of a ConfigMap. @@ -2504,96 +2888,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap - or its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select - in the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: + only resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are + currently supported. properties: containerName: - description: - "Container name: required for - volumes, optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: - Selects a key of a secret in the - pod's namespace + description: >- + Selects a key of a secret in the pod's + namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret - or its key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -2605,7 +3011,7 @@ spec: type: object type: array hostname: - description: + description: >- Hostname is the authorization proxy server hostname type: string @@ -2613,17 +3019,17 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy - for the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: - LeaderElection is boolean flag to enable - leader election + description: >- + LeaderElection is boolean flag to enable leader + election type: boolean licenseName: - description: + description: >- LicenseName is the name of the license for app-mobility type: string @@ -2633,14 +3039,17 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true + for the pod to fit on a node. + + Selector which must match a node's labels for + the pod to be scheduled on that node. type: object objectStoreSecretName: - description: - ObjectStoreSecretName is the name of the - secret for the object store for app-mobility + description: >- + ObjectStoreSecretName is the name of the secret + for the object store for app-mobility type: string opa: description: Opa is the image tag for the Container @@ -2649,30 +3058,30 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of + the OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: + description: >- ProxyServerIngress is the authorization proxy server ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key - value map that stores additional annotations for + description: >- + Annotations is an unstructured key value + map that stores additional annotations for the ingress type: object hosts: @@ -2689,7 +3098,7 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: + description: >- ProxyServiceReplicas is the number of replicas for the proxy service deployment type: integer @@ -2697,18 +3106,20 @@ spec: description: Redis is the image tag for the Container type: string redisCommander: - description: RedisCommander is the name of the redis deployment + description: >- + RedisCommander is the name of the redis + deployment type: string redisName: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: - RedisReplicas is the number of replicas for - the redis deployment + description: >- + RedisReplicas is the number of replicas for the + redis deployment type: integer replicaCount: - description: + description: >- ReplicaCount is the replica count for app mobility type: string @@ -2716,7 +3127,7 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: + description: >- RoleServiceReplicas is the number of replicas for the role service deployment type: integer @@ -2724,20 +3135,22 @@ spec: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: - skipCertificateValidation is the flag to - skip certificate validation + description: >- + skipCertificateValidation is the flag to skip + certificate validation type: boolean storageService: - description: StorageService is the image tag for the Container + description: >- + StorageService is the image tag for the + Container type: string storageServiceReplicas: - description: + description: >- StorageServiceReplicas is the number of replicas for storage service deployment type: integer storageclass: - description: + description: >- RedisStorageClass is the authorization proxy server redis storage class for persistence type: string @@ -2745,60 +3158,92 @@ spec: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: + description: >- TenantServiceReplicas is the number of replicas for the tenant service deployment type: integer tolerations: - description: - Tolerations is the list of tolerations for - the driver pods + description: >- + Tolerations is the list of tolerations for the + driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to + tolerates any taint that matches + + the triple using the + matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to + match. Empty means match all taint + effects. + + When specified, allowed values are + NoSchedule, PreferNoSchedule and + NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint + keys. + + If the key is empty, operator must be + Exists; this combination means to match + all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. + description: >- + Operator represents a key's relationship + to the value. + + Valid operators are Exists and Equal. + Defaults to Equal. + + Exists is equivalent to wildcard for + value, so that a pod can + + tolerate all taints of a particular + category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field + is ignored) tolerates the taint. By + default, + + it is not set, which means tolerate the + taint forever (do not evict). Zero and + + negative values will be treated as 0 + (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value + should be empty, otherwise just a regular + string. type: string type: object type: array useVolumeSnapshot: - description: + description: >- UseSnapshot is to check whether volume snapshot is enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -2806,23 +3251,23 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault - certificate + certificate authority for validaitng the + vault certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string identifier: - description: + description: >- Identifier is the identifier for this vault type: string @@ -2830,36 +3275,39 @@ spec: description: Role is the role for this vault type: string skipCertificateValidation: - description: - SkipCertificateValidation validates - the vault server certificate or not + description: >- + SkipCertificateValidation validates the + vault server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object type: array configVersion: - description: + description: >- ConfigVersion is the configuration version of the module type: string enabled: - description: - Enabled is used to indicate whether or not to deploy - a module + description: >- + Enabled is used to indicate whether or not to deploy a + module type: boolean forceRemoveModule: - description: + description: >- ForceRemoveModule is the boolean flag used to remove - authorization proxy server deployment when CR is deleted + authorization proxy server deployment when CR is + deleted type: boolean initContainer: - description: InitContainer is the specification for Module InitContainer + description: >- + InitContainer is the specification for Module + InitContainer items: description: ContainerTemplate template properties: @@ -2869,22 +3317,23 @@ spec: type: string type: array authorizationController: - description: - AuthorizationController is the image tag - for the container + description: >- + AuthorizationController is the image tag for the + container type: string authorizationControllerReplicas: - description: - AuthorizationControllerReplicas is the number - of replicas for the authorization controller deployment + description: >- + AuthorizationControllerReplicas is the number of + replicas for the authorization controller + deployment type: integer certificate: - description: - Certificate is a certificate used for a certificate/private-key - pair + description: >- + Certificate is a certificate used for a + certificate/private-key pair type: string certificateAuthority: - description: + description: >- CertificateAuthority is a certificate authority used to validate a certificate type: string @@ -2892,39 +3341,40 @@ spec: description: Commander is the image tag for the Container type: string controllerReconcileInterval: - description: + description: >- The interval which the reconcile of each controller is run type: string credentials: - description: + description: >- ComponentCred is to store the velero credential contents items: description: Credential struct properties: createWithInstall: - description: + description: >- CreateWithInstall is used to indicate - wether or not to create a secret for objectstore + wether or not to create a secret for + objectstore type: boolean name: - description: + description: >- Name is the name of secret which contains credentials to access objectstore type: string secretContents: - description: - SecretContents contains credentials - to access objectstore + description: >- + SecretContents contains credentials to + access objectstore properties: aws_access_key_id: - description: - AccessKeyID is a name of key ID - to access objectstore + description: >- + AccessKeyID is a name of key ID to + access objectstore type: string aws_secret_access_key: - description: + description: >- AccessKey contains the key to access objectstore type: string @@ -2932,45 +3382,61 @@ spec: type: object type: array deployNodeAgent: - description: + description: >- DeployNodeAgent is to enable/disable node-agent services type: boolean enabled: - description: - Enabled is used to indicate wether or not - to deploy a module + description: >- + Enabled is used to indicate wether or not to + deploy a module type: boolean envs: - description: - Envs is the set of environment variables - for the container + description: >- + Envs is the set of environment variables for the + container items: - description: + description: >- EnvVar represents an environment variable present in a Container. properties: name: - description: - Name of the environment variable. Must - be a C_IDENTIFIER. + description: >- + Name of the environment variable. Must be + a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable + description: >- + Variable references $(VAR_NAME) are + expanded + + using the previously defined environment + variables in the container and + + any service environment variables. If a + variable cannot be resolved, + + the reference in the input string will be + unchanged. Double $$ are reduced + + to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. + + "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". + + Escaped references will never be expanded, + regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: - description: + description: >- Source for the environment variable's - value. Cannot be used if value is not empty. + value. Cannot be used if value is not + empty. properties: configMapKeyRef: description: Selects a key of a ConfigMap. @@ -2979,96 +3445,118 @@ spec: description: The key to select. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the ConfigMap - or its key must be defined + description: >- + Specify whether the ConfigMap or its key + must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + description: >- + Selects a field of the pod: supports + metadata.name, metadata.namespace, + `metadata.labels['']`, + `metadata.annotations['']`, + + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs. properties: apiVersion: - description: - Version of the schema the FieldPath - is written in terms of, defaults to "v1". + description: >- + Version of the schema the FieldPath is + written in terms of, defaults to "v1". type: string fieldPath: - description: - Path of the field to select - in the specified API version. + description: >- + Path of the field to select in the + specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + description: >- + Selects a resource of the container: + only resources limits and requests + + (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and + requests.ephemeral-storage) are + currently supported. properties: containerName: - description: - "Container name: required for - volumes, optional for env vars" + description: >- + Container name: required for volumes, + optional for env vars type: string divisor: anyOf: - type: integer - type: string - description: - Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + description: >- + Specifies the output format of the + exposed resources, defaults to "1" + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: "Required: resource to select" + description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: - Selects a key of a secret in the - pod's namespace + description: >- + Selects a key of a secret in the pod's + namespace properties: key: - description: - The key of the secret to select - from. Must be a valid secret key. + description: >- + The key of the secret to select from. + Must be a valid secret key. type: string name: - default: "" - description: |- + default: '' + description: >- Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are + + This field is effectively required, but + due to backwards compatibility is + + allowed to be empty. Instances of this + type with an empty value here are + almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + + More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: - Specify whether the Secret - or its key must be defined + description: >- + Specify whether the Secret or its key + must be defined type: boolean required: - key @@ -3080,7 +3568,7 @@ spec: type: object type: array hostname: - description: + description: >- Hostname is the authorization proxy server hostname type: string @@ -3088,17 +3576,17 @@ spec: description: Image is the image tag for the Container type: string imagePullPolicy: - description: - ImagePullPolicy is the image pull policy - for the image + description: >- + ImagePullPolicy is the image pull policy for the + image type: string leaderElection: - description: - LeaderElection is boolean flag to enable - leader election + description: >- + LeaderElection is boolean flag to enable leader + election type: boolean licenseName: - description: + description: >- LicenseName is the name of the license for app-mobility type: string @@ -3108,14 +3596,17 @@ spec: nodeSelector: additionalProperties: type: string - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. + description: >- + NodeSelector is a selector which must be true + for the pod to fit on a node. + + Selector which must match a node's labels for + the pod to be scheduled on that node. type: object objectStoreSecretName: - description: - ObjectStoreSecretName is the name of the - secret for the object store for app-mobility + description: >- + ObjectStoreSecretName is the name of the secret + for the object store for app-mobility type: string opa: description: Opa is the image tag for the Container @@ -3124,30 +3615,30 @@ spec: description: OpaKubeMgmt is the image tag for the Container type: string openTelemetryCollectorAddress: - description: - OpenTelemetryCollectorAddress is the address - of the OTLP receiving endpoint using gRPC + description: >- + OpenTelemetryCollectorAddress is the address of + the OTLP receiving endpoint using gRPC type: string privateKey: - description: - PrivateKey is a private key used for a certificate/private-key - pair + description: >- + PrivateKey is a private key used for a + certificate/private-key pair type: string proxyServerIngress: - description: + description: >- ProxyServerIngress is the authorization proxy server ingress configuration items: - description: + description: >- ProxyServerIngress is the authorization ingress configuration struct properties: annotations: additionalProperties: type: string - description: - Annotations is an unstructured key - value map that stores additional annotations for + description: >- + Annotations is an unstructured key value + map that stores additional annotations for the ingress type: object hosts: @@ -3164,7 +3655,7 @@ spec: description: ProxyService is the image tag for the Container type: string proxyServiceReplicas: - description: + description: >- ProxyServiceReplicas is the number of replicas for the proxy service deployment type: integer @@ -3172,18 +3663,20 @@ spec: description: Redis is the image tag for the Container type: string redisCommander: - description: RedisCommander is the name of the redis deployment + description: >- + RedisCommander is the name of the redis + deployment type: string redisName: description: RedisName is the name of the redis statefulset type: string redisReplicas: - description: - RedisReplicas is the number of replicas for - the redis deployment + description: >- + RedisReplicas is the number of replicas for the + redis deployment type: integer replicaCount: - description: + description: >- ReplicaCount is the replica count for app mobility type: string @@ -3191,7 +3684,7 @@ spec: description: RoleService is the image tag for the Container type: string roleServiceReplicas: - description: + description: >- RoleServiceReplicas is the number of replicas for the role service deployment type: integer @@ -3199,20 +3692,22 @@ spec: description: Sentinel is the name of the sentinel statefulSet type: string skipCertificateValidation: - description: - skipCertificateValidation is the flag to - skip certificate validation + description: >- + skipCertificateValidation is the flag to skip + certificate validation type: boolean storageService: - description: StorageService is the image tag for the Container + description: >- + StorageService is the image tag for the + Container type: string storageServiceReplicas: - description: + description: >- StorageServiceReplicas is the number of replicas for storage service deployment type: integer storageclass: - description: + description: >- RedisStorageClass is the authorization proxy server redis storage class for persistence type: string @@ -3220,60 +3715,92 @@ spec: description: TenantService is the image tag for the Container type: string tenantServiceReplicas: - description: + description: >- TenantServiceReplicas is the number of replicas for the tenant service deployment type: integer tolerations: - description: - Tolerations is the list of tolerations for - the driver pods + description: >- + Tolerations is the list of tolerations for the + driver pods items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . + description: >- + The pod this Toleration is attached to + tolerates any taint that matches + + the triple using the + matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: >- + Effect indicates the taint effect to + match. Empty means match all taint + effects. + + When specified, allowed values are + NoSchedule, PreferNoSchedule and + NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: >- + Key is the taint key that the toleration + applies to. Empty means match all taint + keys. + + If the key is empty, operator must be + Exists; this combination means to match + all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. + description: >- + Operator represents a key's relationship + to the value. + + Valid operators are Exists and Equal. + Defaults to Equal. + + Exists is equivalent to wildcard for + value, so that a pod can + + tolerate all taints of a particular + category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. + description: >- + TolerationSeconds represents the period of + time the toleration (which must be + + of effect NoExecute, otherwise this field + is ignored) tolerates the taint. By + default, + + it is not set, which means tolerate the + taint forever (do not evict). Zero and + + negative values will be treated as 0 + (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. + description: >- + Value is the taint value the toleration + matches to. + + If the operator is Exists, the value + should be empty, otherwise just a regular + string. type: string type: object type: array useVolumeSnapshot: - description: + description: >- UseSnapshot is to check whether volume snapshot is enabled under velero component type: boolean vaultConfigurations: description: Vaults are the vault configurations items: - description: + description: >- Vault is the configuration for a vault instance struct properties: @@ -3281,23 +3808,23 @@ spec: description: Address is the address for this vault type: string certificateAuthority: - description: + description: >- CertificateAuthority is the base64-encoded - certificate authority for validaitng the vault - certificate + certificate authority for validaitng the + vault certificate type: string clientCertificate: - description: + description: >- ClientCertificate is the base64-encoded certificate for connecting to vault type: string clientKey: - description: + description: >- ClientKey validates is the base64-encoded certificate key for connecting to vault type: string identifier: - description: + description: >- Identifier is the identifier for this vault type: string @@ -3305,16 +3832,16 @@ spec: description: Role is the role for this vault type: string skipCertificateValidation: - description: - SkipCertificateValidation validates - the vault server certificate or not + description: >- + SkipCertificateValidation validates the + vault server certificate or not type: boolean type: object type: array veleroNamespace: - description: - VeleroNamespace is the namespace that Velero - is installed in + description: >- + VeleroNamespace is the namespace that Velero is + installed in type: string type: object type: array @@ -3325,7 +3852,7 @@ spec: type: array type: object status: - description: + description: >- ContainerStorageModuleStatus defines the observed state of ContainerStorageModule properties: diff --git a/controllers/csm_controller.go b/controllers/csm_controller.go index 02e68cca..22a9a4b1 100644 --- a/controllers/csm_controller.go +++ b/controllers/csm_controller.go @@ -737,15 +737,15 @@ func (r *ContainerStorageModuleReconciler) SyncCSM(ctx context.Context, cr csmv1 } // Create/Update Reverseproxy Server - if reverseProxyEnabled, _ := utils.IsModuleEnabled(ctx, cr, csmv1.ReverseProxy); reverseProxyEnabled { + if reverseProxyEnabled, _ := utils.IsModuleEnabled(ctx, cr, csmv1.ReverseProxy); reverseProxyEnabled && !modules.IsReverseProxySidecar() { log.Infow("Trying Create/Update reverseproxy...") - if err := r.reconcileReverseProxy(ctx, false, operatorConfig, cr, ctrlClient); err != nil { + if err := r.reconcileReverseProxyServer(ctx, false, operatorConfig, cr, ctrlClient); err != nil { return fmt.Errorf("failed to deploy reverseproxy proxy server: %v", err) } } // Get Driver resources - driverConfig, err := getDriverConfig(ctx, cr, operatorConfig) + driverConfig, err := getDriverConfig(ctx, cr, operatorConfig, ctrlClient) if err != nil { return err } @@ -765,6 +765,25 @@ func (r *ContainerStorageModuleReconciler) SyncCSM(ctx context.Context, cr csmv1 node := driverConfig.Node controller := driverConfig.Controller + if cr.GetDriverType() == csmv1.PowerMax { + if !modules.IsReverseProxySidecar() { + log.Infof("DeployAsSidar is false...csi-reverseproxy should be present as deployement\n") + log.Infof("adding proxy service name...\n") + modules.AddReverseProxyServiceName(&controller.Deployment) + } else { + log.Info("Starting CSI ReverseProxy Service") + if err := modules.ReverseProxyStartService(ctx, false, operatorConfig, cr, ctrlClient); err != nil { + return fmt.Errorf("unable to reconcile reverse-proxy service: %v", err) + } + log.Info("Injecting CSI ReverseProxy") + dp, err := modules.ReverseProxyInjectDeployment(controller.Deployment, cr, operatorConfig) + if err != nil { + return fmt.Errorf("injecting replication into deployment: %v", err) + } + controller.Deployment = *dp + } + } + replicationEnabled, clusterClients, err := utils.GetDefaultClusters(ctx, cr, r) if err != nil { return err @@ -833,13 +852,6 @@ func (r *ContainerStorageModuleReconciler) SyncCSM(ctx context.Context, cr csmv1 } controller.Rbac.ClusterRole = *clusterRole - case csmv1.ReverseProxy: - log.Info("Injecting CSI ReverseProxy") - dp, err := modules.ReverseProxyInjectDeployment(controller.Deployment, cr, operatorConfig) - if err != nil { - return fmt.Errorf("injecting replication into deployment: %v", err) - } - controller.Deployment = *dp } } } @@ -1101,6 +1113,7 @@ func (r *ContainerStorageModuleReconciler) reconcileAppMobility(ctx context.Cont func getDriverConfig(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfig utils.OperatorConfig, + ctrlClient client.Client, ) (*DriverConfig, error) { var ( err error @@ -1135,7 +1148,7 @@ func getDriverConfig(ctx context.Context, return nil, fmt.Errorf("getting %s CSIDriver: %v", driverType, err) } - node, err = drivers.GetNode(ctx, cr, operatorConfig, driverType, NodeYaml) + node, err = drivers.GetNode(ctx, cr, operatorConfig, driverType, NodeYaml, ctrlClient) if err != nil { return nil, fmt.Errorf("getting %s node: %v", driverType, err) } @@ -1153,16 +1166,13 @@ func getDriverConfig(ctx context.Context, }, nil } -// reconcileReverseProxy - deploy reverse proxy server -func (r *ContainerStorageModuleReconciler) reconcileReverseProxy(ctx context.Context, isDeleting bool, op utils.OperatorConfig, cr csmv1.ContainerStorageModule, ctrlClient client.Client) error { +// reconcileReverseProxyServer - deploy reverse proxy server +func (r *ContainerStorageModuleReconciler) reconcileReverseProxyServer(ctx context.Context, isDeleting bool, op utils.OperatorConfig, cr csmv1.ContainerStorageModule, ctrlClient client.Client) error { log := logger.GetLogger(ctx) log.Infow("Reconcile reverseproxy proxy") if err := modules.ReverseProxyServer(ctx, isDeleting, op, cr, ctrlClient); err != nil { return fmt.Errorf("unable to reconcile reverse-proxy server: %v", err) } - if err := modules.ReverseProxyStartService(ctx, isDeleting, op, cr, ctrlClient); err != nil { - return fmt.Errorf("unable to reconcile reverse-proxy service: %v", err) - } return nil } @@ -1250,7 +1260,7 @@ func (r *ContainerStorageModuleReconciler) removeDriver(ctx context.Context, ins log := logger.GetLogger(ctx) // Get Driver resources - driverConfig, err := getDriverConfig(ctx, instance, operatorConfig) + driverConfig, err := getDriverConfig(ctx, instance, operatorConfig, r.Client) if err != nil { log.Error("error in getDriverConfig") return err @@ -1287,6 +1297,12 @@ func (r *ContainerStorageModuleReconciler) removeDriver(ctx context.Context, ins } } + if instance.GetDriverType() == csmv1.PowerMax && modules.IsReverseProxySidecar() { + log.Info("Removing CSI ReverseProxy Service") + if err := modules.ReverseProxyStartService(ctx, true, operatorConfig, instance, cluster.ClusterCTRLClient); err != nil { + return fmt.Errorf("unable to reconcile reverse-proxy service: %v", err) + } + } } return nil @@ -1309,9 +1325,9 @@ func (r *ContainerStorageModuleReconciler) removeModule(ctx context.Context, ins return err } } - if reverseproxyEnabled, _ := utils.IsModuleEnabled(ctx, instance, csmv1.ReverseProxy); reverseproxyEnabled { + if reverseproxyEnabled, _ := utils.IsModuleEnabled(ctx, instance, csmv1.ReverseProxy); reverseproxyEnabled && !modules.IsReverseProxySidecar() { log.Infow("Deleting ReverseProxy") - if err := r.reconcileReverseProxy(ctx, true, operatorConfig, instance, ctrlClient); err != nil { + if err := r.reconcileReverseProxyServer(ctx, true, operatorConfig, instance, ctrlClient); err != nil { return err } } diff --git a/controllers/csm_controller_test.go b/controllers/csm_controller_test.go index ca1ceda0..6a3f1ad7 100644 --- a/controllers/csm_controller_test.go +++ b/controllers/csm_controller_test.go @@ -273,6 +273,17 @@ func (suite *CSMControllerTestSuite) TestReverseProxyReconcile() { suite.runFakeCSMManager("", true) } +func (suite *CSMControllerTestSuite) TestReverseProxySidecarReconcile() { + revProxy := getReverseProxyModule() + deploAsSidecar := corev1.EnvVar{Name: "DeployAsSidecar", Value: "true"} + revProxy[0].Components[0].Envs = append(revProxy[0].Components[0].Envs, deploAsSidecar) + modules.IsReverseProxySidecar = func() bool { return true } + suite.makeFakeRevProxyCSM(csmName, suite.namespace, true, revProxy, string(v1.PowerMax)) + suite.runFakeCSMManager("", false) + suite.deleteCSM(csmName) + suite.runFakeCSMManager("", true) +} + func (suite *CSMControllerTestSuite) TestReverseProxyPreCheckError() { suite.makeFakeRevProxyCSM(csmName, suite.namespace, false, getReverseProxyModule(), "badVersion") reconciler := suite.createReconciler() @@ -287,7 +298,7 @@ func (suite *CSMControllerTestSuite) TestReconcileReverseProxyError() { csm := shared.MakeCSM(csmName, suite.namespace, shared.PmaxConfigVersion) csm.Spec.Modules = getReverseProxyModule() reconciler := suite.createReconciler() - err := reconciler.reconcileReverseProxy(ctx, false, badOperatorConfig, csm, suite.fakeClient) + err := reconciler.reconcileReverseProxyServer(ctx, false, badOperatorConfig, csm, suite.fakeClient) assert.NotNil(suite.T(), err) } @@ -300,7 +311,7 @@ func (suite *CSMControllerTestSuite) TestReconcileReverseProxyServiceError() { reconciler := suite.createReconciler() _ = modules.ReverseProxyPrecheck(ctx, operatorConfig, revProxy[0], csm, reconciler) revProxy[0].ConfigVersion = "" - err := reconciler.reconcileReverseProxy(ctx, false, badOperatorConfig, csm, suite.fakeClient) + err := reconciler.reconcileReverseProxyServer(ctx, false, badOperatorConfig, csm, suite.fakeClient) assert.NotNil(suite.T(), err) } @@ -738,7 +749,8 @@ func (suite *CSMControllerTestSuite) TestRemoveDriver() { csmBadType.Spec.Driver.CSIDriverType = "wrongdriver" csmWoType := shared.MakeCSM(csmName, suite.namespace, configVersion) csm := shared.MakeCSM(csmName, suite.namespace, configVersion) - csm.Spec.Driver.CSIDriverType = "powerscale" + csm.Spec.Driver.CSIDriverType = csmv1.PowerMax + modules.IsReverseProxySidecar = func() bool { return true } removeDriverTests := []struct { name string @@ -801,6 +813,7 @@ func (suite *CSMControllerTestSuite) TestSyncCSM() { appMobCSM.Spec.Modules = getAppMob() reverseProxyServerCSM := shared.MakeCSM(csmName, suite.namespace, configVersion) reverseProxyServerCSM.Spec.Modules = getReverseProxyModule() + modules.IsReverseProxySidecar = func() bool { return false } syncCSMTests := []struct { name string @@ -861,6 +874,9 @@ func (suite *CSMControllerTestSuite) TestRemoveModule() { } *tt.errorInjector = true } + if tt.csm.HasModule(csmv1.ReverseProxy) { + modules.IsReverseProxySidecar = func() bool { return false } + } err := r.removeModule(ctx, tt.csm, operatorConfig, r.Client) if tt.expectedErr == "" { assert.Nil(t, err) @@ -926,7 +942,7 @@ func (suite *CSMControllerTestSuite) TestOldStandAloneModuleCleanup() { if errorInjector != nil { *errorInjector = true } - driverConfig, _ := getDriverConfig(ctx, *csm, operatorConfig) + driverConfig, _ := getDriverConfig(ctx, *csm, operatorConfig, r.Client) err := r.oldStandAloneModuleCleanup(ctx, csm, operatorConfig, driverConfig) if expectedErr == "" { diff --git a/pkg/drivers/common_test.go b/pkg/drivers/common_test.go index d406b6ba..bc79de9b 100644 --- a/pkg/drivers/common_test.go +++ b/pkg/drivers/common_test.go @@ -37,43 +37,56 @@ var ( func csmWithTolerations(driver csmv1.DriverType, version string) csmv1.ContainerStorageModule { res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) - // Add tolerations to controller and node - res.Spec.Driver.Node.Tolerations = []corev1.Toleration{ - { - Key: "notNil", - Value: "123", - TolerationSeconds: new(int64), - }, - { - Key: "nil", - Value: "123", - TolerationSeconds: nil, - }, + // Add tolerations, node selector to controller and node + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Node.Tolerations = []corev1.Toleration{ + { + Key: "notNil", + Value: "123", + TolerationSeconds: new(int64), + }, + { + Key: "nil", + Value: "123", + TolerationSeconds: nil, + }, + } } - res.Spec.Driver.Controller.Tolerations = []corev1.Toleration{ - { - Key: "notNil", - Value: "123", - TolerationSeconds: new(int64), - }, - { - Key: "nil", - Value: "123", - TolerationSeconds: nil, - }, + res.Spec.Driver.Controller = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Controller.Tolerations = []corev1.Toleration{ + { + Key: "notNil", + Value: "123", + TolerationSeconds: new(int64), + }, + { + Key: "nil", + Value: "123", + TolerationSeconds: nil, + }, + } } // Add FSGroupPolicy - res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" - - // Add FSGroupPolicy - res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "ReadWriteOnceWithFSType" + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "ReadWriteOnceWithFSType" + } // Add DNS Policy for GetNode test res.Spec.Driver.DNSPolicy = "ThisIsADNSPolicy" // Add image name - res.Spec.Driver.Common.Image = "thisIsAnImage" + if res.Spec.Driver.Common != nil { + res.Spec.Driver.Common.Image = "thisIsAnImage" + // Add CSI_LOG_LEVEL environment variables + envVar := corev1.EnvVar{Name: "CSI_LOG_LEVEL"} + res.Spec.Driver.Common.Envs = []corev1.EnvVar{envVar} + } // Add pscale driver version res.Spec.Driver.ConfigVersion = version @@ -81,14 +94,6 @@ func csmWithTolerations(driver csmv1.DriverType, version string) csmv1.Container // Add pscale driver type res.Spec.Driver.CSIDriverType = driver - // Add NodeSelector to node and controller - res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - - // Add CSI_LOG_LEVEL environment variables - envVar := corev1.EnvVar{Name: "CSI_LOG_LEVEL"} - res.Spec.Driver.Common.Envs = []corev1.EnvVar{envVar} - // Add sidecars to trigger code in controller sideCarObjEnabledNil := csmv1.ContainerTemplate{ Name: "driver", @@ -116,9 +121,6 @@ func csmWithTolerations(driver csmv1.DriverType, version string) csmv1.Container func csmForPowerFlex(customCSMName string) csmv1.ContainerStorageModule { res := shared.MakeCSM(customCSMName, pFlexNS, shared.PFlexConfigVersion) - // Add driver common image - res.Spec.Driver.Common.Image = "driverimage" - // Add sdc initcontainer res.Spec.Driver.InitContainers = []csmv1.ContainerTemplate{{ Name: "sdc", @@ -146,11 +148,16 @@ func csmForPowerFlex(customCSMName string) csmv1.ContainerStorageModule { // Add pflex driver version res.Spec.Driver.ConfigVersion = shared.PFlexConfigVersion res.Spec.Driver.CSIDriverType = csmv1.PowerFlex - if customCSMName == "no-sdc" { + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} + res.Spec.Driver.Common = &csmv1.ContainerTemplate{} + if customCSMName == "no-sdc" && res.Spec.Driver.Node != nil && res.Spec.Driver.Common != nil { res.Spec.Driver.Node.Envs = append(res.Spec.Driver.Node.Envs, corev1.EnvVar{Name: "X_CSI_SDC_ENABLED", Value: "false"}) res.Spec.Driver.Common.Envs = append(res.Spec.Driver.Common.Envs, corev1.EnvVar{Name: "INTERFACE_NAMES", Value: "worker1: \"interface1\",worker2: \"interface2\""}) } + // Add driver common image + res.Spec.Driver.Common.Image = "driverimage" + return res } @@ -158,8 +165,10 @@ func csmWithPowerstore(driver csmv1.DriverType, version string) csmv1.ContainerS res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) // Add FSGroupPolicy - res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" - + res.Spec.Driver.CSIDriverSpec = &csmv1.CSIDriverSpec{} + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + } // Add DNS Policy for GetNode test res.Spec.Driver.DNSPolicy = "ThisIsADNSPolicy" @@ -172,10 +181,6 @@ func csmWithPowerstore(driver csmv1.DriverType, version string) csmv1.ContainerS // Add pstore driver type res.Spec.Driver.CSIDriverType = driver - // Add NodeSelector to node and controller - res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - // Add node name prefix to cover some code in GetNode nodeNamePrefix := corev1.EnvVar{Name: "X_CSI_POWERSTORE_NODE_NAME_PREFIX"} @@ -187,14 +192,25 @@ func csmWithPowerstore(driver csmv1.DriverType, version string) csmv1.ContainerS enableChap := corev1.EnvVar{Name: "X_CSI_POWERSTORE_ENABLE_CHAP", Value: "true"} healthMonitor := corev1.EnvVar{Name: "X_CSI_HEALTH_MONITOR_ENABLED", Value: "true"} maxVolumesPerNode := corev1.EnvVar{Name: "X_CSI_POWERSTORE_MAX_VOLUMES_PER_NODE", Value: "0"} - res.Spec.Driver.Node.Envs = []corev1.EnvVar{enableChap, healthMonitor, maxVolumesPerNode} + // Add NodeSelector to node and controller + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Node.Envs = []corev1.EnvVar{enableChap, healthMonitor, maxVolumesPerNode} + } // Add controller fields specific nfsAclsParam := corev1.EnvVar{Name: "X_CSI_NFS_ACLS"} externalAccess := corev1.EnvVar{Name: "X_CSI_POWERSTORE_EXTERNAL_ACCESS"} - res.Spec.Driver.Controller.Envs = []corev1.EnvVar{nfsAclsParam, healthMonitor, externalAccess} + res.Spec.Driver.Controller = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Controller.Envs = []corev1.EnvVar{nfsAclsParam, healthMonitor, externalAccess} + } - res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + } return res } @@ -203,7 +219,9 @@ func csmWithPowermax(driver csmv1.DriverType, version string) csmv1.ContainerSto res := shared.MakeCSM("csm", "driver-test", version) // Add FSGroupPolicy - res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "ReadWriteOnceWithFSType" + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "ReadWriteOnceWithFSType" + } // Add DNS Policy for GetNode test res.Spec.Driver.DNSPolicy = "ThisIsADNSPolicy" @@ -218,24 +236,40 @@ func csmWithPowermax(driver csmv1.DriverType, version string) csmv1.ContainerSto res.Spec.Driver.CSIDriverType = driver // Add NodeSelector to node and controller - res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + } + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + } // Add common envs commonEnvs := getPmaxCommonEnvs() - res.Spec.Driver.Common.Envs = commonEnvs + if res.Spec.Driver.Common != nil { + res.Spec.Driver.Common.Envs = commonEnvs + } // Add node fields specific to powermax + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} enableChap := corev1.EnvVar{Name: "X_CSI_POWERMAX_ISCSI_ENABLE_CHAP", Value: "true"} healthMonitor := corev1.EnvVar{Name: "X_CSI_HEALTH_MONITOR_ENABLED", Value: "true"} nodeTopology := corev1.EnvVar{Name: "X_CSI_TOPOLOGY_CONTROL_ENABLED", Value: "true"} - res.Spec.Driver.Node.Envs = []corev1.EnvVar{enableChap, healthMonitor, nodeTopology} + maxVolumes := corev1.EnvVar{Name: "X_CSI_MAX_VOLUMES_PER_NODE", Value: "true"} + + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.Envs = []corev1.EnvVar{enableChap, healthMonitor, nodeTopology, maxVolumes} + } // Add controller fields specific to powermax - res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} + res.Spec.Driver.Controller = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} + } // Add CSI Driver specific fields - res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + } // Add reverseproxy module revproxy := shared.MakeReverseProxyModule(shared.ConfigVersion) @@ -306,9 +340,12 @@ func getPmaxCommonEnvs() []corev1.EnvVar { func csmWithPowerScale(driver csmv1.DriverType, version string) csmv1.ContainerStorageModule { res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) + res.Spec.Driver.CSIDriverSpec = &csmv1.CSIDriverSpec{} // Add FSGroupPolicy - res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + } // Add DNS Policy for GetNode test res.Spec.Driver.DNSPolicy = "ThisIsADNSPolicy" @@ -322,30 +359,41 @@ func csmWithPowerScale(driver csmv1.DriverType, version string) csmv1.ContainerS // Add pscale driver type res.Spec.Driver.CSIDriverType = driver - // Add NodeSelector to node and controller - res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - // Add node name prefix to cover some code in GetNode nodeNamePrefix := corev1.EnvVar{Name: "X_CSI_POWERSTORE_NODE_NAME_PREFIX"} // Add FC port filter fcFilterPath := corev1.EnvVar{Name: "X_CSI_FC_PORTS_FILTER_FILE_PATH"} - res.Spec.Driver.Common.Envs = []corev1.EnvVar{nodeNamePrefix, fcFilterPath} + + if res.Spec.Driver.Common != nil { + res.Spec.Driver.Common.Envs = []corev1.EnvVar{nodeNamePrefix, fcFilterPath} + } // Add environment variable csiLogLevel := corev1.EnvVar{Name: "CSI_LOG_LEVEL", Value: "debug"} - res.Spec.Driver.Node.Envs = []corev1.EnvVar{csiLogLevel} - // Add node fields specific to powerstore healthMonitor := corev1.EnvVar{Name: "X_CSI_HEALTH_MONITOR_ENABLED", Value: "true"} - res.Spec.Driver.Node.Envs = []corev1.EnvVar{healthMonitor} + + // Add node fields specific + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Node.Envs = []corev1.EnvVar{csiLogLevel} + res.Spec.Driver.Node.Envs = []corev1.EnvVar{healthMonitor} + } // Add controller fields specific - res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} + res.Spec.Driver.Controller = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Controller.Envs = []corev1.EnvVar{csiLogLevel} + res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} + } - res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + } // Add sidecars to trigger code in controller sideCarObjEnabledNil := csmv1.ContainerTemplate{ @@ -365,6 +413,10 @@ func csmWithPowerScale(driver csmv1.DriverType, version string) csmv1.ContainerS } sideCarList := []csmv1.ContainerTemplate{sideCarObjEnabledNil, sideCarObjEnabledFalse, sideCarObjEnabledTrue} res.Spec.Driver.SideCars = sideCarList + res.Spec.Modules = []csmv1.Module{{ + Name: csmv1.Resiliency, + Enabled: true, + }} return res } @@ -372,7 +424,11 @@ func csmWithUnity(driver csmv1.DriverType, version string, certProvided bool) cs res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) // Add FSGroupPolicy - res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + res.Spec.Driver.CSIDriverSpec = &csmv1.CSIDriverSpec{} + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "ReadWriteOnceWithFSType" + } // Add DNS Policy for GetNode test res.Spec.Driver.DNSPolicy = "ThisIsADNSPolicy" @@ -387,8 +443,14 @@ func csmWithUnity(driver csmv1.DriverType, version string, certProvided bool) cs res.Spec.Driver.CSIDriverType = driver // Add NodeSelector to node and controller - res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} - res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + } + res.Spec.Driver.Controller = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + } // Add environment variables envVar1 := corev1.EnvVar{Name: "X_CSI_UNITY_ALLOW_MULTI_POD_ACCESS", Value: "false"} @@ -405,11 +467,64 @@ func csmWithUnity(driver csmv1.DriverType, version string, certProvided bool) cs // Add node fields specific to unity healthMonitor := corev1.EnvVar{Name: "X_CSI_HEALTH_MONITOR_ENABLED", Value: "true"} - res.Spec.Driver.Node.Envs = []corev1.EnvVar{healthMonitor} + allowedNetworks := corev1.EnvVar{Name: "X_CSI_ALLOWED_NETWORKS", Value: "true"} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.Envs = []corev1.EnvVar{healthMonitor, allowedNetworks} + } + + // Add controller fields specific + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} + } + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + } + + return res +} + +func csmWithUnityInvalidValue(driver csmv1.DriverType, version string) csmv1.ContainerStorageModule { + res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) + res.Spec.Driver.Common = nil + // Add FSGroupPolicy + res.Spec.Driver.CSIDriverSpec = &csmv1.CSIDriverSpec{} + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.FSGroupPolicy = "File" + } + + // Add DNS Policy for GetNode test + res.Spec.Driver.DNSPolicy = "ThisIsADNSPolicy" + + // Add unity driver version + res.Spec.Driver.ConfigVersion = version + + // Add unity driver type + res.Spec.Driver.CSIDriverType = driver + + // Add NodeSelector to node and controller + res.Spec.Driver.Node = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + } + res.Spec.Driver.Controller = &csmv1.ContainerTemplate{} + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.NodeSelector = map[string]string{"thisIs": "NodeSelector"} + } + + // Add node fields specific to unity + healthMonitor := corev1.EnvVar{Name: "X_CSI_HEALTH_MONITOR_ENABLED", Value: "true"} + allowedNetworks := corev1.EnvVar{Name: "X_CSI_ALLOWED_NETWORKS", Value: "true"} + if res.Spec.Driver.Node != nil { + res.Spec.Driver.Node.Envs = []corev1.EnvVar{healthMonitor, allowedNetworks} + } // Add controller fields specific - res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} - res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + if res.Spec.Driver.Controller != nil { + res.Spec.Driver.Controller.Envs = []corev1.EnvVar{healthMonitor} + } + if res.Spec.Driver.CSIDriverSpec != nil { + res.Spec.Driver.CSIDriverSpec.StorageCapacity = true + } return res } diff --git a/pkg/drivers/commonconfig.go b/pkg/drivers/commonconfig.go index 95d7552d..be2a3946 100644 --- a/pkg/drivers/commonconfig.go +++ b/pkg/drivers/commonconfig.go @@ -27,6 +27,7 @@ import ( storagev1 "k8s.io/api/storage/v1" acorev1 "k8s.io/client-go/applyconfigurations/core/v1" metacv1 "k8s.io/client-go/applyconfigurations/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" ) @@ -71,12 +72,8 @@ func GetController(ctx context.Context, cr csmv1.ContainerStorageModule, operato controllerYAML := driverYAML.(utils.ControllerYAML) controllerYAML.Deployment.Spec.Replicas = &cr.Spec.Driver.Replicas - var defaultReplicas int32 = 2 - if *(controllerYAML.Deployment.Spec.Replicas) == 0 { - controllerYAML.Deployment.Spec.Replicas = &defaultReplicas - } - if len(cr.Spec.Driver.Controller.Tolerations) != 0 { + if cr.Spec.Driver.Controller != nil && len(cr.Spec.Driver.Controller.Tolerations) != 0 { tols := make([]acorev1.TolerationApplyConfiguration, 0) for _, t := range cr.Spec.Driver.Controller.Tolerations { log.Debugw("Adding toleration", "t", t) @@ -94,19 +91,22 @@ func GetController(ctx context.Context, cr csmv1.ContainerStorageModule, operato controllerYAML.Deployment.Spec.Template.Spec.Tolerations = tols } - if cr.Spec.Driver.Controller.NodeSelector != nil { + if cr.Spec.Driver.Controller != nil && cr.Spec.Driver.Controller.NodeSelector != nil { controllerYAML.Deployment.Spec.Template.Spec.NodeSelector = cr.Spec.Driver.Controller.NodeSelector } containers := controllerYAML.Deployment.Spec.Template.Spec.Containers newcontainers := make([]acorev1.ContainerApplyConfiguration, 0) for i, c := range containers { - if string(*c.Name) == "driver" { - containers[i].Env = utils.ReplaceAllApplyCustomEnvs(c.Env, cr.Spec.Driver.Common.Envs, cr.Spec.Driver.Controller.Envs) - c.Env = containers[i].Env - if string(cr.Spec.Driver.Common.Image) != "" { - image := string(cr.Spec.Driver.Common.Image) - c.Image = &image + if c.Name != nil && string(*c.Name) == "driver" { + // Check if Common is not nil before accessing Envs + if cr.Spec.Driver.Common != nil && cr.Spec.Driver.Controller != nil { + containers[i].Env = utils.ReplaceAllApplyCustomEnvs(c.Env, cr.Spec.Driver.Common.Envs, cr.Spec.Driver.Controller.Envs) + c.Env = containers[i].Env + if string(cr.Spec.Driver.Common.Image) != "" { + image := string(cr.Spec.Driver.Common.Image) + c.Image = &image + } } } @@ -189,7 +189,7 @@ func GetController(ctx context.Context, cr csmv1.ContainerStorageModule, operato } // GetNode get node yaml -func GetNode(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfig utils.OperatorConfig, driverType csmv1.DriverType, filename string) (*utils.NodeYAML, error) { +func GetNode(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfig utils.OperatorConfig, driverType csmv1.DriverType, filename string, ct client.Client) (*utils.NodeYAML, error) { log := logger.GetLogger(ctx) configMapPath := fmt.Sprintf("%s/driverconfig/%s/%s/%s", operatorConfig.ConfigDirectory, driverType, cr.Spec.Driver.ConfigVersion, filename) log.Debugw("GetNode", "configMapPath", configMapPath) @@ -233,7 +233,7 @@ func GetNode(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfi nodeYaml.DaemonSetApplyConfig.Spec.Template.Spec.DNSPolicy = &defaultDNSPolicy } - if len(cr.Spec.Driver.Node.Tolerations) != 0 { + if cr.Spec.Driver.Node != nil && len(cr.Spec.Driver.Node.Tolerations) != 0 { tols := make([]acorev1.TolerationApplyConfiguration, 0) for _, t := range cr.Spec.Driver.Node.Tolerations { fmt.Printf("[BRUH] toleration t: %+v\n", t) @@ -251,19 +251,22 @@ func GetNode(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfi nodeYaml.DaemonSetApplyConfig.Spec.Template.Spec.Tolerations = tols } - if cr.Spec.Driver.Node.NodeSelector != nil { + if cr.Spec.Driver.Node != nil && cr.Spec.Driver.Node.NodeSelector != nil { nodeYaml.DaemonSetApplyConfig.Spec.Template.Spec.NodeSelector = cr.Spec.Driver.Node.NodeSelector } containers := nodeYaml.DaemonSetApplyConfig.Spec.Template.Spec.Containers newcontainers := make([]acorev1.ContainerApplyConfiguration, 0) for i, c := range containers { - if string(*c.Name) == "driver" { - containers[i].Env = utils.ReplaceAllApplyCustomEnvs(c.Env, cr.Spec.Driver.Common.Envs, cr.Spec.Driver.Node.Envs) - c.Env = containers[i].Env - if string(cr.Spec.Driver.Common.Image) != "" { - image := string(cr.Spec.Driver.Common.Image) - c.Image = &image + if c.Name != nil && string(*c.Name) == "driver" { + // Check if Common is not nil before accessing its fields + if cr.Spec.Driver.Common != nil && cr.Spec.Driver.Node != nil { + containers[i].Env = utils.ReplaceAllApplyCustomEnvs(c.Env, cr.Spec.Driver.Common.Envs, cr.Spec.Driver.Node.Envs) + c.Env = containers[i].Env + if string(cr.Spec.Driver.Common.Image) != "" { + image := string(cr.Spec.Driver.Common.Image) + c.Image = &image + } } } removeContainer := false @@ -299,11 +302,22 @@ func GetNode(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfi nodeYaml.DaemonSetApplyConfig.Spec.Template.Spec.Containers = newcontainers + var updatedCr csmv1.ContainerStorageModule + if cr.Spec.Driver.CSIDriverType == "powerflex" { + updatedCr, err = SetSDCinitContainers(ctx, cr, ct) + if err != nil { + log.Errorw("Failed to set SDC init container", "Error", err.Error()) + return nil, err + } + } + initcontainers := make([]acorev1.ContainerApplyConfiguration, 0) sdcEnabled := true - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_SDC_ENABLED" && env.Value == "false" { - sdcEnabled = false + if updatedCr.Spec.Driver.Node != nil { + for _, env := range updatedCr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_SDC_ENABLED" && env.Value == "false" { + sdcEnabled = false + } } } for _, ic := range nodeYaml.DaemonSetApplyConfig.Spec.Template.Spec.InitContainers { @@ -314,7 +328,7 @@ func GetNode(ctx context.Context, cr csmv1.ContainerStorageModule, operatorConfi for i := range initcontainers { utils.ReplaceAllContainerImageApply(operatorConfig.K8sVersion, &initcontainers[i]) - utils.UpdateInitContainerApply(cr.Spec.Driver.InitContainers, &initcontainers[i]) + utils.UpdateInitContainerApply(updatedCr.Spec.Driver.InitContainers, &initcontainers[i]) // mdm-container is exclusive to powerflex driver deamonset, will use the driver image as an init container if *initcontainers[i].Name == "mdm-container" { if string(cr.Spec.Driver.Common.Image) != "" { @@ -402,14 +416,16 @@ func GetConfigMap(ctx context.Context, cr csmv1.ContainerStorageModule, operator return nil, err } - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "CSI_LOG_LEVEL" { - cmValue += fmt.Sprintf("\n%s: %s", env.Name, env.Value) - podmanLogLevel = env.Value - } - if env.Name == "CSI_LOG_FORMAT" { - cmValue += fmt.Sprintf("\n%s: %s", env.Name, env.Value) - podmanLogFormat = env.Value + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "CSI_LOG_LEVEL" { + cmValue += fmt.Sprintf("\n%s: %s", env.Name, env.Value) + podmanLogLevel = env.Value + } + if env.Name == "CSI_LOG_FORMAT" { + cmValue += fmt.Sprintf("\n%s: %s", env.Name, env.Value) + podmanLogFormat = env.Value + } } } @@ -425,11 +441,13 @@ func GetConfigMap(ctx context.Context, cr csmv1.ContainerStorageModule, operator } if cr.Spec.Driver.CSIDriverType == "powerflex" { - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "INTERFACE_NAMES" { - cmValue += fmt.Sprintf("\n%s: ", "interfaceNames") - for _, v := range strings.Split(env.Value, ",") { - cmValue += fmt.Sprintf("\n %s ", v) + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "INTERFACE_NAMES" { + cmValue += fmt.Sprintf("\n%s: ", "interfaceNames") + for _, v := range strings.Split(env.Value, ",") { + cmValue += fmt.Sprintf("\n %s ", v) + } } } } @@ -478,11 +496,12 @@ func GetCSIDriver(ctx context.Context, cr csmv1.ContainerStorageModule, operator return nil, err } // overriding default FSGroupPolicy if this was provided in manifest - if cr.Spec.Driver.CSIDriverSpec.FSGroupPolicy != "" { + if cr.Spec.Driver.CSIDriverSpec != nil && cr.Spec.Driver.CSIDriverSpec.FSGroupPolicy != "" { fsGroupPolicy := storagev1.NoneFSGroupPolicy - if cr.Spec.Driver.CSIDriverSpec.FSGroupPolicy == "ReadWriteOnceWithFSType" { + switch cr.Spec.Driver.CSIDriverSpec.FSGroupPolicy { + case "ReadWriteOnceWithFSType": fsGroupPolicy = storagev1.ReadWriteOnceWithFSTypeFSGroupPolicy - } else if cr.Spec.Driver.CSIDriverSpec.FSGroupPolicy == "File" { + case "File": fsGroupPolicy = storagev1.FileFSGroupPolicy } csidriver.Spec.FSGroupPolicy = &fsGroupPolicy diff --git a/pkg/drivers/commonconfig_test.go b/pkg/drivers/commonconfig_test.go index 4bad1828..6e85ce50 100644 --- a/pkg/drivers/commonconfig_test.go +++ b/pkg/drivers/commonconfig_test.go @@ -20,6 +20,7 @@ import ( "github.com/dell/csm-operator/tests/shared" "github.com/stretchr/testify/assert" storagev1 "k8s.io/api/storage/v1" + ctrlClientFake "sigs.k8s.io/controller-runtime/pkg/client/fake" ) var ( @@ -29,6 +30,7 @@ var ( pScaleCSM = csmWithPowerScale(csmv1.PowerScale, shared.PScaleConfigVersion) unityCSM = csmWithUnity(csmv1.Unity, shared.UnityConfigVersion, false) unityCSMCertProvided = csmWithUnity(csmv1.Unity, shared.UnityConfigVersion, true) + unityCSMInvalidValue = csmWithUnityInvalidValue(csmv1.Unity, shared.UnityConfigVersion) pmaxCSM = csmWithPowermax(csmv1.PowerMax, shared.PmaxConfigVersion) fakeDriver csmv1.DriverType = "fakeDriver" @@ -53,6 +55,7 @@ var ( {"pstore happy path", pStoreCSM, csmv1.PowerStore, "node.yaml", ""}, {"unity happy path", unityCSM, csmv1.Unity, "node.yaml", ""}, {"unity happy path when secrets with certificates provided", unityCSMCertProvided, csmv1.Unity, "node.yaml", ""}, + {"unity common is nil", unityCSMInvalidValue, csmv1.Unity, "node.yaml", ""}, {"file does not exist", csm, fakeDriver, "NonExist.yaml", "no such file or directory"}, {"pmax happy path", pmaxCSM, csmv1.PowerMax, "node.yaml", ""}, {"config file is invalid", csm, badDriver, "bad.yaml", "unmarshal"}, @@ -66,15 +69,17 @@ func TestGetCsiDriver(t *testing.T) { csiDriver, err := GetCSIDriver(ctx, tt.csm, config, tt.driverName) if tt.expectedErr == "" { assert.Nil(t, err) - switch tt.csm.Spec.Driver.CSIDriverSpec.FSGroupPolicy { - case "": - assert.Equal(t, storagev1.ReadWriteOnceWithFSTypeFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) - case "ReadWriteOnceWithFSType": - assert.Equal(t, storagev1.ReadWriteOnceWithFSTypeFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) - case "File": - assert.Equal(t, storagev1.FileFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) - default: - assert.Equal(t, storagev1.NoneFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) + if tt.csm.Spec.Driver.CSIDriverSpec != nil { + switch tt.csm.Spec.Driver.CSIDriverSpec.FSGroupPolicy { + case "": + assert.Equal(t, storagev1.ReadWriteOnceWithFSTypeFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) + case "ReadWriteOnceWithFSType": + assert.Equal(t, storagev1.ReadWriteOnceWithFSTypeFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) + case "File": + assert.Equal(t, storagev1.FileFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) + default: + assert.Equal(t, storagev1.NoneFSGroupPolicy, *csiDriver.Spec.FSGroupPolicy) + } } } else { assert.Containsf(t, err.Error(), tt.expectedErr, "expected error containing %q, got %s", tt.expectedErr, err) @@ -130,7 +135,7 @@ func TestGetNode(t *testing.T) { foundInitMdm := false for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - node, err := GetNode(ctx, tt.csm, config, tt.driverName, tt.filename) + node, err := GetNode(ctx, tt.csm, config, tt.driverName, tt.filename, ctrlClientFake.NewClientBuilder().Build()) if tt.expectedErr == "" { assert.Nil(t, err) initcontainers := node.DaemonSetApplyConfig.Spec.Template.Spec.InitContainers diff --git a/pkg/drivers/powerflex.go b/pkg/drivers/powerflex.go index 419459d6..3b7e77fe 100644 --- a/pkg/drivers/powerflex.go +++ b/pkg/drivers/powerflex.go @@ -71,96 +71,95 @@ func PrecheckPowerFlex(ctx context.Context, cr *csmv1.ContainerStorageModule, op return fmt.Errorf("%s %s not supported", csmv1.PowerFlexName, cr.Spec.Driver.ConfigVersion) } - mdmVar, err := GetMDMFromSecret(ctx, cr, ct) + // Check if MDM is set in the secret + _, err := GetMDMFromSecret(ctx, cr, ct) if err != nil { return err } - var newmdm corev1.EnvVar + + return nil +} + +func SetSDCinitContainers(ctx context.Context, cr csmv1.ContainerStorageModule, ct client.Client) (csmv1.ContainerStorageModule, error) { + mdmVar, _ := GetMDMFromSecret(ctx, &cr, ct) + + // Check if SDC is enabled sdcEnabled := true - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_SDC_ENABLED" && env.Value == "false" { - sdcEnabled = false + if cr.Spec.Driver.Node != nil { + for _, env := range cr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_SDC_ENABLED" && env.Value == "false" { + sdcEnabled = false + break + } } } - newInitContainers := make([]csmv1.ContainerTemplate, 0) + // Update init containers + var newInitContainers []csmv1.ContainerTemplate for _, initcontainer := range cr.Spec.Driver.InitContainers { - if initcontainer.Name != "sdc" { - newInitContainers = append(newInitContainers, initcontainer) - } else if initcontainer.Name == "sdc" && sdcEnabled { - k := 0 - initenv := initcontainer.Envs - for c, env := range initenv { + if initcontainer.Name == "sdc" && sdcEnabled { + // Ensure MDM env variable is set + mdmUpdated := false + for i, env := range initcontainer.Envs { if env.Name == "MDM" { - env.Value = mdmVar - newmdm = env - k = c + initcontainer.Envs[i].Value = mdmVar + mdmUpdated = true break } } - initenv[k] = newmdm - newInitContainers = append(newInitContainers, initcontainer) + // If MDM not found, update it from secret + if !mdmUpdated { + initcontainer.Envs = append(initcontainer.Envs, corev1.EnvVar{ + Name: "MDM", + Value: mdmVar, + }) + } } + newInitContainers = append(newInitContainers, initcontainer) } - cr.Spec.Driver.InitContainers = newInitContainers - if len(cr.Spec.Driver.InitContainers) == 0 && sdcEnabled { - cr.Spec.Driver.InitContainers = []csmv1.ContainerTemplate{ - { - Name: "sdc", - Envs: []corev1.EnvVar{ - { - Name: "MDM", - Value: mdmVar, - }, - }, - }, - } + + // If there is no init containers and SDC is enabled, add a sdc init container + if len(newInitContainers) == 0 && sdcEnabled { + newInitContainers = append(newInitContainers, csmv1.ContainerTemplate{ + Name: "sdc", + Envs: []corev1.EnvVar{{Name: "MDM", Value: mdmVar}}, + }) } + cr.Spec.Driver.InitContainers = newInitContainers - for _, sidecar := range cr.Spec.Driver.SideCars { - if sidecar.Name == "sdc-monitor" { - sidenv := sidecar.Envs - var updatenv corev1.EnvVar - j := 0 - for c, env := range sidenv { + // Update sidecar containers + for i := range cr.Spec.Driver.SideCars { + if cr.Spec.Driver.SideCars[i].Name == "sdc-monitor" { + // Ensure MDM env variable is set + mdmUpdated := false + for j, env := range cr.Spec.Driver.SideCars[i].Envs { if env.Name == "MDM" { - env.Value = mdmVar - updatenv = env - j = c + cr.Spec.Driver.SideCars[i].Envs[j].Value = mdmVar + mdmUpdated = true break } } - sidenv[j] = updatenv + // If MDM not found, update it from secret + if !mdmUpdated { + cr.Spec.Driver.SideCars[i].Envs = append(cr.Spec.Driver.SideCars[i].Envs, corev1.EnvVar{ + Name: "MDM", + Value: mdmVar, + }) + } } } - if cr.Spec.Driver.SideCars == nil { + + // If no sidecars are present, add a new "sdc-monitor" sidecar with MDM + if len(cr.Spec.Driver.SideCars) == 0 { cr.Spec.Driver.SideCars = []csmv1.ContainerTemplate{ { Name: "sdc-monitor", - Envs: []corev1.EnvVar{ - { - Name: "MDM", - Value: mdmVar, - }, - }, + Envs: []corev1.EnvVar{{Name: "MDM", Value: mdmVar}}, }, } } - kubeletConfigDirFound := false - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "KUBELET_CONFIG_DIR" { - kubeletConfigDirFound = true - } - } - if !kubeletConfigDirFound { - cr.Spec.Driver.Common.Envs = append(cr.Spec.Driver.Common.Envs, corev1.EnvVar{ - Name: "KUBELET_CONFIG_DIR", - Value: "/var/lib/kubelet", - }) - } - - return nil + return cr, nil } // GetMDMFromSecret - Get MDM value from secret @@ -291,15 +290,17 @@ func ModifyPowerflexCR(yamlString string, cr csmv1.ContainerStorageModule, fileT // nolint:gosec switch fileType { case "Controller": - for _, env := range cr.Spec.Driver.Controller.Envs { - if env.Name == "X_CSI_POWERFLEX_EXTERNAL_ACCESS" { - powerflexExternalAccess = env.Value - } - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorController = env.Value - } - if env.Name == "X_CSI_DEBUG" { - csiDebug = env.Value + if cr.Spec.Driver.Controller != nil { + for _, env := range cr.Spec.Driver.Controller.Envs { + if env.Name == "X_CSI_POWERFLEX_EXTERNAL_ACCESS" { + powerflexExternalAccess = env.Value + } + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorController = env.Value + } + if env.Name == "X_CSI_DEBUG" { + csiDebug = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorController) @@ -307,27 +308,29 @@ func ModifyPowerflexCR(yamlString string, cr csmv1.ContainerStorageModule, fileT yamlString = strings.ReplaceAll(yamlString, CsiDebug, csiDebug) case "Node": - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_SDC_ENABLED" { - sdcEnabled = env.Value - } - if env.Name == "X_CSI_APPROVE_SDC_ENABLED" { - approveSdcEnabled = env.Value - } - if env.Name == "X_CSI_RENAME_SDC_ENABLED" { - renameSdcEnabled = env.Value - } - if env.Name == "X_CSI_RENAME_SDC_PREFIX" { - renameSdcPrefix = env.Value - } - if env.Name == "X_CSI_MAX_VOLUMES_PER_NODE" { - maxVolumesPerNode = env.Value - } - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorNode = env.Value - } - if env.Name == "X_CSI_DEBUG" { - csiDebug = env.Value + if cr.Spec.Driver.Node != nil { + for _, env := range cr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_SDC_ENABLED" { + sdcEnabled = env.Value + } + if env.Name == "X_CSI_APPROVE_SDC_ENABLED" { + approveSdcEnabled = env.Value + } + if env.Name == "X_CSI_RENAME_SDC_ENABLED" { + renameSdcEnabled = env.Value + } + if env.Name == "X_CSI_RENAME_SDC_PREFIX" { + renameSdcPrefix = env.Value + } + if env.Name == "X_CSI_MAX_VOLUMES_PER_NODE" { + maxVolumesPerNode = env.Value + } + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorNode = env.Value + } + if env.Name == "X_CSI_DEBUG" { + csiDebug = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiSdcEnabled, sdcEnabled) @@ -339,7 +342,7 @@ func ModifyPowerflexCR(yamlString string, cr csmv1.ContainerStorageModule, fileT yamlString = strings.ReplaceAll(yamlString, CsiDebug, csiDebug) case "CSIDriverSpec": - if cr.Spec.Driver.CSIDriverSpec.StorageCapacity { + if cr.Spec.Driver.CSIDriverSpec != nil && cr.Spec.Driver.CSIDriverSpec.StorageCapacity { storageCapacity = "true" } yamlString = strings.ReplaceAll(yamlString, CsiStorageCapacityEnabled, storageCapacity) diff --git a/pkg/drivers/powerflex_test.go b/pkg/drivers/powerflex_test.go index 6deb8ddd..b1046af1 100644 --- a/pkg/drivers/powerflex_test.go +++ b/pkg/drivers/powerflex_test.go @@ -58,6 +58,7 @@ var ( }{ {"missing secret", powerFlexCSM, powerFlexClient, fakeSecret, "no secrets found"}, {"happy path", powerFlexCSM, powerFlexClient, powerFlexSecret, ""}, + {"happy path with initContainers but no MDM", csmForPowerFlex("no-mdm"), powerFlexClient, shared.MakeSecretWithJSON("no-mdm-config", pFlexNS, configJSONFileGood), ""}, {"happy path without sdc", csmForPowerFlex("no-sdc"), powerFlexClient, shared.MakeSecretWithJSON("no-sdc-config", pFlexNS, configJSONFileGood), ""}, {"bad version", powerFlexCSMBadVersion, powerFlexClient, powerFlexSecret, "not supported"}, {"bad username", csmForPowerFlex("bad-user"), powerFlexClient, shared.MakeSecretWithJSON("bad-user-config", pFlexNS, configJSONFileBadUser), "invalid value for Username"}, @@ -84,7 +85,7 @@ var ( cr: csmv1.ContainerStorageModule{ Spec: csmv1.ContainerStorageModuleSpec{ Driver: csmv1.Driver{ - Controller: csmv1.ContainerTemplate{ + Controller: &csmv1.ContainerTemplate{ Envs: []corev1.EnvVar{ {Name: "X_CSI_POWERFLEX_EXTERNAL_ACCESS", Value: "NEW_POWERFLEX_ACCESS"}, {Name: "X_CSI_HEALTH_MONITOR_ENABLED", Value: "NEW_HEALTH_MONITOR"}, @@ -103,7 +104,7 @@ var ( cr: csmv1.ContainerStorageModule{ Spec: csmv1.ContainerStorageModuleSpec{ Driver: csmv1.Driver{ - Node: csmv1.ContainerTemplate{ + Node: &csmv1.ContainerTemplate{ Envs: []corev1.EnvVar{ {Name: "X_CSI_SDC_ENABLED", Value: "NEW_SDC_ENABLED"}, {Name: "X_CSI_APPROVE_SDC_ENABLED", Value: "NEW_APPROVE_SDC"}, @@ -126,7 +127,7 @@ var ( cr: csmv1.ContainerStorageModule{ Spec: csmv1.ContainerStorageModuleSpec{ Driver: csmv1.Driver{ - CSIDriverSpec: csmv1.CSIDriverSpec{ + CSIDriverSpec: &csmv1.CSIDriverSpec{ StorageCapacity: true, }, }, @@ -141,7 +142,7 @@ var ( cr: csmv1.ContainerStorageModule{ Spec: csmv1.ContainerStorageModuleSpec{ Driver: csmv1.Driver{ - CSIDriverSpec: csmv1.CSIDriverSpec{ + CSIDriverSpec: &csmv1.CSIDriverSpec{ StorageCapacity: false, }, }, diff --git a/pkg/drivers/powermax.go b/pkg/drivers/powermax.go index 72422629..105fe2c4 100644 --- a/pkg/drivers/powermax.go +++ b/pkg/drivers/powermax.go @@ -85,60 +85,14 @@ func PrecheckPowerMax(ctx context.Context, cr *csmv1.ContainerStorageModule, ope } } } - kubeletConfigDirFound := false - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "KUBELET_CONFIG_DIR" { - kubeletConfigDirFound = true - } - } - if !kubeletConfigDirFound { - cr.Spec.Driver.Common.Envs = append(cr.Spec.Driver.Common.Envs, corev1.EnvVar{ - Name: "KUBELET_CONFIG_DIR", - Value: "/var/lib/kubelet", - }) - } - foundRevProxy := false for i, mod := range cr.Spec.Modules { if mod.Name == csmv1.ReverseProxy { - foundRevProxy = true cr.Spec.Modules[i].Enabled = true cr.Spec.Modules[i].ForceRemoveModule = true break } } - if !foundRevProxy { - // if we are here then it's minimal yaml - log.Infof("Reverse proxy module not found adding it with default config") - components := make([]csmv1.ContainerTemplate, 0) - components = append(components, csmv1.ContainerTemplate{ - Name: "csipowermax-reverseproxy", - }) - - components[0].Envs = append(components[0].Envs, corev1.EnvVar{ - Name: "X_CSI_REVPROXY_TLS_SECRET", - Value: "csirevproxy-tls-secret", - }) - components[0].Envs = append(components[0].Envs, corev1.EnvVar{ - Name: "X_CSI_REVPROXY_PORT", - Value: "2222", - }) - components[0].Envs = append(components[0].Envs, corev1.EnvVar{ - Name: "X_CSI_CONFIG_MAP_NAME", - Value: "powermax-reverseproxy-config", - }) - components[0].Envs = append(components[0].Envs, corev1.EnvVar{ - Name: "DeployAsSidecar", - Value: "true", - }) - - cr.Spec.Modules = append(cr.Spec.Modules, csmv1.Module{ - Name: csmv1.ReverseProxy, - Enabled: true, - ForceRemoveModule: true, - Components: components, - }) - } log.Debugw("preCheck", "secrets", cred) return nil @@ -169,59 +123,63 @@ func ModifyPowermaxCR(yamlString string, cr csmv1.ContainerStorageModule, fileTy // #nosec G101 - False positives switch fileType { case "Node": - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_MANAGED_ARRAYS" { - managedArray = env.Value - } - if env.Name == "X_CSI_POWERMAX_ENDPOINT" { - endpoint = env.Value - } - if env.Name == "X_CSI_K8S_CLUSTER_PREFIX" { - clusterPrefix = env.Value - } - if env.Name == "X_CSI_POWERMAX_DEBUG" { - debug = env.Value - } - if env.Name == "X_CSI_POWERMAX_PORTGROUPS" { - portGroup = env.Value - } - if env.Name == "X_CSI_TRANSPORT_PROTOCOL" { - protocol = env.Value - } - if env.Name == "X_CSI_VSPHERE_ENABLED" { - vsphereEnabled = env.Value - } - if env.Name == "X_CSI_VSPHERE_PORTGROUP" { - vspherePG = env.Value - } - if env.Name == "X_CSI_VSPHERE_HOSTNAME" { - vsphereHostname = env.Value - } - if env.Name == "X_CSI_VCENTER_HOST" { - vsphereHost = env.Value - } - if env.Name == "X_CSI_VSPHERE_ENABLED" { - vsphereEnabled = env.Value - } - if env.Name == "X_CSI_IG_MODIFY_HOSTNAME" { - modifyHostname = env.Value - } - if env.Name == "X_CSI_IG_NODENAME_TEMPLATE" { - nodeTemplate = env.Value + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_MANAGED_ARRAYS" { + managedArray = env.Value + } + if env.Name == "X_CSI_POWERMAX_ENDPOINT" { + endpoint = env.Value + } + if env.Name == "X_CSI_K8S_CLUSTER_PREFIX" { + clusterPrefix = env.Value + } + if env.Name == "X_CSI_POWERMAX_DEBUG" { + debug = env.Value + } + if env.Name == "X_CSI_POWERMAX_PORTGROUPS" { + portGroup = env.Value + } + if env.Name == "X_CSI_TRANSPORT_PROTOCOL" { + protocol = env.Value + } + if env.Name == "X_CSI_VSPHERE_ENABLED" { + vsphereEnabled = env.Value + } + if env.Name == "X_CSI_VSPHERE_PORTGROUP" { + vspherePG = env.Value + } + if env.Name == "X_CSI_VSPHERE_HOSTNAME" { + vsphereHostname = env.Value + } + if env.Name == "X_CSI_VCENTER_HOST" { + vsphereHost = env.Value + } + if env.Name == "X_CSI_VSPHERE_ENABLED" { + vsphereEnabled = env.Value + } + if env.Name == "X_CSI_IG_MODIFY_HOSTNAME" { + modifyHostname = env.Value + } + if env.Name == "X_CSI_IG_NODENAME_TEMPLATE" { + nodeTemplate = env.Value + } } } - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - nodeHealthMonitor = env.Value - } - if env.Name == "X_CSI_POWERMAX_ISCSI_ENABLE_CHAP" { - nodeChap = env.Value - } - if env.Name == "X_CSI_TOPOLOGY_CONTROL_ENABLED" { - nodeTopology = env.Value - } - if env.Name == "X_CSI_MAX_VOLUMES_PER_NODE" { - maxVolumesPerNode = env.Value + if cr.Spec.Driver.Node != nil { + for _, env := range cr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + nodeHealthMonitor = env.Value + } + if env.Name == "X_CSI_POWERMAX_ISCSI_ENABLE_CHAP" { + nodeChap = env.Value + } + if env.Name == "X_CSI_TOPOLOGY_CONTROL_ENABLED" { + nodeTopology = env.Value + } + if env.Name == "X_CSI_MAX_VOLUMES_PER_NODE" { + maxVolumesPerNode = env.Value + } } } @@ -242,47 +200,51 @@ func ModifyPowermaxCR(yamlString string, cr csmv1.ContainerStorageModule, fileTy yamlString = strings.ReplaceAll(yamlString, CSIPmaxChap, nodeChap) yamlString = strings.ReplaceAll(yamlString, CsiPmaxMaxVolumesPerNode, maxVolumesPerNode) case "Controller": - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_MANAGED_ARRAYS" { - managedArray = env.Value - } - if env.Name == "X_CSI_POWERMAX_ENDPOINT" { - endpoint = env.Value - } - if env.Name == "X_CSI_K8S_CLUSTER_PREFIX" { - clusterPrefix = env.Value - } - if env.Name == "X_CSI_POWERMAX_DEBUG" { - debug = env.Value - } - if env.Name == "X_CSI_POWERMAX_PORTGROUPS" { - portGroup = env.Value - } - if env.Name == "X_CSI_TRANSPORT_PROTOCOL" { - protocol = env.Value - } - if env.Name == "X_CSI_VSPHERE_ENABLED" { - vsphereEnabled = env.Value - } - if env.Name == "X_CSI_VSPHERE_PORTGROUP" { - vspherePG = env.Value - } - if env.Name == "X_CSI_VSPHERE_HOSTNAME" { - vsphereHostname = env.Value - } - if env.Name == "X_CSI_VCENTER_HOST" { - vsphereHost = env.Value - } - if env.Name == "X_CSI_IG_MODIFY_HOSTNAME" { - modifyHostname = env.Value - } - if env.Name == "X_CSI_IG_NODENAME_TEMPLATE" { - nodeTemplate = env.Value + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_MANAGED_ARRAYS" { + managedArray = env.Value + } + if env.Name == "X_CSI_POWERMAX_ENDPOINT" { + endpoint = env.Value + } + if env.Name == "X_CSI_K8S_CLUSTER_PREFIX" { + clusterPrefix = env.Value + } + if env.Name == "X_CSI_POWERMAX_DEBUG" { + debug = env.Value + } + if env.Name == "X_CSI_POWERMAX_PORTGROUPS" { + portGroup = env.Value + } + if env.Name == "X_CSI_TRANSPORT_PROTOCOL" { + protocol = env.Value + } + if env.Name == "X_CSI_VSPHERE_ENABLED" { + vsphereEnabled = env.Value + } + if env.Name == "X_CSI_VSPHERE_PORTGROUP" { + vspherePG = env.Value + } + if env.Name == "X_CSI_VSPHERE_HOSTNAME" { + vsphereHostname = env.Value + } + if env.Name == "X_CSI_VCENTER_HOST" { + vsphereHost = env.Value + } + if env.Name == "X_CSI_IG_MODIFY_HOSTNAME" { + modifyHostname = env.Value + } + if env.Name == "X_CSI_IG_NODENAME_TEMPLATE" { + nodeTemplate = env.Value + } } } - for _, env := range cr.Spec.Driver.Controller.Envs { - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - ctrlHealthMonitor = env.Value + if cr.Spec.Driver.Controller != nil { + for _, env := range cr.Spec.Driver.Controller.Envs { + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + ctrlHealthMonitor = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CSIPmaxManagedArray, managedArray) @@ -301,7 +263,7 @@ func ModifyPowermaxCR(yamlString string, cr csmv1.ContainerStorageModule, fileTy yamlString = strings.ReplaceAll(yamlString, CSIPmaxVsphereHost, vsphereHost) yamlString = strings.ReplaceAll(yamlString, CSIPmaxChap, nodeChap) case "CSIDriverSpec": - if cr.Spec.Driver.CSIDriverSpec.StorageCapacity { + if cr.Spec.Driver.CSIDriverSpec != nil && cr.Spec.Driver.CSIDriverSpec.StorageCapacity { storageCapacity = "true" } yamlString = strings.ReplaceAll(yamlString, CsiStorageCapacityEnabled, storageCapacity) diff --git a/pkg/drivers/powerscale.go b/pkg/drivers/powerscale.go index 27ff6088..de578ec0 100644 --- a/pkg/drivers/powerscale.go +++ b/pkg/drivers/powerscale.go @@ -58,32 +58,24 @@ func PrecheckPowerScale(ctx context.Context, cr *csmv1.ContainerStorageModule, o // check if skip validation is enabled: skipCertValid := false certCount := 1 - kubeletConfigDirFound := false - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION" { - b, err := strconv.ParseBool(env.Value) - if err != nil { - return fmt.Errorf("%s is an invalid value for X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION" { + b, err := strconv.ParseBool(env.Value) + if err != nil { + return fmt.Errorf("%s is an invalid value for X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + } + skipCertValid = b } - skipCertValid = b - } - if env.Name == "CERT_SECRET_COUNT" { - d, err := strconv.ParseInt(env.Value, 0, 8) - if err != nil { - return fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + if env.Name == "CERT_SECRET_COUNT" { + d, err := strconv.ParseInt(env.Value, 0, 8) + if err != nil { + return fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + } + certCount = int(d) } - certCount = int(d) - } - if env.Name == "KUBELET_CONFIG_DIR" { - kubeletConfigDirFound = true } } - if !kubeletConfigDirFound { - cr.Spec.Driver.Common.Envs = append(cr.Spec.Driver.Common.Envs, corev1.EnvVar{ - Name: "KUBELET_CONFIG_DIR", - Value: "/var/lib/kubelet", - }) - } secrets := []string{config} @@ -113,26 +105,31 @@ func getApplyCertVolume(cr csmv1.ContainerStorageModule) (*acorev1.VolumeApplyCo skipCertValid := false certCount := 1 - if len(cr.Spec.Driver.Common.Envs) == 0 || - (len(cr.Spec.Driver.Common.Envs) == 1 && cr.Spec.Driver.Common.Envs[0].Name != "CERT_SECRET_COUNT") { - certCount = 0 - } + if cr.Spec.Driver.Common != nil { + if len(cr.Spec.Driver.Common.Envs) == 0 || + (len(cr.Spec.Driver.Common.Envs) == 1 && cr.Spec.Driver.Common.Envs[0].Name != "CERT_SECRET_COUNT") { + certCount = 0 + } - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION" { - b, err := strconv.ParseBool(env.Value) - if err != nil { - return nil, fmt.Errorf("%s is an invalid value for X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION" { + b, err := strconv.ParseBool(env.Value) + if err != nil { + return nil, fmt.Errorf("%s is an invalid value for X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + } + skipCertValid = b } - skipCertValid = b - } - if env.Name == "CERT_SECRET_COUNT" { - d, err := strconv.ParseInt(env.Value, 0, 8) - if err != nil { - return nil, fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + if env.Name == "CERT_SECRET_COUNT" { + d, err := strconv.ParseInt(env.Value, 0, 8) + if err != nil { + return nil, fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + } + certCount = int(d) } - certCount = int(d) } + } else { + certCount = 0 + skipCertValid = true } name := "certs" @@ -175,21 +172,25 @@ func ModifyPowerScaleCR(yamlString string, cr csmv1.ContainerStorageModule, file switch fileType { case "CSIDriverSpec": - if cr.Spec.Driver.CSIDriverSpec.StorageCapacity { + if cr.Spec.Driver.CSIDriverSpec != nil && cr.Spec.Driver.CSIDriverSpec.StorageCapacity { storageCapacity = "true" } yamlString = strings.ReplaceAll(yamlString, CsiStorageCapacityEnabled, storageCapacity) case "Controller": - for _, env := range cr.Spec.Driver.Controller.Envs { - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorController = env.Value + if cr.Spec.Driver.Controller != nil { + for _, env := range cr.Spec.Driver.Controller.Envs { + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorController = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorController) case "Node": - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorNode = env.Value + if cr.Spec.Driver.Node != nil { + for _, env := range cr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorNode = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorNode) diff --git a/pkg/drivers/powerscale_test.go b/pkg/drivers/powerscale_test.go index 6c2ed9b3..2a67f5cc 100644 --- a/pkg/drivers/powerscale_test.go +++ b/pkg/drivers/powerscale_test.go @@ -28,6 +28,7 @@ import ( var ( powerScaleCSM = csmForPowerScale() + powerScaleCSMEmptyEnv = csmForPowerScaleWithEmptyEnv() powerScaleCSMBadSkipCert = csmForPowerScaleBadSkipCert() powerScaleCSMBadCertCnt = csmForPowerScaleBadCertCnt() powerScaleCSMBadVersion = csmForPowerScaleBadVersion() @@ -65,6 +66,7 @@ var ( }{ {"missing secret", powerScaleCSM, powerScaleClient, powerScaleSecret, "failed to find secret"}, {"bad version", powerScaleCSMBadVersion, powerScaleClient, powerScaleSecret, "not supported"}, + {"missing envs", powerScaleCSMEmptyEnv, powerScaleClient, powerScaleSecret, "failed to find secret"}, } ) @@ -138,6 +140,19 @@ func csmForPowerScale() csmv1.ContainerStorageModule { return res } +func csmForPowerScaleWithEmptyEnv() csmv1.ContainerStorageModule { + res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) + + res.Spec.Driver.Common.Envs = []corev1.EnvVar{} + res.Spec.Driver.AuthSecret = "csm-creds" + + // Add pscale driver version + res.Spec.Driver.ConfigVersion = shared.ConfigVersion + res.Spec.Driver.CSIDriverType = csmv1.PowerScale + + return res +} + // makes a csm object with tolerations func csmForPowerScaleBadSkipCert() csmv1.ContainerStorageModule { res := shared.MakeCSM("csm", "driver-test", shared.ConfigVersion) diff --git a/pkg/drivers/powerstore.go b/pkg/drivers/powerstore.go index 1a4f0021..d60eda59 100644 --- a/pkg/drivers/powerstore.go +++ b/pkg/drivers/powerstore.go @@ -68,19 +68,6 @@ func PrecheckPowerStore(ctx context.Context, cr *csmv1.ContainerStorageModule, o config = cr.Spec.Driver.AuthSecret } - kubeletConfigDirFound := false - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "KUBELET_CONFIG_DIR" { - kubeletConfigDirFound = true - } - } - if !kubeletConfigDirFound { - cr.Spec.Driver.Common.Envs = append(cr.Spec.Driver.Common.Envs, corev1.EnvVar{ - Name: "KUBELET_CONFIG_DIR", - Value: "/var/lib/kubelet", - }) - } - // Check if driver version is supported by doing a stat on a config file configFilePath := fmt.Sprintf("%s/driverconfig/powerstore/%s/upgrade-path.yaml", operatorConfig.ConfigDirectory, cr.Spec.Driver.ConfigVersion) if _, err := os.Stat(configFilePath); os.IsNotExist(err) { @@ -119,23 +106,27 @@ func ModifyPowerstoreCR(yamlString string, cr csmv1.ContainerStorageModule, file switch fileType { case "Node": - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_POWERSTORE_NODE_NAME_PREFIX" { - nodePrefix = env.Value - } - if env.Name == "X_CSI_FC_PORTS_FILTER_FILE_PATH" { - fcPortFilter = env.Value + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_POWERSTORE_NODE_NAME_PREFIX" { + nodePrefix = env.Value + } + if env.Name == "X_CSI_FC_PORTS_FILTER_FILE_PATH" { + fcPortFilter = env.Value + } } } - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_POWERSTORE_ENABLE_CHAP" { - chap = env.Value - } - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorNode = env.Value - } - if env.Name == "X_CSI_POWERSTORE_MAX_VOLUMES_PER_NODE" { - maxVolumesPerNode = env.Value + if cr.Spec.Driver.Node != nil { + for _, env := range cr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_POWERSTORE_ENABLE_CHAP" { + chap = env.Value + } + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorNode = env.Value + } + if env.Name == "X_CSI_POWERSTORE_MAX_VOLUMES_PER_NODE" { + maxVolumesPerNode = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiPowerstoreNodeNamePrefix, nodePrefix) @@ -144,22 +135,24 @@ func ModifyPowerstoreCR(yamlString string, cr csmv1.ContainerStorageModule, file yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorNode) yamlString = strings.ReplaceAll(yamlString, CsiPowerstoreMaxVolumesPerNode, maxVolumesPerNode) case "Controller": - for _, env := range cr.Spec.Driver.Controller.Envs { - if env.Name == "X_CSI_NFS_ACLS" { - nfsAcls = env.Value - } - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorController = env.Value - } - if env.Name == "X_CSI_POWERSTORE_EXTERNAL_ACCESS" { - powerstoreExternalAccess = env.Value + if cr.Spec.Driver.Controller != nil { + for _, env := range cr.Spec.Driver.Controller.Envs { + if env.Name == "X_CSI_NFS_ACLS" { + nfsAcls = env.Value + } + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorController = env.Value + } + if env.Name == "X_CSI_POWERSTORE_EXTERNAL_ACCESS" { + powerstoreExternalAccess = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiNfsAcls, nfsAcls) yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorController) yamlString = strings.ReplaceAll(yamlString, CsiPowerstoreExternalAccess, powerstoreExternalAccess) case "CSIDriverSpec": - if cr.Spec.Driver.CSIDriverSpec.StorageCapacity { + if cr.Spec.Driver.CSIDriverSpec != nil && cr.Spec.Driver.CSIDriverSpec.StorageCapacity { storageCapacity = "true" } yamlString = strings.ReplaceAll(yamlString, CsiStorageCapacityEnabled, storageCapacity) diff --git a/pkg/drivers/unity.go b/pkg/drivers/unity.go index 218e44c7..afbaa1af 100644 --- a/pkg/drivers/unity.go +++ b/pkg/drivers/unity.go @@ -70,20 +70,22 @@ func PrecheckUnity(ctx context.Context, cr *csmv1.ContainerStorageModule, operat skipCertValid := true certCount := 1 - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION" { - b, err := strconv.ParseBool(env.Value) - if err != nil { - return fmt.Errorf("%s is an invalid value for X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION" { + b, err := strconv.ParseBool(env.Value) + if err != nil { + return fmt.Errorf("%s is an invalid value for X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + } + skipCertValid = b } - skipCertValid = b - } - if env.Name == "CERT_SECRET_COUNT" { - d, err := strconv.ParseInt(env.Value, 0, 8) - if err != nil { - return fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + if env.Name == "CERT_SECRET_COUNT" { + d, err := strconv.ParseInt(env.Value, 0, 8) + if err != nil { + return fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + } + certCount = int(d) } - certCount = int(d) } } @@ -119,25 +121,29 @@ func ModifyUnityCR(yamlString string, cr csmv1.ContainerStorageModule, fileType switch fileType { case "Node": - for _, env := range cr.Spec.Driver.Node.Envs { - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorNode = env.Value - } - if env.Name == "X_CSI_ALLOWED_NETWORKS" { - allowedNetworks = env.Value + if cr.Spec.Driver.Node != nil { + for _, env := range cr.Spec.Driver.Node.Envs { + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorNode = env.Value + } + if env.Name == "X_CSI_ALLOWED_NETWORKS" { + allowedNetworks = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorNode) yamlString = strings.ReplaceAll(yamlString, AllowedNetworks, allowedNetworks) case "Controller": - for _, env := range cr.Spec.Driver.Controller.Envs { - if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { - healthMonitorController = env.Value + if cr.Spec.Driver.Controller != nil { + for _, env := range cr.Spec.Driver.Controller.Envs { + if env.Name == "X_CSI_HEALTH_MONITOR_ENABLED" { + healthMonitorController = env.Value + } } } yamlString = strings.ReplaceAll(yamlString, CsiHealthMonitorEnabled, healthMonitorController) case "CSIDriverSpec": - if cr.Spec.Driver.CSIDriverSpec.StorageCapacity { + if cr.Spec.Driver.CSIDriverSpec != nil && cr.Spec.Driver.CSIDriverSpec.StorageCapacity { storageCapacity = "true" } yamlString = strings.ReplaceAll(yamlString, CsiStorageCapacityEnabled, storageCapacity) @@ -150,22 +156,24 @@ func ModifyUnityCR(yamlString string, cr csmv1.ContainerStorageModule, fileType func ModifyUnityConfigMap(_ context.Context, cr csmv1.ContainerStorageModule) map[string]string { keyValue := "" var configMapData map[string]string - for _, env := range cr.Spec.Driver.Common.Envs { + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_UNITY_ALLOW_MULTI_POD_ACCESS" { - keyValue += fmt.Sprintf("\n %s: %s", "ALLOW_MULTI_POD_ACCESS", env.Value) - } - if env.Name == "MAX_UNITY_VOLUMES_PER_NODE" { - keyValue += fmt.Sprintf("\n %s: %s", env.Name, env.Value) - } - if env.Name == "X_CSI_UNITY_SYNC_NODEINFO_INTERVAL" { - keyValue += fmt.Sprintf("\n %s: %s", "SYNC_NODE_INFO_TIME_INTERVAL", env.Value) - } - if env.Name == "TENANT_NAME" { - keyValue += fmt.Sprintf("\n %s: %s", env.Name, env.Value) - } - if env.Name == "CSI_LOG_LEVEL" { - keyValue += fmt.Sprintf("\n %s: %s", env.Name, env.Value) + if env.Name == "X_CSI_UNITY_ALLOW_MULTI_POD_ACCESS" { + keyValue += fmt.Sprintf("\n %s: %s", "ALLOW_MULTI_POD_ACCESS", env.Value) + } + if env.Name == "MAX_UNITY_VOLUMES_PER_NODE" { + keyValue += fmt.Sprintf("\n %s: %s", env.Name, env.Value) + } + if env.Name == "X_CSI_UNITY_SYNC_NODEINFO_INTERVAL" { + keyValue += fmt.Sprintf("\n %s: %s", "SYNC_NODE_INFO_TIME_INTERVAL", env.Value) + } + if env.Name == "TENANT_NAME" { + keyValue += fmt.Sprintf("\n %s: %s", env.Name, env.Value) + } + if env.Name == "CSI_LOG_LEVEL" { + keyValue += fmt.Sprintf("\n %s: %s", env.Name, env.Value) + } } } configMapData = map[string]string{ @@ -178,21 +186,26 @@ func ModifyUnityConfigMap(_ context.Context, cr csmv1.ContainerStorageModule) ma func getApplyCertVolumeUnity(cr csmv1.ContainerStorageModule) (*acorev1.VolumeApplyConfiguration, error) { skipCertValid := true certCount := 1 - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION" { - b, err := strconv.ParseBool(env.Value) - if err != nil { - return nil, fmt.Errorf("%s is an invalid value for X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + if cr.Spec.Driver.Common != nil { + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION" { + b, err := strconv.ParseBool(env.Value) + if err != nil { + return nil, fmt.Errorf("%s is an invalid value for X_CSI_UNITY_SKIP_CERTIFICATE_VALIDATION: %v", env.Value, err) + } + skipCertValid = b } - skipCertValid = b - } - if env.Name == "CERT_SECRET_COUNT" { - d, err := strconv.ParseInt(env.Value, 0, 8) - if err != nil { - return nil, fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + if env.Name == "CERT_SECRET_COUNT" { + d, err := strconv.ParseInt(env.Value, 0, 8) + if err != nil { + return nil, fmt.Errorf("%s is an invalid value for CERT_SECRET_COUNT: %v", env.Value, err) + } + certCount = int(d) } - certCount = int(d) } + } else { + skipCertValid = true + certCount = 0 } name := "certs" diff --git a/pkg/modules/authorization_test.go b/pkg/modules/authorization_test.go index 0f4dcfb7..5b28734b 100644 --- a/pkg/modules/authorization_test.go +++ b/pkg/modules/authorization_test.go @@ -121,7 +121,7 @@ func TestAuthInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } @@ -133,7 +133,7 @@ func TestAuthInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } @@ -149,7 +149,7 @@ func TestAuthInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } @@ -165,7 +165,7 @@ func TestAuthInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerScaleName, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } diff --git a/pkg/modules/resiliency_test.go b/pkg/modules/resiliency_test.go index 6324e6f4..31d9ee67 100644 --- a/pkg/modules/resiliency_test.go +++ b/pkg/modules/resiliency_test.go @@ -313,7 +313,7 @@ func TestResiliencyInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerStore, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerStore, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } @@ -325,7 +325,7 @@ func TestResiliencyInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerStore, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerStore, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } @@ -341,7 +341,7 @@ func TestResiliencyInjectDaemonset(t *testing.T) { if err != nil { panic(err) } - nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerStore, "node.yaml") + nodeYAML, err := drivers.GetNode(ctx, customResource, operatorConfig, csmv1.PowerStore, "node.yaml", ctrlClientFake.NewClientBuilder().Build()) if err != nil { panic(err) } diff --git a/pkg/modules/reverseproxy.go b/pkg/modules/reverseproxy.go index 80a055eb..16e98dc5 100644 --- a/pkg/modules/reverseproxy.go +++ b/pkg/modules/reverseproxy.go @@ -49,13 +49,15 @@ const ( // var used in deploying reverseproxy var ( - deployAsSidecar bool - CSIPmaxRevProxyServiceName = "X_CSI_POWERMAX_PROXY_SERVICE_NAME" - CSIPmaxRevProxyPort = "X_CSI_POWERMAX_SIDECAR_PROXY_PORT" - RevProxyDefaultPort = "2222" - RevProxyServiceName = "csipowermax-reverseproxy" - RevProxyConfigMapVolName = "configmap-volume" - RevProxyTLSSecretVolName = "tls-secret" + deployAsSidecar = true + CSIPmaxRevProxyServiceName = "X_CSI_POWERMAX_PROXY_SERVICE_NAME" + CSIPmaxRevProxyPort = "X_CSI_POWERMAX_SIDECAR_PROXY_PORT" + RevProxyDefaultPort = "2222" + RevProxyServiceName = "csipowermax-reverseproxy" + RevProxyConfigMapVolName = "configmap-volume" + RevProxyConfigMapDeafultName = "powermax-reverseproxy-config" + RevProxyTLSSecretVolName = "tls-secret" + RevProxyTLSSecretDefaultName = "csirevproxy-tls-secret" // #nosec G101 ) // ReverseproxySupportedDrivers is a map containing the CSI Drivers supported by CSM Reverseproxy. The key is driver name and the value is the driver plugin identifier @@ -118,13 +120,7 @@ func ReverseProxyPrecheck(ctx context.Context, op utils.OperatorConfig, revproxy // ReverseProxyServer - apply/delete deployment objects func ReverseProxyServer(ctx context.Context, isDeleting bool, op utils.OperatorConfig, cr csmv1.ContainerStorageModule, ctrlClient crclient.Client) error { log := logger.GetLogger(ctx) - log.Infof("Checking if DeployAsSidar is false...\n") - if deployAsSidecar { - log.Infof("DeployAsSidar is true...csi-reverseproxy will be installed as sidecar\n") - log.Infof("exiting ReverseProxyServer...\n") - return nil - } - YamlString, err := getReverseProxyDeployment(op, cr, csmv1.Module{}) + YamlString, err := getReverseProxyDeployment(op, cr) if err != nil { return err } @@ -152,10 +148,7 @@ func ReverseProxyServer(ctx context.Context, isDeleting bool, op utils.OperatorC // ReverseProxyStartService starts reverseproxy service for node to connect to revserseproxy sidecar func ReverseProxyStartService(ctx context.Context, isDeleting bool, op utils.OperatorConfig, cr csmv1.ContainerStorageModule, ctrlClient crclient.Client) error { log := logger.GetLogger(ctx) - if !deployAsSidecar { - log.Infof("DeployAsSidar is false...csi-reverseproxy service is part of deployement already\n") - return nil - } + YamlString, err := getReverseProxyService(op, cr) if err != nil { return err @@ -193,9 +186,10 @@ func getReverseProxyModule(cr csmv1.ContainerStorageModule) (csmv1.Module, error // getReverseProxyService - gets the reverseproxy service manifest func getReverseProxyService(op utils.OperatorConfig, cr csmv1.ContainerStorageModule) (string, error) { yamlString := "" - revProxy, err := getReverseProxyModule(cr) - if err != nil { - return yamlString, err + revProxy := cr.GetModule(csmv1.ReverseProxy) + // This is necessary for the minimal manifest, where the reverse proxy will not be included in the CSM CR. + if len(revProxy.Name) == 0 { + revProxy.Name = csmv1.ReverseProxy } buf, err := readConfigFile(revProxy, cr, op, ReverseProxyService) @@ -204,7 +198,7 @@ func getReverseProxyService(op utils.OperatorConfig, cr csmv1.ContainerStorageMo } yamlString = string(buf) - var proxyPort string + proxyPort := "2222" for _, component := range revProxy.Components { if component.Name == ReverseProxyServerComponent { for _, env := range component.Envs { @@ -222,7 +216,7 @@ func getReverseProxyService(op utils.OperatorConfig, cr csmv1.ContainerStorageMo } // getReverseProxyDeployment - updates deployment manifest with reverseproxy CRD values -func getReverseProxyDeployment(op utils.OperatorConfig, cr csmv1.ContainerStorageModule, revProxy csmv1.Module) (string, error) { +func getReverseProxyDeployment(op utils.OperatorConfig, cr csmv1.ContainerStorageModule) (string, error) { YamlString := "" revProxy, err := getReverseProxyModule(cr) if err != nil { @@ -237,42 +231,16 @@ func getReverseProxyDeployment(op utils.OperatorConfig, cr csmv1.ContainerStorag YamlString = string(buf) proxyNamespace := cr.Namespace - var proxyTLSSecret, proxyPort, proxyConfig string - - // we will populate default values for environment variables, if nothing is given (minimal yaml) - if revProxy.Components == nil { - components := make([]csmv1.ContainerTemplate, 0) - components = append(components, csmv1.ContainerTemplate{ - Name: "csipowermax-reverseproxy", - }) - revProxy.Components = components - - revProxy.Components[0].Envs = append(revProxy.Components[0].Envs, corev1.EnvVar{ - Name: "X_CSI_REVPROXY_TLS_SECRET", - Value: "csirevproxy-tls-secret", - }) - revProxy.Components[0].Envs = append(revProxy.Components[0].Envs, corev1.EnvVar{ - Name: "X_CSI_REVPROXY_PORT", - Value: "2222", - }) - revProxy.Components[0].Envs = append(revProxy.Components[0].Envs, corev1.EnvVar{ - Name: "X_CSI_CONFIG_MAP_NAME", - Value: "powermax-reverseproxy-config", - }) - revProxy.Components[0].Envs = append(revProxy.Components[0].Envs, corev1.EnvVar{ - Name: "DeployAsSidecar", - Value: "true", - }) - - } + proxyTLSSecret := RevProxyTLSSecretDefaultName + proxyPort := RevProxyDefaultPort + proxyConfig := RevProxyConfigMapDeafultName + image := op.K8sVersion.Images.CSIRevProxy for _, component := range revProxy.Components { if component.Name == ReverseProxyServerComponent { - image := op.K8sVersion.Images.CSIRevProxy if string(component.Image) != "" { image = string(component.Image) } - YamlString = strings.ReplaceAll(YamlString, ReverseProxyImage, image) for _, env := range component.Envs { if env.Name == "X_CSI_REVPROXY_TLS_SECRET" { proxyTLSSecret = env.Value @@ -283,13 +251,11 @@ func getReverseProxyDeployment(op utils.OperatorConfig, cr csmv1.ContainerStorag if env.Name == "X_CSI_CONFIG_MAP_NAME" { proxyConfig = env.Value } - if env.Name == "DeployAsSidecar" { - deployAsSidecar, _ = strconv.ParseBool(env.Value) - } } } } + YamlString = strings.ReplaceAll(YamlString, ReverseProxyImage, image) YamlString = strings.ReplaceAll(YamlString, utils.DefaultReleaseNamespace, proxyNamespace) YamlString = strings.ReplaceAll(YamlString, ReverseProxyPort, proxyPort) YamlString = strings.ReplaceAll(YamlString, ReverseProxyTLSSecret, proxyTLSSecret) @@ -300,26 +266,11 @@ func getReverseProxyDeployment(op utils.OperatorConfig, cr csmv1.ContainerStorag // ReverseProxyInjectDeployment injects reverseproxy container as sidecar into controller func ReverseProxyInjectDeployment(dp v1.DeploymentApplyConfiguration, cr csmv1.ContainerStorageModule, op utils.OperatorConfig) (*v1.DeploymentApplyConfiguration, error) { - log := logger.GetLogger(context.Background()) - - if !deployAsSidecar { - log.Infof("DeployAsSidar is false...csi-reverseproxy should be present as deployement\n") - log.Infof("adding proxy service name...\n") - for i, cnt := range dp.Spec.Template.Spec.Containers { - if *cnt.Name == "driver" { - dp.Spec.Template.Spec.Containers[i].Env = append(dp.Spec.Template.Spec.Containers[i].Env, - acorev1.EnvVarApplyConfiguration{Name: &CSIPmaxRevProxyServiceName, Value: &RevProxyServiceName}, - ) - break - } - } - return &dp, nil - } - revProxyModule, containerPtr, err := getRevproxyApplyCR(cr, op) if err != nil { return nil, err } + container := *containerPtr // update the image for _, side := range revProxyModule.Components { @@ -363,7 +314,7 @@ func getRevProxyPort(revProxyModule csmv1.Module) string { } func getRevProxyVolumeComp(revProxyModule csmv1.Module) []acorev1.VolumeApplyConfiguration { - var revProxyConfigMap, revProxyTLSSecret string + revProxyConfigMap, revProxyTLSSecret := RevProxyConfigMapDeafultName, RevProxyTLSSecretDefaultName for _, component := range revProxyModule.Components { if component.Name == ReverseProxyServerComponent { for _, env := range component.Envs { @@ -403,9 +354,10 @@ func getRevProxyVolumeComp(revProxyModule csmv1.Module) []acorev1.VolumeApplyCon // returns revproxy module and container func getRevproxyApplyCR(cr csmv1.ContainerStorageModule, op utils.OperatorConfig) (*csmv1.Module, *acorev1.ContainerApplyConfiguration, error) { var err error - revProxyModule, err := getReverseProxyModule(cr) - if err != nil { - return nil, nil, err + revProxyModule := cr.GetModule(csmv1.ReverseProxy) + // This is necessary for the minimal manifest, where the reverse proxy will not be included in the CSM CR. + if len(revProxyModule.Name) == 0 { + revProxyModule.Name = csmv1.ReverseProxy } buf, err := readConfigFile(revProxyModule, cr, op, ReverseProxySidecar) @@ -421,3 +373,18 @@ func getRevproxyApplyCR(cr csmv1.ContainerStorageModule, op utils.OperatorConfig } return &revProxyModule, &container, nil } + +func AddReverseProxyServiceName(dp *v1.DeploymentApplyConfiguration) { + for i, cnt := range dp.Spec.Template.Spec.Containers { + if *cnt.Name == "driver" { + dp.Spec.Template.Spec.Containers[i].Env = append(dp.Spec.Template.Spec.Containers[i].Env, + acorev1.EnvVarApplyConfiguration{Name: &CSIPmaxRevProxyServiceName, Value: &RevProxyServiceName}, + ) + break + } + } +} + +var IsReverseProxySidecar = func() bool { + return deployAsSidecar +} diff --git a/pkg/modules/reverseproxy_test.go b/pkg/modules/reverseproxy_test.go index 6ea01bf2..213beb56 100644 --- a/pkg/modules/reverseproxy_test.go +++ b/pkg/modules/reverseproxy_test.go @@ -14,6 +14,7 @@ package modules import ( "context" + "strings" "testing" "github.com/dell/csm-operator/pkg/drivers" @@ -366,3 +367,112 @@ func TestReverseProxyStartService(t *testing.T) { }) } } + +func TestAddReverseProxyServiceName(t *testing.T) { + tests := map[string]func(t *testing.T) applyv1.DeploymentApplyConfiguration{ + "Add env var to driver container": func(*testing.T) applyv1.DeploymentApplyConfiguration { + customResource, err := getCustomResource("./testdata/cr_powermax_reverseproxy.yaml") + if err != nil { + panic(err) + } + controllerYAML, err := drivers.GetController(ctx, customResource, operatorConfig, csmv1.PowerMax) + if err != nil { + panic(err) + } + deployAsSidecar = true + return controllerYAML.Deployment + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + dp := tc(t) + AddReverseProxyServiceName(&dp) + isEnvFound := false + for i, cnt := range dp.Spec.Template.Spec.Containers { + if *cnt.Name == "driver" { + for _, env := range dp.Spec.Template.Spec.Containers[i].Env { + if strings.EqualFold(*env.Name, CSIPmaxRevProxyServiceName) && strings.EqualFold(*env.Value, RevProxyServiceName) { + isEnvFound = true + } + } + } + } + if !isEnvFound { + t.Errorf("Expected env vars: %v with value %v, but not found", CSIPmaxRevProxyServiceName, RevProxyServiceName) + } + }) + } +} + +func TestIsReverseProxySidecar(t *testing.T) { + type fakeControllerRuntimeClientWrapper func(clusterConfigData []byte) (ctrlClient.Client, error) + + tests := map[string]func(t *testing.T) (bool, csmv1.Module, csmv1.ContainerStorageModule, ctrlClient.Client, fakeControllerRuntimeClientWrapper){ + "Reverse proxy is configured as sidecar": func(*testing.T) (bool, csmv1.Module, csmv1.ContainerStorageModule, ctrlClient.Client, fakeControllerRuntimeClientWrapper) { + customResource, err := getCustomResource("./testdata/cr_powermax_reverseproxy_sidecar.yaml") + if err != nil { + panic(err) + } + + proxySecret := getSecret(customResource.Namespace, "csirevproxy-tls-secret") + proxyConfigMap := getConfigMap(customResource.Namespace, "powermax-reverseproxy-config") + + tmpCR := customResource + reverseProxy := tmpCR.Spec.Modules[0] + + sourceClient := ctrlClientFake.NewClientBuilder().WithObjects(proxySecret, proxyConfigMap).Build() + fakeControllerRuntimeClient := func(_ []byte) (ctrlClient.Client, error) { + clusterClient := ctrlClientFake.NewClientBuilder().WithObjects(proxySecret, proxyConfigMap).Build() + return clusterClient, nil + } + + return true, reverseProxy, tmpCR, sourceClient, fakeControllerRuntimeClient + }, + "Reverse proxy is not configured as sidecar": func(*testing.T) (bool, csmv1.Module, csmv1.ContainerStorageModule, ctrlClient.Client, fakeControllerRuntimeClientWrapper) { + customResource, err := getCustomResource("./testdata/cr_powermax_reverseproxy.yaml") + if err != nil { + panic(err) + } + + proxySecret := getSecret(customResource.Namespace, "csirevproxy-tls-secret") + proxyConfigMap := getConfigMap(customResource.Namespace, "powermax-reverseproxy-config") + + tmpCR := customResource + reverseProxy := tmpCR.Spec.Modules[0] + + sourceClient := ctrlClientFake.NewClientBuilder().WithObjects(proxySecret, proxyConfigMap).Build() + fakeControllerRuntimeClient := func(_ []byte) (ctrlClient.Client, error) { + clusterClient := ctrlClientFake.NewClientBuilder().WithObjects(proxySecret, proxyConfigMap).Build() + return clusterClient, nil + } + + return false, reverseProxy, tmpCR, sourceClient, fakeControllerRuntimeClient + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + oldNewControllerRuntimeClientWrapper := utils.NewControllerRuntimeClientWrapper + oldNewK8sClientWrapper := utils.NewK8sClientWrapper + defer func() { + utils.NewControllerRuntimeClientWrapper = oldNewControllerRuntimeClientWrapper + utils.NewK8sClientWrapper = oldNewK8sClientWrapper + }() + + isSideCar, reverseProxy, tmpCR, sourceClient, fakeControllerRuntimeClient := tc(t) + utils.NewControllerRuntimeClientWrapper = fakeControllerRuntimeClient + utils.NewK8sClientWrapper = func(_ []byte) (*kubernetes.Clientset, error) { + return nil, nil + } + + fakeReconcile := utils.FakeReconcileCSM{ + Client: sourceClient, + K8sClient: fake.NewSimpleClientset(), + } + + ReverseProxyPrecheck(ctx, operatorConfig, reverseProxy, tmpCR, &fakeReconcile) + if isSideCar != IsReverseProxySidecar() { + t.Errorf("Expected %v but got %v", isSideCar, IsReverseProxySidecar()) + } + }) + } +} diff --git a/pkg/modules/testdata/cr_powermax_reverseproxy_sidecar.yaml b/pkg/modules/testdata/cr_powermax_reverseproxy_sidecar.yaml new file mode 100644 index 00000000..a1ce5ce2 --- /dev/null +++ b/pkg/modules/testdata/cr_powermax_reverseproxy_sidecar.yaml @@ -0,0 +1,63 @@ +# Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +# +apiVersion: storage.dell.com/v1 +kind: ContainerStorageModule +metadata: + name: test-powermax + namespace: powermax +spec: + driver: + csiDriverType: "powermax" + configVersion: v2.13.0 + authSecret: powermax-creds + replicas: 1 + common: + image: "quay.io/dell/container-storage-modules/csi-powermax:v2.13.0" + imagePullPolicy: IfNotPresent + modules: + # CSI Powermax Reverseproxy is a mandatory module + - name: "csireverseproxy" + # enabled: Always set to true + enabled: true + configVersion: v2.12.0 + components: + - name: csipowermax-reverseproxy + # image: Define the container images used for the reverse proxy + # Default value: None + image: quay.io/dell/container-storage-modules/csipowermax-reverseproxy:v2.12.0 + envs: + # "tlsSecret" defines the TLS secret that is created with certificate + # and its associated key + # Default value: None + # Example: "tls-secret" + - name: X_CSI_REVPROXY_TLS_SECRET + value: "csirevproxy-tls-secret" + - name: X_CSI_REVPROXY_PORT + value: "2222" + - name: X_CSI_CONFIG_MAP_NAME + value: "powermax-reverseproxy-config" + - name: "DeployAsSidecar" + value: "true" + - name: authorization + # enable: Enable/Disable csm-authorization + enabled: false + components: + - name: karavi-authorization-proxy + image: quay.io/dell/container-storage-modules/csm-authorization-sidecar:v2.1.0 + envs: + # proxyHost: hostname of the csm-authorization server + - name: "PROXY_HOST" + value: "testing-proxy-host" + # skipCertificateValidation: Enable/Disable certificate validation of the csm-authorization server + - name: "SKIP_CERTIFICATE_VALIDATION" + value: "true" diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 8da3ce6f..da966167 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -159,6 +159,8 @@ const ( ClientNamespace = "" // BrownfieldManifest - brownfield-onboard.yaml BrownfieldManifest = "brownfield-onboard.yaml" + // DefaultKubeletConfigDir - default kubelet config directory + DefaultKubeletConfigDir = "/var/lib/kubelet" ) // SplitYaml divides a big bytes of yaml files in individual yaml files. @@ -350,14 +352,16 @@ func ModifyCommonCR(YamlString string, cr csmv1.ContainerStorageModule) string { if cr.Namespace != "" { YamlString = strings.ReplaceAll(YamlString, DefaultReleaseNamespace, cr.Namespace) } - if string(cr.Spec.Driver.Common.ImagePullPolicy) != "" { - YamlString = strings.ReplaceAll(YamlString, DefaultImagePullPolicy, string(cr.Spec.Driver.Common.ImagePullPolicy)) - } - path := "" - for _, env := range cr.Spec.Driver.Common.Envs { - if env.Name == "KUBELET_CONFIG_DIR" { - path = env.Value - break + path := DefaultKubeletConfigDir + if cr.Spec.Driver.Common != nil { + if string(cr.Spec.Driver.Common.ImagePullPolicy) != "" { + YamlString = strings.ReplaceAll(YamlString, DefaultImagePullPolicy, string(cr.Spec.Driver.Common.ImagePullPolicy)) + } + for _, env := range cr.Spec.Driver.Common.Envs { + if env.Name == "KUBELET_CONFIG_DIR" { + path = env.Value + break + } } } YamlString = strings.ReplaceAll(YamlString, KubeletConfigDir, path) diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index ee180c43..f1f3d70d 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -933,7 +933,7 @@ func TestModifyCommonCR(t *testing.T) { }, Spec: csmv1.ContainerStorageModuleSpec{ Driver: csmv1.Driver{ - Common: csmv1.ContainerTemplate{ + Common: &csmv1.ContainerTemplate{ ImagePullPolicy: corev1.PullPolicy("Always"), }, }, diff --git a/tests/e2e/steps/steps_def.go b/tests/e2e/steps/steps_def.go index 2f5c12ce..dd6a8040 100644 --- a/tests/e2e/steps/steps_def.go +++ b/tests/e2e/steps/steps_def.go @@ -18,6 +18,7 @@ import ( "math/rand" "os" "os/exec" + "path/filepath" "strconv" "strings" "time" @@ -25,6 +26,7 @@ import ( csmv1 "github.com/dell/csm-operator/api/v1" "encoding/json" + "github.com/dell/csm-operator/pkg/constants" "github.com/dell/csm-operator/pkg/modules" "github.com/dell/csm-operator/pkg/utils" @@ -38,7 +40,6 @@ import ( "k8s.io/kubernetes/test/e2e/framework/kubectl" fpod "k8s.io/kubernetes/test/e2e/framework/pod" "k8s.io/utils/pointer" - "path/filepath" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" ) @@ -323,6 +324,52 @@ func (step *Step) validateDriverInstalled(res Resource, driverName string, crNum return checkAllRunningPods(context.TODO(), res.CustomResource[crNum-1].(csmv1.ContainerStorageModule).Namespace, step.clientSet) } +func (step *Step) validateMinimalCSMDriverSpec(res Resource, driverName string, crNumStr string) error { + crNum, _ := strconv.Atoi(crNumStr) + cr := res.CustomResource[crNum-1].(csmv1.ContainerStorageModule) + found := new(csmv1.ContainerStorageModule) + err := step.ctrlClient.Get(context.TODO(), client.ObjectKey{ + Namespace: cr.Namespace, + Name: cr.Name, + }, found) + if err != nil { + if errors.IsNotFound(err) { + return fmt.Errorf("CSM resource '%s' not found in namespace '%s'", cr.Name, cr.Namespace) + } + return fmt.Errorf("failed to get CSM resource '%s/%s': %w", cr.Namespace, cr.Name, err) + } + driver := found.Spec.Driver + if driver.ConfigVersion == "" { + return fmt.Errorf("configVersion is missing") + } + if driver.CSIDriverType == "" { + return fmt.Errorf("csiDriverType is missing") + } + if driver.Replicas == 0 { + return fmt.Errorf("replicas should have a non-zero value") + } + + // Ensure all other fields are empty or nil + if len(driver.SideCars) > 0 || + len(driver.InitContainers) > 0 || + len(driver.SnapshotClass) > 0 || + driver.Controller != nil || + driver.Node != nil || + driver.CSIDriverSpec != nil || + driver.DNSPolicy != "" || + driver.Common != nil || + driver.AuthSecret != "" || + driver.TLSCertSecret != "" { + return fmt.Errorf("unexpected fields found in Driver spec: %+v", driver) + } + + if driver.CSIDriverType == csmv1.PowerMax && found.HasModule(csmv1.ReverseProxy) { + return fmt.Errorf("csm resource '%s' contains reverse proxy module", cr.Name) + } + + return nil +} + func (step *Step) validateDriverNotInstalled(res Resource, driverName string, crNumStr string) error { crNum, _ := strconv.Atoi(crNumStr) time.Sleep(20 * time.Second) diff --git a/tests/e2e/steps/steps_runner.go b/tests/e2e/steps/steps_runner.go index b971efb8..b20003ba 100644 --- a/tests/e2e/steps/steps_runner.go +++ b/tests/e2e/steps/steps_runner.go @@ -49,6 +49,7 @@ func StepRunnerInit(runner *Runner, ctrlClient client.Client, clientSet *kuberne runner.addStep(`^Upgrade from custom resource \[(\d+)\] to \[(\d+)\]$`, step.upgradeCustomResource) runner.addStep(`^Validate custom resource \[(\d+)\]$`, step.validateCustomResourceStatus) runner.addStep(`^Validate \[([^"]*)\] driver from CR \[(\d+)\] is installed$`, step.validateDriverInstalled) + runner.addStep(`^Validate \[([^"]*)\] driver spec from CR \[(\d+)\]$`, step.validateMinimalCSMDriverSpec) runner.addStep(`^Validate \[([^"]*)\] driver from CR \[(\d+)\] is not installed$`, step.validateDriverNotInstalled) runner.addStep(`^Run custom test$`, step.runCustomTest) // legacy support - original e2e was designed only to run ONE custom test diff --git a/tests/e2e/testfiles/minimal-testfiles/scenarios.yaml b/tests/e2e/testfiles/minimal-testfiles/scenarios.yaml index 7fe02eb3..f81abad8 100644 --- a/tests/e2e/testfiles/minimal-testfiles/scenarios.yaml +++ b/tests/e2e/testfiles/minimal-testfiles/scenarios.yaml @@ -12,6 +12,7 @@ - "Apply custom resource [1]" - "Validate custom resource [1]" - "Validate [powerstore] driver from CR [1] is installed" + - "Validate [powerstore] driver spec from CR [1]" - "Run custom test" # cleanup - "Enable forceRemoveDriver on CR [1]" @@ -94,9 +95,9 @@ - "Restore template [testfiles/powerstore-templates/powerstore-secret-template.yaml] for [pstore]" - "Restore template [testfiles/powerstore-templates/powerstore-storageclass-template.yaml] for [pstore]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-pstore --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-pstore --chainNumber 2 --chainLength 2 - scenario: "Install PowerStore Driver (Minimal, With false forceRemoveDriver)" paths: @@ -122,9 +123,9 @@ - "Restore template [testfiles/powerstore-templates/powerstore-secret-template.yaml] for [pstore]" - "Restore template [testfiles/powerstore-templates/powerstore-storageclass-template.yaml] for [pstore]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-pstore --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-pstore --chainNumber 2 --chainLength 2 - scenario: "Install Unity Driver (Minimal, Standalone)" paths: @@ -138,6 +139,7 @@ - "Apply custom resource [1]" - "Validate custom resource [1]" - "Validate [unity] driver from CR [1] is installed" + - "Validate [unity] driver spec from CR [1]" - "Run custom test" # cleanup - "Enable forceRemoveDriver on CR [1]" @@ -173,9 +175,9 @@ - "Restore template [testfiles/unity-templates/unity-secret-template.yaml] for [unity]" - "Restore template [testfiles/unity-templates/unity-storageclass-template.yaml] for [unity]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-unity --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-unity --chainNumber 2 --chainLength 2 - scenario: "Install Unity Driver (Minimal, With no forceRemoveDriver)" paths: @@ -197,9 +199,9 @@ - "Restore template [testfiles/unity-templates/unity-secret-template.yaml] for [unity]" - "Restore template [testfiles/unity-templates/unity-storageclass-template.yaml] for [unity]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-unity --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-unity --chainNumber 2 --chainLength 2 - scenario: "Install PowerFlex Driver (Minimal, Standalone)" paths: @@ -214,6 +216,7 @@ - "Apply custom resource [1]" - "Validate custom resource [1]" - "Validate [powerflex] driver from CR [1] is installed" + - "Validate [powerflex] driver spec from CR [1]" - "Run custom test" # cleanup - "Enable forceRemoveDriver on CR [1]" @@ -245,9 +248,9 @@ - "Restore template [testfiles/powerflex-templates/powerflex-secret-template.yaml] for [pflex]" - "Restore template [testfiles/powerflex-templates/powerflex-storageclass-template.yaml] for [pflex]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-vxflexos --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-vxflexos --chainNumber 2 --chainLength 2 - scenario: "Install PowerFlex Driver (Minimal, With false forceRemoveDriver)" paths: @@ -275,9 +278,9 @@ - "Restore template [testfiles/powerflex-templates/powerflex-secret-template.yaml] for [pflex]" - "Restore template [testfiles/powerflex-templates/powerflex-storageclass-template.yaml] for [pflex]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-vxflexos --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-vxflexos --chainNumber 2 --chainLength 2 - scenario: "Install PowerFlex Driver (Minimal, With Resiliency)" paths: @@ -451,6 +454,7 @@ - "Apply custom resource [1]" - "Validate custom resource [1]" - "Validate [powerscale] driver from CR [1] is installed" + - "Validate [powerscale] driver spec from CR [1]" - "Run custom test" # cleanup - "Enable forceRemoveDriver on CR [1]" @@ -483,9 +487,9 @@ - "Restore template [testfiles/powerscale-templates/powerscale-secret-template.yaml] for [pscale]" - "Restore template [testfiles/powerscale-templates/powerscale-storageclass-template.yaml] for [pscale]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-isilon --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-isilon --chainNumber 2 --chainLength 2 - scenario: "Install PowerScale Driver (Minimal, With false forceRemoveDriver)" paths: @@ -513,9 +517,9 @@ - "Restore template [testfiles/powerscale-templates/powerscale-secret-template.yaml] for [pscale]" - "Restore template [testfiles/powerscale-templates/powerscale-storageclass-template.yaml] for [pscale]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-isilon --chainNumber 2 --chainLength 2 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-isilon --chainNumber 2 --chainLength 2 - scenario: "Install PowerScale Driver (Minimal, Standalone), Enable/Disable Resiliency" paths: @@ -831,6 +835,7 @@ - "Apply custom resource [1]" - "Validate custom resource [1]" - "Validate [powermax] driver from CR [1] is installed" + - "Validate [powermax] driver spec from CR [1]" - "Run custom test" - "Enable forceRemoveDriver on CR [1]" - "Delete custom resource [1]" @@ -863,9 +868,9 @@ - "Restore template [testfiles/powermax-templates/powermax-storageclass-template.yaml] for [pmax]" - "Restore template [testfiles/powermax-templates/powermax-secret-template.yaml] for [pmaxCreds]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-pmax --chainLength 1 --chainNumber 1 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-pmax --chainLength 1 --chainNumber 1 - scenario: "Install PowerMax Driver (Minimal, With false forceRemoveDriver)" paths: @@ -893,9 +898,9 @@ - "Restore template [testfiles/powermax-templates/powermax-storageclass-template.yaml] for [pmax]" - "Restore template [testfiles/powermax-templates/powermax-secret-template.yaml] for [pmaxCreds]" customTest: - name: Cert CSI - run: - - cert-csi test vio --sc op-e2e-pmax --chainLength 1 --chainNumber 1 + - name: Cert CSI + run: + - cert-csi test vio --sc op-e2e-pmax --chainLength 1 --chainNumber 1 - scenario: "Install PowerMax Driver (Minimal, With Observability)" paths: diff --git a/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_2.yaml b/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_2.yaml index 67a8c7c0..5d6ecb08 100644 --- a/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_2.yaml +++ b/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_2.yaml @@ -209,11 +209,11 @@ spec: - key: "node.kubernetes.io/network-unavailable" operator: "Exists" effect: "NoExecute" - # Uncomment if nodes you wish to use have the node-role.kubernetes.io/control-plane taint + # Uncomment if nodes you wish to use have the node-role.kubernetes.io/control-plane taint - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" - # Uncomment if nodes you wish to use have the node-role.kubernetes.io/master taint + # Uncomment if nodes you wish to use have the node-role.kubernetes.io/master taint - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" diff --git a/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_3.yaml b/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_3.yaml index ba30072d..f4a2900b 100644 --- a/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_3.yaml +++ b/tests/e2e/testfiles/storage_csm_powerscale_alt_vals_3.yaml @@ -153,7 +153,7 @@ spec: - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" - # Uncomment if nodes you wish to use have the node-role.kubernetes.io/master taint + # Uncomment if nodes you wish to use have the node-role.kubernetes.io/master taint - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" diff --git a/tests/shared/common.go b/tests/shared/common.go index e0323708..1a422640 100644 --- a/tests/shared/common.go +++ b/tests/shared/common.go @@ -116,7 +116,7 @@ func MakeModuleCSM(name, ns, configVersion string) csmv1.ContainerStorageModule func MakeDriver(configVersion, skipCertValid string) csmv1.Driver { driverObj := csmv1.Driver{ ConfigVersion: configVersion, - Common: csmv1.ContainerTemplate{ + Common: &csmv1.ContainerTemplate{ Envs: []corev1.EnvVar{ { Name: "X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION",