diff --git a/.github/workflows/kustomize-cinder-volume-netapp.yaml b/.github/workflows/kustomize-cinder-volume-netapp.yaml new file mode 100644 index 00000000..6cb8069d --- /dev/null +++ b/.github/workflows/kustomize-cinder-volume-netapp.yaml @@ -0,0 +1,28 @@ +name: Kustomize GitHub Actions for cinder-volume-netapp + +on: + pull_request: + paths: + - base-kustomize/cinder/netapp/** + - .github/workflows/kustomize-cinder-volume-netapp.yaml +jobs: + kustomize: + name: Kustomize + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Kustomize Install + working-directory: /usr/local/bin/ + run: | + if [ ! -f /usr/local/bin/kustomize ]; then + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | sudo bash + fi + - name: Run Kustomize Build + run: | + kustomize build base-kustomize/cinder/netapp/ > /tmp/rendered.yaml + - name: Return Kustomize Build + uses: actions/upload-artifact@v4 + with: + name: kustomize-cinder-volume-netapp-artifact + path: /tmp/rendered.yaml diff --git a/base-kustomize/cinder/netapp/configmap-etc.yaml b/base-kustomize/cinder/netapp/configmap-etc.yaml new file mode 100644 index 00000000..ffc52713 --- /dev/null +++ b/base-kustomize/cinder/netapp/configmap-etc.yaml @@ -0,0 +1,53 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cinder-volume-netapp-config + namespace: openstack +data: + cinder-volume.sh: | + #!/bin/bash + set -ex + exec cinder-volume --config-file /etc/cinder/cinder.conf \ + --config-file /tmp/pod-shared/backends.conf \ + --config-file /tmp/pod-shared/internal_tenant.conf \ + --config-file /tmp/pod-shared/cinder-netapp.conf + generate-backends.py: | + #!/usr/bin/env python3 + import configparser + import os + netapp_backends = os.environ.get('NETAPP_BACKENDS') + config = configparser.ConfigParser() + for backend in netapp_backends.split(';'): + backend = backend.split(',') + assert len(backend) == 11 + config.add_section(backend[0]) + config.set(backend[0], 'netapp_login', backend[1]) + config.set(backend[0], 'netapp_password', backend[2]) + config.set(backend[0], 'netapp_server_hostname', backend[3]) + config.set(backend[0], 'netapp_server_port', backend[4]) + config.set(backend[0], 'netapp_storage_family', 'ontap_cluster') + config.set(backend[0], 'netapp_storage_protocol', 'iscsi') + config.set(backend[0], 'netapp_transport_type', 'http') + config.set(backend[0], 'netapp_vserver', backend[5]) + config.set(backend[0], 'netapp:qos_policy_group', backend[6]) + config.set(backend[0], 'netapp_dedup', backend[7]) + config.set(backend[0], 'netapp_compression', backend[8]) + config.set(backend[0], 'netapp_thick_provisioned', backend[9]) + config.set(backend[0], 'netapp_lun_space_reservation', backend[10]) + config.set(backend[0], 'volume_driver', 'cinder.volume.drivers.netapp.common.NetAppDriver') + config.set(backend[0], 'volume_backend_name', backend[0]) + print(f'Added backend {backend[0]}') + with open('/tmp/pod-shared/backends.conf', 'w') as configfile: + config.write(configfile) + print('Generated backends.conf') + + config = configparser.ConfigParser() + backends = ','.join([i.split(',')[0] for i in netapp_backends.split(';')]) + config.set('DEFAULT', 'enabled_backends', backends) + config.set('DEFAULT', 'host', 'cinder-volume-netapp-worker') + with open('/tmp/pod-shared/cinder-netapp.conf', 'w') as configfile: + config.write(configfile) + print('Updated cinder.conf') + ssh_known_hosts: | + # Empty SSH host file managed by cinder-volume-netapp diff --git a/base-kustomize/cinder/netapp/deploy-volume-netapp.yaml b/base-kustomize/cinder/netapp/deploy-volume-netapp.yaml new file mode 100644 index 00000000..56151301 --- /dev/null +++ b/base-kustomize/cinder/netapp/deploy-volume-netapp.yaml @@ -0,0 +1,346 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cinder-volume-netapp + namespace: openstack +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cinder-openstack-cinder-volume-netapp + namespace: openstack +rules: + - apiGroups: + - "" + - extensions + - batch + - apps + verbs: + - get + - list + resources: + - services + - endpoints + - jobs + - pods + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cinder-cinder-volume-netapp + namespace: openstack +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cinder-openstack-cinder-volume-netapp +subjects: + - kind: ServiceAccount + name: cinder-volume-netapp + namespace: openstack + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cinder-volume-netapp + labels: + release_group: cinder + application: cinder + component: volume +spec: + replicas: 1 + selector: + matchLabels: + release_group: cinder + application: cinder + component: volume + revisionHistoryLimit: 3 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 3 + template: + metadata: + labels: + release_group: cinder + application: cinder + component: volume + spec: + serviceAccountName: cinder-volume-netapp + securityContext: + runAsUser: 42424 + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: release_group + operator: In + values: + - cinder + - key: application + operator: In + values: + - cinder + - key: component + operator: In + values: + - volume + topologyKey: kubernetes.io/hostname + weight: 10 + nodeSelector: + openstack-control-plane: enabled + initContainers: + - name: init + image: image-kubernetes-entrypoint-init + imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 65534 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INTERFACE_NAME + value: eth0 + - name: PATH + value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/ + - name: DEPENDENCY_SERVICE + value: "openstack:keystone-api,openstack:cinder-api" + - name: DEPENDENCY_JOBS + value: "cinder-db-sync,cinder-ks-user,cinder-ks-endpoints" + - name: DEPENDENCY_DAEMONSET + value: "" + - name: DEPENDENCY_CONTAINER + value: "" + - name: DEPENDENCY_POD_JSON + value: "" + - name: DEPENDENCY_CUSTOM_RESOURCE + value: "" + command: + - kubernetes-entrypoint + volumeMounts: [] + - name: init-cinder-conf + securityContext: + readOnlyRootFilesystem: true + runAsUser: 0 + image: image-heat-conf-init + imagePullPolicy: IfNotPresent + command: + - /tmp/retrieve-internal-tenant.sh + volumeMounts: + - name: pod-tmp + mountPath: /tmp + - name: cinder-bin + mountPath: /tmp/retrieve-internal-tenant.sh + subPath: retrieve-internal-tenant.sh + readOnly: true + - name: pod-shared + mountPath: /tmp/pod-shared + env: + - name: OS_IDENTITY_API_VERSION + value: "3" + - name: OS_AUTH_URL + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_AUTH_URL + - name: OS_REGION_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_REGION_NAME + - name: OS_INTERFACE + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_INTERFACE + - name: OS_ENDPOINT_TYPE + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_INTERFACE + - name: OS_PROJECT_DOMAIN_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_PROJECT_DOMAIN_NAME + - name: OS_PROJECT_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_PROJECT_NAME + - name: OS_USER_DOMAIN_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_USER_DOMAIN_NAME + - name: OS_USERNAME + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_USERNAME + - name: OS_PASSWORD + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_PASSWORD + - name: OS_DEFAULT_DOMAIN + valueFrom: + secretKeyRef: + name: cinder-keystone-admin + key: OS_DEFAULT_DOMAIN + - name: INTERNAL_PROJECT_NAME + value: "internal_cinder" + - name: INTERNAL_USER_NAME + value: "internal_cinder" + - name: SERVICE_OS_REGION_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-user + key: OS_REGION_NAME + - name: SERVICE_OS_PROJECT_DOMAIN_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-user + key: OS_PROJECT_DOMAIN_NAME + - name: SERVICE_OS_PROJECT_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-user + key: OS_PROJECT_NAME + - name: SERVICE_OS_USER_DOMAIN_NAME + valueFrom: + secretKeyRef: + name: cinder-keystone-user + key: OS_USER_DOMAIN_NAME + - name: SERVICE_OS_USERNAME + valueFrom: + secretKeyRef: + name: cinder-keystone-user + key: OS_USERNAME + - name: SERVICE_OS_PASSWORD + valueFrom: + secretKeyRef: + name: cinder-keystone-user + key: OS_PASSWORD + - name: cinder-volume-netapp-init + image: image-cinder-volume-netapp-init + imagePullPolicy: IfNotPresent + securityContext: + readOnlyRootFilesystem: true + command: + - /var/lib/openstack/bin/python3 + - /tmp/generate-backends.py + env: + - name: NETAPP_BACKENDS + valueFrom: + secretKeyRef: + name: cinder-netapp + key: BACKENDS + terminationMessagePath: /var/log/termination-log + resources: + limits: + memory: "1Gi" + requests: + memory: "256Mi" + cpu: "250m" + volumeMounts: + - name: cinder-netapp-data + mountPath: /tmp/generate-backends.py + subPath: generate-backends.py + readOnly: true + - name: pod-shared + mountPath: /tmp/pod-shared + containers: + - name: cinder-volume-netapp + image: image-cinder-volume-netapp + imagePullPolicy: IfNotPresent + securityContext: + capabilities: + add: + - SYS_ADMIN + readOnlyRootFilesystem: true + command: + - /tmp/cinder-volume.sh + env: [] + terminationMessagePath: /var/log/termination-log + resources: + limits: + memory: "1Gi" + requests: + memory: "256Mi" + cpu: "250m" + volumeMounts: + - name: pod-tmp + mountPath: /tmp + - name: cinder-netapp-data + mountPath: /tmp/cinder-volume.sh + subPath: cinder-volume.sh + readOnly: true + - name: pod-shared + mountPath: /tmp/pod-shared + - name: cinder-conversion + mountPath: /var/lib/cinder/conversion + - name: cinder-etc + mountPath: /etc/cinder/cinder.conf + subPath: cinder.conf + readOnly: true + - name: cinder-etc + mountPath: /etc/cinder/logging.conf + subPath: logging.conf + readOnly: true + - name: cinder-coordination + mountPath: /var/lib/cinder/coordination + - name: cinder-netapp-data + mountPath: /var/lib/cinder/ssh_known_hosts + subPath: ssh_known_hosts + - name: cinder-etc + mountPath: /etc/sudoers.d/kolla_cinder_sudoers + subPath: cinder_sudoers + readOnly: true + - name: cinder-etc + mountPath: /etc/sudoers.d/kolla_cinder_volume_sudoers + subPath: cinder_sudoers + readOnly: true + - name: cinder-etc + mountPath: /etc/cinder/rootwrap.conf + subPath: rootwrap.conf + readOnly: true + - name: cinder-etc + mountPath: /etc/cinder/rootwrap.d/volume.filters + subPath: volume.filters + readOnly: true + volumes: + - name: pod-tmp + emptyDir: {} + - name: cinder-bin + configMap: + name: cinder-bin + defaultMode: 0555 + - name: cinder-etc + secret: + secretName: cinder-etc + defaultMode: 0444 + - name: pod-shared + emptyDir: {} + - name: cinder-conversion + emptyDir: {} + - name: cinder-coordination + emptyDir: {} + - name: cinder-netapp-data + configMap: + name: "cinder-volume-netapp-config" + defaultMode: 0555 diff --git a/base-kustomize/cinder/netapp/hpa-cinder-volume-netapp.yaml b/base-kustomize/cinder/netapp/hpa-cinder-volume-netapp.yaml new file mode 100644 index 00000000..6dd3b5ee --- /dev/null +++ b/base-kustomize/cinder/netapp/hpa-cinder-volume-netapp.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: cinder-volume-netapp + namespace: openstack +spec: + maxReplicas: 9 + minReplicas: 3 + metrics: + - resource: + name: cpu + target: + averageUtilization: 50 + type: Utilization + type: Resource + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: cinder-volume-netapp diff --git a/base-kustomize/cinder/netapp/kustomization.yaml b/base-kustomize/cinder/netapp/kustomization.yaml new file mode 100644 index 00000000..f921fb7f --- /dev/null +++ b/base-kustomize/cinder/netapp/kustomization.yaml @@ -0,0 +1,18 @@ +images: + - name: image-kubernetes-entrypoint-init + newName: quay.io/airshipit/kubernetes-entrypoint + newTag: v1.0.0 + - name: image-heat-conf-init + newName: docker.io/openstackhelm/heat + newTag: 2024.1-ubuntu_jammy + - name: image-cinder-volume-netapp-init + newName: docker.io/openstackhelm/cinder + newTag: 2024.1-ubuntu_jammy + - name: image-cinder-volume-netapp + newName: docker.io/openstackhelm/cinder + newTag: 2024.1-ubuntu_jammy + +resources: + - configmap-etc.yaml + - deploy-volume-netapp.yaml + - hpa-cinder-volume-netapp.yaml diff --git a/docs/openstack-cinder-netapp.md b/docs/openstack-cinder-netapp.md new file mode 100644 index 00000000..e7ac3644 --- /dev/null +++ b/docs/openstack-cinder-netapp.md @@ -0,0 +1,65 @@ +# NetApp Volume Worker Configuration Documentation + +This document provides information on configuring NetApp backends for the isolated Cinder volume worker. Each backend is defined by a set of +11 comma-separated options, and multiple backends can be specified by separating them with semicolons. + +## Backend Options + +Below is a table detailing each option, its position in the backend configuration, a description, and the expected data type. + +| Option Index | Option Name | Description | Type | +|--------------|-------------------------------|------------------------------------------------------------------------------|---------| +| 0 | `backend_name` | The name of the backend configuration section. Used as `volume_backend_name`.| String | +| 1 | `netapp_login` | Username for authenticating with the NetApp storage system. | String | +| 2 | `netapp_password` | Password for authenticating with the NetApp storage system. | String | +| 3 | `netapp_server_hostname` | Hostname or IP address of the NetApp storage system. | String | +| 4 | `netapp_server_port` | Port number to communicate with the NetApp storage system. | Integer | +| 5 | `netapp_vserver` | The name of the Vserver on the NetApp storage system. | String | +| 6 | `netapp:qos_policy_group` | The name of the QoS policy group. | String | +| 7 | `netapp_dedup` | Enable (`True`) or disable (`False`) deduplication. | Boolean | +| 8 | `netapp_compression` | Enable (`True`) or disable (`False`) compression. | Boolean | +| 9 | `netapp_thick_provisioned` | Use thick (`True`) or thin (`False`) provisioning. | Boolean | +| 10 | `netapp_lun_space_reservation`| Enable (`enabled`) or disable (`disabled`) LUN space reservation. | String | + +### Detailed Option Descriptions + +- **`backend_name`**: A unique identifier for the backend configuration. This name is used internally by Cinder to distinguish between different backends. +- **`netapp_login`**: The username credential required to authenticate with the NetApp storage system. +- **`netapp_password`**: The password credential required for authentication. Ensure this is kept secure. +- **`netapp_server_hostname`**: The address of the NetApp storage system. This can be either an IP address or a fully qualified domain name (FQDN). +- **`netapp_server_port`**: The port number used for communication with the NetApp storage system. Common ports are `80` for HTTP and `443` for HTTPS. +- **`netapp_vserver`**: Specifies the virtual storage server (Vserver) on the NetApp storage system that will serve the volumes. +- **`netapp:qos_policy_group`**: The Quality of Service (QoS) policy group name that will be applied to volumes for this backend. +- **`netapp_dedup`**: A boolean value to enable or disable deduplication on the storage volumes. Acceptable values are `True` or `False`. +- **`netapp_compression`**: A boolean value to enable or disable compression on the storage volumes. Acceptable values are `True` or `False`. +- **`netapp_thick_provisioned`**: Determines whether volumes are thick (`True`) or thin (`False`) provisioned. +- **`netapp_lun_space_reservation`**: A String indicating whether to enable space reservation for LUNs. If `enabled`, space is reserved for the entire LUN size at creation time. + +## Example opaque Configuration + +Before deploying the NetApp volume worker, create the necessary Kubernetes secret with the `BACKENDS` environment variable: + +```shell +kubectl --namespace openstack create secret generic cinder-netapp \ + --type Opaque \ + --from-literal=BACKENDS="backend1,user1,password1,host1,80,vserver1,qos1,True,True,False,enabled" +``` + +### `BACKENDS` Environment Variable Structure + +The `BACKENDS` environment variable is used to pass backend configurations to the NetApp volume worker. Each backend configuration consists of 11 options +in a specific order. + +!!! Example "Replace the placeholder values with your actual backend configuration details" + + ```shell + BACKENDS="backend1,user1,password1,host1,80,vserver1,qos1,True,True,False,disabled;backend2,user2,password2,host2,443,vserver2,qos2,False,True,True,enabled" + ``` + +## Run the deployment + +With your configuration defined, run the deployment with a standard `kubectl apply` command. + +``` shell +kubectl --namespace openstack apply -k /etc/genestack/kustomize/cinder/netapp +``` diff --git a/mkdocs.yml b/mkdocs.yml index a3e8adf7..5f97d72b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -187,6 +187,7 @@ nav: - Block Storage: - Cinder: openstack-cinder.md - LVM iSCSI: openstack-cinder-lvmisci.md + - NETAPP: openstack-cinder-netapp.md - FIPS Cinder Encryption: openstack-cinder-fips-encryption.md - Compute Kit: - Compute Overview: openstack-compute-kit.md