From 3ff5d9a7ae9e0a5077b4d03d80bd60db940e07d5 Mon Sep 17 00:00:00 2001 From: Michael Mattsson Date: Sun, 7 May 2023 18:54:40 -0700 Subject: [PATCH] Fixes for #41 (#42) Signed-off-by: Michael Mattsson --- INSTALL.md | 15 +++++----- K8s/v2.3.10/hpe-storageclass-nfs.yaml | 25 +++++++++++++++++ K8s/v2.3.10/hpe-storageclass.yaml | 24 ++++++++++++++++ K8s/v2.3.10/truenas-csp.yaml | 38 ++++++++++++++++++++++++++ K8s/v2.3.10/truenas-secret.yaml | 12 ++++++++ README.md | 5 ++++ docs/index.yaml | 35 +++++++++++++++++++++++- docs/truenas-csp-1.1.4.tgz | Bin 0 -> 21954 bytes helm/charts/truenas-csp/Chart.yaml | 4 +-- helm/charts/truenas-csp/README.md | 3 +- helm/charts/truenas-csp/values.yaml | 2 +- truenascsp/backend.py | 15 ++++++++-- truenascsp/truenascsp.py | 7 ++--- 13 files changed, 163 insertions(+), 22 deletions(-) create mode 100644 K8s/v2.3.10/hpe-storageclass-nfs.yaml create mode 100644 K8s/v2.3.10/hpe-storageclass.yaml create mode 100644 K8s/v2.3.10/truenas-csp.yaml create mode 100644 K8s/v2.3.10/truenas-secret.yaml create mode 100644 docs/truenas-csp-1.1.4.tgz diff --git a/INSTALL.md b/INSTALL.md index bfa94cf..cc0e838 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -7,7 +7,6 @@ These procedures assumes a running Kubernetes cluster [supported by the HPE CSI - TrueNAS 12.0 or later - TrueNAS SCALE 22.02 or later - FreeNAS 11.2-U3 or later -- Kubernetes 1.23 or later - Helm 3.6 or later (recommended, only needed if using Helm to install the CSP) ### TrueNAS Container Storage Provider Helm Chart @@ -22,9 +21,10 @@ The HPE CSI Driver may be installed using either a Helm Chart, Operator or direc **Note:** The [TrueNAS Container Storage Provider Helm Chart](https://artifacthub.io/packages/helm/truenas-csp/truenas-csp) has a dependency on the HPE CSI Driver for Kubernetes Helm Chart and makes it a lot easier to manage configuration during runtime. Consider using Helm to deploy the CSP over the YAML manifests. -Install HPE CSI Driver using manifests: +Install HPE CSI Driver using manifests (assumes latest supported Kubernetes version of the CSI driver): ``` +kubectl create ns hpe-storage kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.3.0/hpe-linux-config.yaml kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.3.0/hpe-csi-k8s-1.26.yaml ``` @@ -32,8 +32,7 @@ kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/m Install the TrueNAS CSP using manifests: ``` -kubectl create ns hpe-storage -kubectl create -f https://raw.githubusercontent.com/hpe-storage/truenas-csp/master/K8s/v2.3.0/truenas-csp.yaml +kubectl create -f https://raw.githubusercontent.com/hpe-storage/truenas-csp/master/K8s/v2.3.10/truenas-csp.yaml ``` **Note:** Replace `hpe-csi-k8s-.yaml` with your version of Kubernetes. Also change the version of the HPE CSI Driver manifests where applicable. Using mismatching versions of the TrueNAS CSP and the HPE CSI Driver will most likely **NOT** work. @@ -52,7 +51,7 @@ metadata: stringData: serviceName: truenas-csp-svc servicePort: "8080" - username: hpe-csi (username is a no-op) + username: hpe-csi (username is a no-op when using API key) password: API key or root password of TrueNAS/FreeNAS appliance backend: Management IP address of TrueNAS/FreeNAS appliance ``` @@ -66,15 +65,15 @@ The TrueNAS/FreeNAS appliance require an iSCSI portal to be configured manually ![](https://hpe-storage.github.io/truenas-csp/assets/portal.png) - Description: `hpe-csi` -- IP Address: List of IPs used for iSCSI (do NOT use 0.0.0.0) +- IP Address: List of IPs used for iSCSI (do **NOT** use 0.0.0.0) -The Target Global Configuration needs to be updated with this Base Name: +The Target Global Configuration needs to have an explicit Base Name: ![](https://hpe-storage.github.io/truenas-csp/assets/global-target.png) - Base Name: `iqn.2011-08.org.truenas.ctl` or `iqn.2005-10.org.freenas.ctl` -**Hint:** If TrueNAS/FreeNAS is not giving you the option to select nothing but 0.0.0.0 in the portal configuration is because you're using DHCP. Only statically assigned addresses can be used in the picker. +**Hint:** If TrueNAS/FreeNAS is not giving you the option to select nothing but 0.0.0.0 in the portal configuration is because DHCP is being used. Only statically assigned addresses can be used in the picker. Also make sure the iSCSI service is started and enabled at boot on TrueNAS/FreeNAS. diff --git a/K8s/v2.3.10/hpe-storageclass-nfs.yaml b/K8s/v2.3.10/hpe-storageclass-nfs.yaml new file mode 100644 index 0000000..0cfca16 --- /dev/null +++ b/K8s/v2.3.10/hpe-storageclass-nfs.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + annotations: + storageclass.kubernetes.io/is-default-class: "false" + name: hpe-standard-nfs +provisioner: csi.hpe.com +parameters: + csi.storage.k8s.io/controller-expand-secret-name: truenas-secret + csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage + csi.storage.k8s.io/controller-publish-secret-name: truenas-secret + csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage + csi.storage.k8s.io/node-publish-secret-name: truenas-secret + csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage + csi.storage.k8s.io/node-stage-secret-name: truenas-secret + csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage + csi.storage.k8s.io/provisioner-secret-name: truenas-secret + csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage + csi.storage.k8s.io/fstype: xfs + nfsResources: "true" + allowOverrides: sparse,compression,deduplication,volblocksize,sync,description + root: zwimming/csi-volumes +reclaimPolicy: Delete +allowVolumeExpansion: true diff --git a/K8s/v2.3.10/hpe-storageclass.yaml b/K8s/v2.3.10/hpe-storageclass.yaml new file mode 100644 index 0000000..ebc877f --- /dev/null +++ b/K8s/v2.3.10/hpe-storageclass.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + annotations: + storageclass.kubernetes.io/is-default-class: "true" + name: hpe-standard +provisioner: csi.hpe.com +parameters: + csi.storage.k8s.io/controller-expand-secret-name: truenas-secret + csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage + csi.storage.k8s.io/controller-publish-secret-name: truenas-secret + csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage + csi.storage.k8s.io/node-publish-secret-name: truenas-secret + csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage + csi.storage.k8s.io/node-stage-secret-name: truenas-secret + csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage + csi.storage.k8s.io/provisioner-secret-name: truenas-secret + csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage + csi.storage.k8s.io/fstype: xfs + allowOverrides: sparse,compression,deduplication,volblocksize,sync,description + root: zwimming/csi-volumes +reclaimPolicy: Delete +allowVolumeExpansion: true diff --git a/K8s/v2.3.10/truenas-csp.yaml b/K8s/v2.3.10/truenas-csp.yaml new file mode 100644 index 0000000..5ee1e2a --- /dev/null +++ b/K8s/v2.3.10/truenas-csp.yaml @@ -0,0 +1,38 @@ +--- +kind: Service +apiVersion: v1 +metadata: + name: truenas-csp-svc + namespace: hpe-storage + labels: + app: truenas-csp-svc +spec: + ports: + - port: 8080 + protocol: TCP + selector: + app: truenas-csp + +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: truenas-csp + namespace: hpe-storage +spec: + selector: + matchLabels: + app: truenas-csp + replicas: 1 + template: + metadata: + labels: + app: truenas-csp + spec: + priorityClassName: system-cluster-critical + containers: + - name: truenas-csp + image: quay.io/datamattsson/truenas-csp:v2.3.10 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 diff --git a/K8s/v2.3.10/truenas-secret.yaml b/K8s/v2.3.10/truenas-secret.yaml new file mode 100644 index 0000000..aa3947e --- /dev/null +++ b/K8s/v2.3.10/truenas-secret.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: truenas-secret + namespace: hpe-storage +stringData: + serviceName: truenas-csp-svc + servicePort: "8080" + username: hpe-csi (username is a no-op) + password: API key or root password of TrueNAS/FreeNAS appliance + backend: Management IP address of TrueNAS/FreeNAS appliance diff --git a/README.md b/README.md index 9c62d89..fab7042 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Topology is currently not supported by the HPE CSI Driver. Releases will track the upstream versioning of the HPE CSI Driver for Kubernetes and potential bugfixes in the TrueNAS CSP will be pushed to the same image tag matching the HPE CSI Driver version. +* [TrueNAS CSP v2.3.10](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.3.10) for HPE CSI Driver v2.3.0 * [TrueNAS CSP v2.3.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.3.0) for HPE CSI Driver v2.3.0 * [TrueNAS CSP v2.2.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.2.0) for HPE CSI Driver v2.2.0 * [TrueNAS CSP v2.1.1](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.1.1) for HPE CSI Driver v2.1.1 @@ -37,6 +38,10 @@ Releases will track the upstream versioning of the HPE CSI Driver for Kubernetes * [TrueNAS CORE CSP v1.4.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v1.4.0) for HPE CSI Driver v1.4.0 * [TrueNAS CORE CSP v1.3.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v1.3.0) for HPE CSI Driver v1.3.0 +# Version schemes + +The TrueNAS CSP will track an official release of the HPE CSI Driver for Kubernetes, i.e v2.2.0 and there will be a subsequent release of the TrueNAS CSP v2.2.0. If a patch release of the CSP is needed, the patch position will be incremented by 10. I.e v2.2.10. The last digit will represent the patch version of the CSI driver. The [Helm chart](https://artifacthub.io/packages/helm/truenas-csp/truenas-csp) is it's own deliverable and has its own semantic versioning. + # Install See [INSTALL](INSTALL.md). diff --git a/docs/index.yaml b/docs/index.yaml index 81a0291..66b50dc 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -1,6 +1,39 @@ apiVersion: v1 entries: truenas-csp: + - annotations: + artifacthub.io/license: MIT + artifacthub.io/links: | + - name: HPE CSI Driver for Kubernetes + url: https://scod.hpedev.io + - name: Install + url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md + artifacthub.io/prerelease: "false" + apiVersion: v2 + appVersion: 2.3.10 + created: "2023-05-07T18:50:16.384944624-07:00" + dependencies: + - name: hpe-csi-driver + repository: https://hpe-storage.github.io/co-deployments + version: 2.3.0 + description: TrueNAS Container Storage Provider Helm chart for Kubernetes + digest: ff1b4d617477b6f55d3debd3820b69b7280acd721ad686b736025f30266df380 + home: https://github.com/hpe-storage/truenas-csp + icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg + keywords: + - HPE + - Storage + - CSI + maintainers: + - email: michael.mattsson@gmail.com + name: Michael Mattsson + name: truenas-csp + sources: + - https://github.com/hpe-storage/truenas-csp + type: application + urls: + - truenas-csp-1.1.4.tgz + version: 1.1.4 - annotations: artifacthub.io/license: MIT artifacthub.io/links: | @@ -166,4 +199,4 @@ entries: urls: - truenas-csp-1.0.0.tgz version: 1.0.0 -generated: "2023-05-04T22:52:19.983893272-07:00" +generated: "2023-05-07T18:50:16.383697211-07:00" diff --git a/docs/truenas-csp-1.1.4.tgz b/docs/truenas-csp-1.1.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..8c1da6324fa323fdb75cc986b5f49b446a595d4d GIT binary patch literal 21954 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 ZY@W@td7kj|{{;X5|NkAZywL!z0su6q*-iie literal 0 HcmV?d00001 diff --git a/helm/charts/truenas-csp/Chart.yaml b/helm/charts/truenas-csp/Chart.yaml index d3d9764..aae6645 100644 --- a/helm/charts/truenas-csp/Chart.yaml +++ b/helm/charts/truenas-csp/Chart.yaml @@ -12,8 +12,8 @@ annotations: - name: Install url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md artifacthub.io/prerelease: "false" -version: "1.1.3" -appVersion: "2.3.0" +version: "1.1.4" +appVersion: "2.3.10" maintainers: - name: Michael Mattsson email: michael.mattsson@gmail.com diff --git a/helm/charts/truenas-csp/README.md b/helm/charts/truenas-csp/README.md index eefd17a..0f3d546 100644 --- a/helm/charts/truenas-csp/README.md +++ b/helm/charts/truenas-csp/README.md @@ -4,12 +4,11 @@ This Chart provide means to install the dependent [HPE CSI Driver for Kubernetes ## Prerequisites -- Fulfill all requirements of the [HPE CSI Driver for Kubernetes Helm chart](https://artifacthub.io/packages/helm/hpe-storage/hpe-csi-driver/2.3.0) v2.3.0 - TrueNAS 12.0 or later - TrueNAS SCALE 22.02 or later - FreeNAS 11.2-U3 or later -This chart is lock stepped with [HPE CSI Driver for Kubernetes Helm chart](https://artifacthub.io/packages/helm/hpe-storage/hpe-csi-driver) application versions. Other requirements and prerequisites may be found on that chart. +This chart is lock stepped with [HPE CSI Driver for Kubernetes Helm chart](https://artifacthub.io/packages/helm/hpe-storage/hpe-csi-driver) application versions. Other requirements and prerequisites such as supported host OS and Kubernetes versions may be found on that chart. **IMPORTANT:** Do **NOT** install this chart if the HPE CSI Driver for Kubernetes is already installed! diff --git a/helm/charts/truenas-csp/values.yaml b/helm/charts/truenas-csp/values.yaml index d811edf..a4397b1 100644 --- a/helm/charts/truenas-csp/values.yaml +++ b/helm/charts/truenas-csp/values.yaml @@ -11,7 +11,7 @@ image: repository: quay.io/datamattsson/truenas-csp pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. - tag: "v2.3.0" + tag: "v2.3.10" imagePullSecrets: [] nameOverride: "" diff --git a/truenascsp/backend.py b/truenascsp/backend.py index 443fed6..d0f6313 100755 --- a/truenascsp/backend.py +++ b/truenascsp/backend.py @@ -111,7 +111,7 @@ def ping(self, req): self.logger.debug(' headers: %s', headers) def ipaddrs_to_networks(self, ipaddrs): - interfaces = self.fetch('interface') + interfaces = self.fetch('interface', returnBy=list) networks = [] @@ -255,11 +255,20 @@ def fetch(self, resource, **kwargs): if len(results) == 1: self.logger.debug('API fetch caught 1 item') - return results[0] + + if kwargs.get('returnBy') == list: + return results + else: + return results[0] if len(results) > 1: self.logger.debug('API fetch caught %d items', len(results)) - return results + + if kwargs.get('returnBy') == dict: + self.logger.debug('Returning first row in result set') + return results[0] + else: + return results return None diff --git a/truenascsp/truenascsp.py b/truenascsp/truenascsp.py index 57b6192..a0294d5 100755 --- a/truenascsp/truenascsp.py +++ b/truenascsp/truenascsp.py @@ -128,7 +128,7 @@ def on_put(self, req, resp, volume_id): # grab host initiator = api.fetch( - 'iscsi/initiator', field='comment', value=content.get('host_uuid')) + 'iscsi/initiator', field='comment', value=content.get('host_uuid'), returnBy=dict) # grab portal IPs portal = api.fetch('iscsi/portal', field='comment', @@ -440,10 +440,7 @@ def on_post(self, req, resp): req_backend['auth_network'] = api.cidrs_to_hosts(content.get('networks')) initiator = api.fetch( - 'iscsi/initiator', field='comment', value=content.get('uuid')) - - # rare condition (race during initial creation) - initiator = initiator[0] if isinstance(initiator, list) else initiator + 'iscsi/initiator', field='comment', value=content.get('uuid'), returnBy=dict) if initiator: api.put(