├── .gitignore ├── CODEOWNERS ├── CONTRIBUTING.md ├── Dockerfile ├── INSTALL.md ├── K8s ├── edge │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v1.3.0 │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v1.4.0 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.0.0 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.1.0-arm64 │ ├── hpe-csi-k8s-1.23-arm64.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.1.0 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.2.0 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.3.0 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.3.10 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.4.0 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.4.2 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── v2.5.1 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml └── v2.5.2 │ ├── hpe-storageclass-nfs.yaml │ ├── hpe-storageclass.yaml │ ├── truenas-csp.yaml │ └── truenas-secret.yaml ├── LICENSE ├── Makefile ├── README.md ├── docs ├── _config.yml ├── artifacthub-repo.yml ├── assets │ ├── global-target.png │ ├── icon-2048x2048.png │ ├── icon.svg │ └── portal.png ├── index.md ├── index.yaml ├── truenas-csp-1.0.0.tgz ├── truenas-csp-1.1.0.tgz ├── truenas-csp-1.1.1.tgz ├── truenas-csp-1.1.2.tgz ├── truenas-csp-1.1.3.tgz ├── truenas-csp-1.1.4.tgz ├── truenas-csp-1.1.5.tgz ├── truenas-csp-1.1.6.tgz ├── truenas-csp-1.2.0.tgz └── truenas-csp-1.2.1.tgz ├── e2e ├── .gitignore ├── Dockerfile ├── README.md ├── job-rwo.yaml ├── job-rwx-block.yaml ├── job-rwx.yaml ├── kustomization.yaml ├── resources.yaml ├── runner.sh ├── secret-dist.yaml └── tests │ ├── storage-class-rwo.yaml │ ├── storage-class-rwx.yaml │ ├── test-driver-rwo.yaml │ ├── test-driver-rwx-block.yaml │ ├── test-driver-rwx.yaml │ └── volume-snapshot-class.yaml ├── helm └── charts │ ├── Makefile │ └── truenas-csp │ ├── .helmignore │ ├── Chart.lock │ ├── Chart.yaml │ ├── README.md │ ├── charts │ └── hpe-csi-driver-2.5.2.tgz │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── service.yaml │ └── serviceaccount.yaml │ ├── values.schema.json │ └── values.yaml ├── requirements.txt ├── tests ├── csp │ ├── clone.yaml │ ├── initiator-chap.yaml │ ├── initiator-multi.yaml │ ├── initiator.yaml │ ├── mutator-negative.yaml │ ├── mutator.yaml │ ├── mutators.yaml │ ├── publish-chap.yaml │ ├── publish-multi.yaml │ ├── publish.yaml │ ├── snapshot1.yaml │ ├── snapshot2.yaml │ ├── unpublish-chap.yaml │ ├── unpublish-multi.yaml │ ├── unpublish.yaml │ ├── volume-chap.yaml │ ├── volume-thick.yaml │ └── volume.yaml ├── kubevirt │ ├── disk-alpine.yaml │ └── vm-alpine.yaml └── sts │ └── sts.yaml └── truenascsp ├── backend.py ├── csp.py └── truenascsp.py /.gitignore: -------------------------------------------------------------------------------- 1 | e2e/e2e.test 2 | e2e/ginkgo 3 | e2e/reports-* 4 | TODO 5 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @datamattsson 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | We welcome and encourage community contributions to TrueNAS Core CSP. 4 | 5 | ## Contributing 6 | 7 | The best way to directly collaborate with the project contributors is through GitHub: 8 | 9 | * If you want to contribute to our code by either fixing a problem or creating a new feature, please open a GitHub pull request. 10 | * If you want to raise an issue such as a defect, an enhancement request or a general issue, please open a GitHub issue. 11 | 12 | Before you start to code, we recommend discussing your plans through a GitHub issue, especially for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give you feedback on your design, and help you find out if someone else is working on the same thing. 13 | 14 | Note that all patches from all contributors get reviewed. 15 | After a pull request is made, other contributors will offer feedback. If the patch passes review, a maintainer will accept it with a comment. 16 | When a pull request fails review, the author is expected to update the pull request to address the issue until it passes review and the pull request merges successfully. 17 | 18 | At least one review from a maintainer is required for all patches. 19 | 20 | ### Developer's Certificate of Origin 21 | 22 | All contributions must include acceptance of the DCO: 23 | 24 | > Developer Certificate of Origin Version 1.1 25 | > 26 | > Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 660 27 | > York Street, Suite 102, San Francisco, CA 94110 USA 28 | > 29 | > Everyone is permitted to copy and distribute verbatim copies of this 30 | > license document, but changing it is not allowed. 31 | > 32 | > Developer's Certificate of Origin 1.1 33 | > 34 | > By making a contribution to this project, I certify that: 35 | > 36 | > \(a) The contribution was created in whole or in part by me and I have 37 | > the right to submit it under the open source license indicated in the 38 | > file; or 39 | > 40 | > \(b) The contribution is based upon previous work that, to the best of my 41 | > knowledge, is covered under an appropriate open source license and I 42 | > have the right under that license to submit that work with 43 | > modifications, whether created in whole or in part by me, under the same 44 | > open source license (unless I am permitted to submit under a different 45 | > license), as indicated in the file; or 46 | > 47 | > \(c) The contribution was provided directly to me by some other person 48 | > who certified (a), (b) or (c) and I have not modified it. 49 | > 50 | > \(d) I understand and agree that this project and the contribution are 51 | > public and that a record of the contribution (including all personal 52 | > information I submit with it, including my sign-off) is maintained 53 | > indefinitely and may be redistributed consistent with this project or 54 | > the open source license(s) involved. 55 | 56 | ### Sign your work 57 | 58 | To accept the DCO, simply add this line to each commit message with your 59 | name and email address (git commit -s will do this for you): 60 | 61 | Signed-off-by: Jane Example 62 | 63 | For legal reasons, no anonymous or pseudonymous contributions are 64 | accepted. 65 | 66 | ## Submitting Code Pull Requests 67 | 68 | We encourage and support contributions from the community. No fix is too 69 | small. We strive to process all pull requests as soon as possible and 70 | with constructive feedback. If your pull request is not accepted at 71 | first, please try again after addressing the feedback you received. 72 | 73 | To make a pull request you will need a GitHub account. For help, see 74 | GitHub's documentation on forking and pull requests. 75 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21.3 2 | ADD requirements.txt / 3 | RUN apk add --no-cache python3 py3-pip && \ 4 | python3 -m venv /app && \ 5 | /app/bin/pip install -r requirements.txt 6 | ADD truenascsp/*.py /app/ 7 | WORKDIR /app 8 | ENTRYPOINT [ "/app/bin/gunicorn", "--workers", "3", "--bind", "0.0.0.0:8080", "--timeout", "180", "--preload", "csp:SERVE" ] 9 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Install TrueNAS Container Storage Provider 2 | 3 | These procedures assumes a running Kubernetes cluster [supported by the HPE CSI Driver](https://scod.hpedev.io/csi_driver/index.html#compatibility_and_support) where the worker nodes have connectivity to a TrueNAS/FreeNAS storage appliance API and networks used for iSCSI traffic. Worker nodes also need their package managers fully functional and connected to their official repos unless iSCSI and multipathing packages have been pre-installed. 4 | 5 | ## Prerequisites 6 | 7 | - TrueNAS Core 12.0 or later 8 | - TrueNAS SCALE 22.02 or later (see note below) 9 | - FreeNAS 11.2-U3 or later 10 | - Helm 3.6 or later (recommended, only needed if using Helm to install the CSP) 11 | 12 | **Note:** TrueNAS SCALE 25.04 is currently NOT supported. 13 | 14 | ### TrueNAS Container Storage Provider Helm Chart 15 | 16 | The recommended way to install the CSP is to use Helm, it automatically fulfill all dependencies. Make sure to make it back here to learn [how to configure and use the CSP with the CSI driver](https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md#configure-csi-driver). 17 | 18 | - Learn more about the Helm chart on [Artifact Hub](https://artifacthub.io/packages/helm/truenas-csp/truenas-csp) 19 | 20 | ### Install HPE CSI Driver for Kubernetes separately (not recommended) 21 | 22 | The HPE CSI Driver may be installed using either a Helm Chart, Operator or directly with manifests. Directly below is the complete procedures for the "[Advanced install](https://scod.hpedev.io/csi_driver/deployment.html#advanced_install)". 23 | 24 | **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. 25 | 26 | Install HPE CSI Driver using manifests (assumes latest supported Kubernetes version of the CSI driver): 27 | 28 | ``` 29 | kubectl create ns hpe-storage 30 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.5.2/hpe-csi-rbac.yaml 31 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.5.2/hpe-linux-config.yaml 32 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.5.2/csi-driver-crd.yaml 33 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.5.2/crds/hpe-nodeinfo-crd.yaml 34 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.5.2/hpe-csi-node.yaml 35 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/co-deployments/master/yaml/csi-driver/v2.5.2/hpe-csi-controller.yaml 36 | ``` 37 | 38 | Install the TrueNAS CSP using manifests: 39 | 40 | ``` 41 | kubectl create -f https://raw.githubusercontent.com/hpe-storage/truenas-csp/master/K8s/v2.5.2/truenas-csp.yaml 42 | ``` 43 | 44 | **Note:** 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 (manifests reflects the latest version). 45 | 46 | ### Configure CSI driver 47 | 48 | Create a `Secret` that references your TrueNAS/FreeNAS appliance: 49 | 50 | ``` 51 | --- 52 | apiVersion: v1 53 | kind: Secret 54 | metadata: 55 | name: truenas-secret 56 | namespace: hpe-storage 57 | stringData: 58 | serviceName: truenas-csp-svc 59 | servicePort: "8080" 60 | username: hpe-csi (username is a no-op when using API key) 61 | password: API key or root password of TrueNAS/FreeNAS appliance 62 | backend: Management IP address of TrueNAS/FreeNAS appliance 63 | ``` 64 | 65 | **Hint:** Generate an API key by clicking the cog in the upper right corner of the TrueNAS web UI (FreeNAS does NOT support API keys). What you name the key or the `Secret` `{.stringData.username}` does not matter as it's not being used or referenced during runtime. For tracking purposes it might be a good idea to name the key the same as the username put into the `Secret`. 66 | 67 | ### Configure TrueNAS/FreeNAS 68 | 69 | The TrueNAS/FreeNAS appliance require an iSCSI portal to be configured manually with the following characteristics: 70 | 71 | ![](https://hpe-storage.github.io/truenas-csp/assets/portal.png) 72 | 73 | - Description: `hpe-csi` 74 | - IP Address: List of IPs used for iSCSI (do **NOT** use 0.0.0.0) 75 | 76 | The Target Global Configuration needs to have an explicit Base Name: 77 | 78 | ![](https://hpe-storage.github.io/truenas-csp/assets/global-target.png) 79 | 80 | - Base Name: `iqn.2011-08.org.truenas.ctl` or `iqn.2005-10.org.freenas.ctl` 81 | 82 | **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. 83 | 84 | Also make sure the iSCSI service is started and enabled at boot on TrueNAS/FreeNAS. 85 | 86 | The default location for CSI volumes will be in the root of a pool named `tank`. That is most likely not desirable, instead, create a dataset in any of your pools and make note of that, i.e `zwimming/csi-volumes` and configure `root` in the `StorageClass`. 87 | 88 | ## Example StorageClass 89 | 90 | All the ZVols created on TrueNAS/FreeNAS will by default be created with these parameters: 91 | 92 | - volblocksize: 8K 93 | - deduplication: OFF 94 | - compression: LZ4 95 | - sparse: "true" 96 | - sync: STANDARD 97 | - description: "Dataset created by HPE CSI Driver for Kubernetes as {pv} in {namespace} from {pvc}" 98 | - root: tank 99 | 100 | These parameters may be overridden in the `StorageClass` or have the defaults altered by passing environment variables to the CSP runtime with the convention of `DEFAULT_COMPRESSION=OFF`. 101 | 102 | Refer to the TrueNAS/FreeNAS documentation what these dataset parameters do. 103 | 104 | **Note:** Since the iSCSI volumes are backed by ZVols, `volblocksize` will be immutable. 105 | 106 | ``` 107 | --- 108 | apiVersion: storage.k8s.io/v1 109 | kind: StorageClass 110 | metadata: 111 | annotations: 112 | storageclass.kubernetes.io/is-default-class: "true" 113 | name: hpe-storageclass 114 | provisioner: csi.hpe.com 115 | parameters: 116 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 117 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 118 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 119 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 120 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 121 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 122 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 123 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 124 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 125 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 126 | csi.storage.k8s.io/fstype: xfs 127 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 128 | root: zwimming/csi-volumes 129 | reclaimPolicy: Delete 130 | allowVolumeExpansion: true 131 | ``` 132 | 133 | Set `root` to a "FILESYSTEM" dataset that will serve as the base dataset where the ZVols will be created. The `allowOverrides` parameter will allow users to annotate their PVCs with the values that makes sense for their workload. [Learn more here](https://scod.hpedev.io/csi_driver/using.html#using_pvc_overrides). 134 | 135 | **Important:** Do NOT use underscore "`_`" in your root dataset for now, it will most likely break. 136 | 137 | Once the `Secret` and `StorageClass` have been created, all functionality is provided by the HPE CSI Driver and is [documented here](https://scod.hpedev.io/csi_driver/using.html). 138 | 139 | **Tip:** If `VolumeSnapshots` are needed, follow the guidance in HPE CSI Driver documentation on how to [enable CSI snapshots](https://scod.hpedev.io/csi_driver/using.html#enabling_csi_snapshots) and [how to use them](https://scod.hpedev.io/csi_driver/using.html#using_csi_snapshots). 140 | 141 | ## Custom auth_networks on TrueNAS SCALE 142 | 143 | From v2.5.1 onwards it's possible to specifiy a comma separated list of networks in the `StorageClass` form where initiators are allowed to connect to the targets. 144 | 145 | Example: 146 | 147 | ```text 148 | ... 149 | parameters: 150 | authNetworks: 192.168.1.0/24, 192.168.2.0/24 151 | ... 152 | ``` 153 | 154 | **Note:** This only works on TrueNAS SCALE. 155 | 156 | ## CHAP support 157 | 158 | From v2.5.1 onwards iSCSI CHAP is supported. Follow the [guidance provided by HPE](https://scod.hpedev.io/csi_driver/index.html#iscsi_chap_considerations). Retrofitting CHAP into an existing cluster is not recommended. Bi-directional CHAP is not supported by the HPE CSI Driver and will not work with the TrueNAS CSP. 159 | 160 | CHAP on TrueNAS uses a hardcoded tag (4730274) for the authorization on the appliance. As long as that authorization exist on the appliance, CHAP details will be returned to the CSI driver and attempted to connect to the target. Do not create this tag manually, it will be created by TrueNAS CSP when enabled in the HPE CSI Driver. 161 | 162 | **Important:** If you need to rotate the CHAP authorization it's recommended to scale down all workloads, change the `Secret`, and scale the workloads up again. Otherwise existing iSCSI sessions may break. 163 | -------------------------------------------------------------------------------- /K8s/edge/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/edge/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/edge/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:edge 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/edge/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v1.3.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: kube-system 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: kube-system 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: kube-system 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: kube-system 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: kube-system 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v1.3.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: kube-system 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: kube-system 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v1.3.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v1.3.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi 11 | password: TrueNAS CORE API key 12 | backend: TrueNAS CORE management IP address 13 | -------------------------------------------------------------------------------- /K8s/v1.4.0/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v1.4.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v1.4.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v1.4.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v1.4.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi 11 | password: TrueNAS CORE API key 12 | backend: TrueNAS CORE management IP address 13 | -------------------------------------------------------------------------------- /K8s/v2.0.0/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.0.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.0.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.0.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.0.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi 11 | password: TrueNAS CORE API key 12 | backend: TrueNAS CORE management IP address 13 | -------------------------------------------------------------------------------- /K8s/v2.1.0-arm64/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.1.0-arm64/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:edge 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.1.0-arm64/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.1.0/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.1.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.1.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.1.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.1.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.2.0/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.2.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.2.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.2.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.2.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.3.0/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.3.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.3.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.3.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.3.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.3.10/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.3.10/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.3.10/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.3.10 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.3.10/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.4.0/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.4.0/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.4.0/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.4.0 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.4.0/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.4.2/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.4.2/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.4.2/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.4.2 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.4.2/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.5.1/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.5.1/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.5.1/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.5.1 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.5.1/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /K8s/v2.5.2/hpe-storageclass-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "false" 7 | name: hpe-standard-nfs 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | nfsResources: "true" 22 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 23 | root: zwimming/csi-volumes 24 | reclaimPolicy: Delete 25 | allowVolumeExpansion: true 26 | -------------------------------------------------------------------------------- /K8s/v2.5.2/hpe-storageclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | annotations: 6 | storageclass.kubernetes.io/is-default-class: "true" 7 | name: hpe-standard 8 | provisioner: csi.hpe.com 9 | parameters: 10 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 17 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 18 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 19 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 20 | csi.storage.k8s.io/fstype: xfs 21 | allowOverrides: sparse,compression,deduplication,volblocksize,sync,description 22 | root: zwimming/csi-volumes 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /K8s/v2.5.2/truenas-csp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: truenas-csp-svc 6 | namespace: hpe-storage 7 | labels: 8 | app: truenas-csp-svc 9 | spec: 10 | ports: 11 | - port: 8080 12 | protocol: TCP 13 | selector: 14 | app: truenas-csp 15 | 16 | --- 17 | kind: Deployment 18 | apiVersion: apps/v1 19 | metadata: 20 | name: truenas-csp 21 | namespace: hpe-storage 22 | spec: 23 | selector: 24 | matchLabels: 25 | app: truenas-csp 26 | replicas: 1 27 | template: 28 | metadata: 29 | labels: 30 | app: truenas-csp 31 | spec: 32 | priorityClassName: system-cluster-critical 33 | containers: 34 | - name: truenas-csp 35 | image: quay.io/datamattsson/truenas-csp:v2.5.2 36 | imagePullPolicy: IfNotPresent 37 | ports: 38 | - containerPort: 8080 39 | -------------------------------------------------------------------------------- /K8s/v2.5.2/truenas-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: truenas-secret 6 | namespace: hpe-storage 7 | stringData: 8 | serviceName: truenas-csp-svc 9 | servicePort: "8080" 10 | username: hpe-csi (username is a no-op) 11 | password: API key or root password of TrueNAS/FreeNAS appliance 12 | backend: Management IP address of TrueNAS/FreeNAS appliance 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2024 Hewlett Packard Enterprise Development LP 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifndef IMAGE_TAG 2 | IMAGE_TAG ?= edge 3 | endif 4 | 5 | ifndef REPO_NAME 6 | REPO_NAME ?= quay.io/datamattsson/truenas-csp 7 | endif 8 | 9 | username = hpe-csi 10 | csp = http://localhost:8080 11 | curl = curl 12 | curl_args = '-v' 13 | 14 | all: 15 | python3 -m py_compile truenascsp/*.py 16 | rm -rf truenascsp/__pycache__ 17 | docker build -t $(REPO_NAME):$(IMAGE_TAG) . 18 | push: 19 | docker buildx build --platform=linux/amd64,linux/arm64 --progress=plain \ 20 | --provenance=false --push -t $(REPO_NAME):$(IMAGE_TAG) . 21 | run: 22 | docker rm -f truenas-csp || true 23 | docker run -d -p8080:8080 --name truenas-csp -e LOG_DEBUG=1 \ 24 | --pull=always $(REPO_NAME):$(IMAGE_TAG) 25 | 26 | test: 27 | 28 | # Delete host 1 29 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' -H 'X-Auth-Token: $(password)' \ 30 | -H 'X-Array-IP: $(backend)' \ 31 | $(csp)/containers/v1/hosts/41302701-0196-420f-b319-834a79891db0 -f 32 | 33 | # Delete host 2 34 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' -H 'X-Auth-Token: $(password)' \ 35 | -H 'X-Array-IP: $(backend)' \ 36 | $(csp)/containers/v1/hosts/41302701-0196-420f-b319-834a79891db1 -f 37 | 38 | # Delete host 3 39 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 40 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 41 | $(csp)/containers/v1/hosts/41302701-0196-420f-b319-834a79891db2 -f 42 | 43 | # Unpublish volume host 1 44 | - $(curl) $(curl_args) -XPUT -d @tests/csp/unpublish.yaml -H 'Content-Type: application/json' \ 45 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 46 | $(csp)/containers/v1/volumes/tank_my-new-volume16/actions/unpublish -f 47 | 48 | # Unpublish volume host 2 49 | - $(curl) $(curl_args) -XPUT -d @tests/csp/unpublish-multi.yaml -H 'Content-Type: application/json' \ 50 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 51 | $(csp)/containers/v1/volumes/tank_my-new-volume16/actions/unpublish -f 52 | 53 | # Unpublish CHAP volume 54 | - $(curl) $(curl_args) -XPUT -d @tests/csp/unpublish-chap.yaml -H 'Content-Type: application/json' \ 55 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 56 | $(csp)/containers/v1/volumes/tank_my-new-volume377/actions/unpublish -f 57 | 58 | # Delete volume 59 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' -H 'X-Auth-Token: $(password)' \ 60 | -H 'X-Array-IP: $(backend)' \ 61 | $(csp)/containers/v1/volumes/tank_my-new-volume16 -f 62 | 63 | # Delete thick volume 64 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 65 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 66 | $(csp)/containers/v1/volumes/tank_my-new-volume18 -f 67 | 68 | # Delete CHAP volume 69 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 70 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 71 | $(csp)/containers/v1/volumes/tank_my-new-volume377 -f 72 | 73 | # "Create" password 74 | $(curl) $(curl_args) -XPOST \ 75 | -d '{ "array_ip": "$(backend)", "username": "$(username)", "password": "$(password)"}' \ 76 | -H 'Content-Type: application/json' $(csp)/containers/v1/tokens -f 77 | 78 | # Delete password 79 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' $(csp)/containers/v1/tokens/123 -f 80 | 81 | # Fail auth 82 | $(curl) $(curl_args) -XGET -H 'Content-Type: application/json' $(csp)/containers/v1/tokens/123 -f || true 83 | 84 | # Create host 1 85 | $(curl) $(curl_args) -XPOST -d @tests/csp/initiator.yaml -H 'Content-Type: application/json' \ 86 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 87 | $(csp)/containers/v1/hosts -f 88 | 89 | # Create host 2 90 | $(curl) $(curl_args) -XPOST -d @tests/csp/initiator-multi.yaml -H 'Content-Type: application/json' \ 91 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 92 | $(csp)/containers/v1/hosts -f 93 | 94 | # Create volume 95 | $(curl) $(curl_args) -XPOST -d @tests/csp/volume.yaml -H 'Content-Type: application/json' \ 96 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 97 | $(csp)/containers/v1/volumes -f 98 | 99 | # List snapshots 100 | - $(curl) $(curl_args) -H 'Content-Type: application/json' \ 101 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 102 | $(csp)/containers/v1/snapshots?volume_id=tank_my-new-volume16 -f 103 | 104 | # Create thick volume 105 | $(curl) $(curl_args) -XPOST -d @tests/csp/volume-thick.yaml -H 'Content-Type: application/json' \ 106 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 107 | $(csp)/containers/v1/volumes -f 108 | 109 | # Get volume 110 | $(curl) $(curl_args) -XGET -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 111 | $(csp)/containers/v1/volumes?name=my-new-volume16 -f 112 | 113 | # Mutate volume 114 | $(curl) $(curl_args) -XPUT -d @tests/csp/mutator.yaml -H 'Content-Type: application/json' \ 115 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 116 | $(csp)/containers/v1/volumes/tank_my-new-volume16 -f 117 | 118 | $(curl) $(curl_args) -XPUT -d @tests/csp/mutators.yaml -H 'Content-Type: application/json' \ 119 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 120 | $(csp)/containers/v1/volumes/tank_my-new-volume16 -f 121 | 122 | $(curl) $(curl_args) -XPUT -d @tests/csp/mutator-negative.yaml -H 'Content-Type: application/json' \ 123 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 124 | $(csp)/containers/v1/volumes/tank_my-new-volume16 -f || true 125 | 126 | # Publish volume host 1 127 | $(curl) $(curl_args) -XPUT -d @tests/csp/publish.yaml -H 'Content-Type: application/json' \ 128 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 129 | $(csp)/containers/v1/volumes/tank_my-new-volume16/actions/publish -f 130 | 131 | # Publish volume host 2 132 | $(curl) $(curl_args) -XPUT -d @tests/csp/publish-multi.yaml -H 'Content-Type: application/json' \ 133 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 134 | $(csp)/containers/v1/volumes/tank_my-new-volume16/actions/publish -f 135 | 136 | # Create snapshots 137 | $(curl) $(curl_args) -XPOST -d @tests/csp/snapshot1.yaml -H 'Content-Type: application/json' \ 138 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 139 | $(csp)/containers/v1/snapshots -f 140 | $(curl) $(curl_args) -XPOST -d @tests/csp/snapshot2.yaml -H 'Content-Type: application/json' \ 141 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 142 | $(csp)/containers/v1/snapshots -f 143 | 144 | # List snapshots 145 | $(curl) $(curl_args) -H 'Content-Type: application/json' \ 146 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 147 | $(csp)/containers/v1/snapshots?volume_id=tank_my-new-volume16 -f 148 | 149 | # Get snapshots from volume 150 | $(curl) $(curl_args) -XGET -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 151 | $(csp)/containers/v1/snapshots?volume_id=tank_my-new-volume16 -f 152 | $(curl) $(curl_args) -XGET -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 153 | '$(csp)/containers/v1/snapshots?volume_id=tank_my-new-volume16&name=my-first-snapshot' -f 154 | $(curl) $(curl_args) -XGET -H 'Content-Type: application/json' \ 155 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 156 | $(csp)/containers/v1/snapshots/tank_my-new-volume16@my-first-snapshot -f 157 | 158 | # Create clone 159 | $(curl) $(curl_args) -XPOST -d @tests/csp/clone.yaml -H 'Content-Type: application/json' \ 160 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 161 | $(csp)/containers/v1/volumes -f 162 | 163 | # Delete clone 164 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' -H 'X-Auth-Token: $(password)' \ 165 | -H 'X-Array-IP: $(backend)' $(csp)/containers/v1/volumes/tank_my-new-volume17 -f 166 | 167 | # Delete a snapshot 168 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 169 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 170 | $(csp)/containers/v1/snapshots/tank_my-new-volume16@my-first-snapshot -f 171 | 172 | # Delete another snapshot 173 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 174 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 175 | $(csp)/containers/v1/snapshots/tank_my-new-volume16@my-second-snapshot -f 176 | 177 | # List snapshots 178 | - $(curl) $(curl_args) -H 'Content-Type: application/json' \ 179 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 180 | $(csp)/containers/v1/snapshots?volume_id=tank_my-new-volume16 -f 181 | 182 | # Unpublish volume host 1 183 | $(curl) $(curl_args) -XPUT -d @tests/csp/unpublish.yaml -H 'Content-Type: application/json' \ 184 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 185 | $(csp)/containers/v1/volumes/tank_my-new-volume16/actions/unpublish -f 186 | 187 | # Unpublish volume host 2 188 | $(curl) $(curl_args) -XPUT -d @tests/csp/unpublish-multi.yaml -H 'Content-Type: application/json' \ 189 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 190 | $(csp)/containers/v1/volumes/tank_my-new-volume16/actions/unpublish -f 191 | 192 | # Delete volume 193 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 194 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 195 | $(csp)/containers/v1/volumes/tank_my-new-volume16 -f 196 | 197 | # Delete thick volume 198 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 199 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 200 | $(csp)/containers/v1/volumes/tank_my-new-volume18 -f 201 | 202 | # Create host 3 CHAP 203 | $(curl) $(curl_args) -XPOST -d @tests/csp/initiator-chap.yaml -H 'Content-Type: application/json' \ 204 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 205 | $(csp)/containers/v1/hosts -f 206 | 207 | # Create CHAP volume 208 | $(curl) $(curl_args) -XPOST -d @tests/csp/volume-chap.yaml -H 'Content-Type: application/json' \ 209 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 210 | $(csp)/containers/v1/volumes -f 211 | 212 | # Publish CHAP volume 213 | $(curl) $(curl_args) -XPUT -d @tests/csp/publish-chap.yaml -H 'Content-Type: application/json' \ 214 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 215 | $(csp)/containers/v1/volumes/tank_my-new-volume377/actions/publish -f 216 | 217 | 218 | # Unpublish CHAP volume 219 | $(curl) $(curl_args) -XPUT -d @tests/csp/unpublish-chap.yaml -H 'Content-Type: application/json' \ 220 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 221 | $(csp)/containers/v1/volumes/tank_my-new-volume377/actions/unpublish -f 222 | 223 | # Delete volume CHAP 224 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 225 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 226 | $(csp)/containers/v1/volumes/tank_my-new-volume377 -f 227 | 228 | # Delete host CHAP 229 | $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 230 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 231 | $(csp)/containers/v1/hosts/41302701-0196-420f-b319-834a79891db2 -f 232 | 233 | # Delete host 1 234 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 235 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 236 | $(csp)/containers/v1/hosts/41302701-0196-420f-b319-834a79891db0 -f 237 | 238 | # Delete host 2 239 | - $(curl) $(curl_args) -XDELETE -H 'Content-Type: application/json' \ 240 | -H 'X-Auth-Token: $(password)' -H 'X-Array-IP: $(backend)' \ 241 | $(csp)/containers/v1/hosts/41302701-0196-420f-b319-834a79891db1 -f 242 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/truenas-csp)](https://artifacthub.io/packages/search?repo=truenas-csp) 2 | # TrueNAS Container Storage Provider 3 | 4 | The TrueNAS Container Storage Provider (CSP) is an API gateway to provide iSCSI block storage provisioning using the [HPE CSI Driver for Kubernetes](https://github.com/hpe-storage/csi-driver). It allows you to use [TrueNAS](https://www.truenas.com) and [FreeNAS](https://www.freenas.org/) to provide persistent storage using iSCSI to Kubernetes. 5 | 6 | CSP API endpoints: 7 | 8 | - tokens 9 | - hosts 10 | - volumes 11 | - snapshots 12 | - volume_groups (not implemented) 13 | - snapshot_groups (not implemented) 14 | 15 | The [CSP specification](https://github.com/hpe-storage/container-storage-provider) in an open specification that supports iSCSI and Fibre Channel protocols. 16 | 17 | As of version 2.5.2 of the HPE CSI Driver, these parts of the CSI spec are currently implemented: 18 | 19 | - Dynamic Provisioning 20 | - Raw Block Volume 21 | - Volume Expansion 22 | - Data Sources (`PersistentVolumeClaims` and `VolumeSnapshots`) 23 | - Volume Limits 24 | - Volume Stats 25 | - Ephemeral Local Volumes (not supported by the TrueNAS CSP, see [limitations](#limitations)) 26 | - Basic CSI Topology 27 | 28 | # Releases 29 | 30 | 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 Helm chart version. 31 | 32 | * [TrueNAS CSP v2.5.2](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.5.2) for HPE CSI Driver v2.5.2 33 | * [TrueNAS CSP v2.5.1](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.5.1) for HPE CSI Driver v2.5.1 34 | * [TrueNAS CSP v2.4.2](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.4.2) for HPE CSI Driver v2.4.2 35 | * [TrueNAS CSP v2.4.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.4.0) for HPE CSI Driver v2.4.0 36 | * [TrueNAS CSP v2.3.10](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.3.10) for HPE CSI Driver v2.3.0 37 | * [TrueNAS CSP v2.3.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.3.0) for HPE CSI Driver v2.3.0 38 | * [TrueNAS CSP v2.2.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.2.0) for HPE CSI Driver v2.2.0 39 | * [TrueNAS CSP v2.1.1](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.1.1) for HPE CSI Driver v2.1.1 40 | * [TrueNAS CSP v2.1.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.1.0) for HPE CSI Driver v2.1.0 41 | * [TrueNAS CORE CSP v2.0.0](https://github.com/hpe-storage/truenas-csp/releases/tag/v2.0.0) for HPE CSI Driver v2.0.0 42 | * [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 43 | * [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 44 | 45 | # Version schemes 46 | 47 | 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. 48 | 49 | # Install 50 | 51 | See [INSTALL](INSTALL.md). 52 | 53 | # Building & testing 54 | 55 | A Makefile is provided to run the CSP in a local docker container, make sure docker is running and issue: 56 | 57 | ``` 58 | make all run 59 | ``` 60 | 61 | The CSP is now listening on localhost:8080 62 | 63 | **Note:** When building and testing the CSP locally it will run with debug logging switched on. 64 | 65 | There are a few adhoc tests provided. Make sure you have a TrueNAS/FreeNAS appliance configured with: 66 | 67 | - A pool named "tank" 68 | - iSCSI portal configured as described in the [prerequisites](INSTALL.md#prerequisites). 69 | 70 | ``` 71 | make test backend= password= 72 | ``` 73 | 74 | **Note:** None of the tests are comprehensive nor provide full coverage and should be considered equivalent to "Does the light come on?". 75 | 76 | See [e2e/README.md](e2e/README.md) how to configure and run Kubernetes e2e test suite focused the CSI tests for the TrueNAS CSP. 77 | 78 | # Limitations 79 | 80 | These are the known issues and limitations. 81 | 82 | - **RESTful support only:** The TrueNAS SCALE project is deprecating RESTful API support in favor of the Websocket API. Websocket API support will be implemented in a future release of the TrueNAS CSP. 83 | - **Residual iSCSI targets on compute nodes:** Due to an upstream CSI driver issue, there may be residual targets lingering on compute nodes after a volume has been detached. These are harmless and can safely be removed if it becomes a problem. 84 | - **Duplicate host initiators:** Fresh compute nodes that get issued parallel publish requests may end up with duplicate host initiators on TrueNAS. Unless there's substantial network changes occurring between publish requests, duplicate host initiators won't pose a problem. 85 | - **Ephemeral Local Volumes:** Due to how TrueNAS handles ZVol names internally and the long names generated by the HPE CSI Driver when requesting ephemeral storage, Ephemeral Local Volumes is not compatible with the TrueNAS CSP. Generic Ephemeral Volumes introduced as an Alpha feature in Kubernetes 1.19 works as the volumes are derived from a regular `StorageClass`. 86 | - **Volume sizing:** TrueNAS ZVols "volblocksize" need to be even divisible by the requesting volume size. This is a non-issue if you're working with even "Gi" sizes in the `PersistentVolumeClaims`. It gets hairy if working with "Mi" sizes and large volume block sizes. 87 | - **Dataset naming:** The underscore character `_` is used as an internal separator for naming snapshots and datasets. Do NOT use underscores in your pool or dataset names. 88 | - **FreeNAS ctl_max_luns:** FreeNAS has an internal limit of 1024 LUNs. That number increments for every new LUN created, even if deleted. The iSCSI Target service won't start and it leads to all sorts of problems. This is the log message on the console: `requested LUN ID 1031 is higher than ctl_max_luns` (this system had two iSCSI Targets). 89 | - **FreeNAS iSCSI Target:** On systems with a high degree of churn, especially during e2e testing, the iSCSI Target sometimes croak and needs to be restarted. It's recommended to starve the CSP to ease the API requests against FreeNAS and let failures be handled by CSI driver and Kubernetes (see [Helm chart](https://artifacthub.io/packages/helm/truenas-csp/truenas-csp)). 90 | - **CSI spec lag:** `VolumeAttributeClasses` (can be mitigated with the HPE CSI Driver Volume Mutator) and `VolumeGroups` are not implemented yet. 91 | 92 | # Need help? 93 | 94 | Please file an [issue](https://github.com/hpe-storage/truenas-csp/issues). This software is not supported by Hewlett Packard Enterprise. It's a voluntary community effort 95 | 96 | # Contributing 97 | 98 | Contributing to the TrueNAS CSP is subject to the following [contributing](CONTRIBUTING.md) guidelines. 99 | 100 | # Other Container Storage Providers for HPE CSI Driver 101 | 102 | There's currently no other open source CSPs, but the official HPE CSI Driver for Kubernetes include: 103 | 104 | - [HPE Alletra 5000/6000 and Nimble Storage](https://scod.hpedev.io/container_storage_provider/hpe_nimble_storage/index.html) 105 | - [HPE Alletra Storage MP B10000, Alletra 9000 and Primera (including 3PAR)](https://scod.hpedev.io/container_storage_provider/hpe_3par_primera/index.html) 106 | 107 | # Similar projects 108 | 109 | The TrueNAS CSP is not the only enabler of TrueNAS/FreeNAS for Kubernetes. 110 | 111 | - [Democratic CSI](https://github.com/democratic-csi/democratic-csi): A generic OpenZFS CSI driver that supports multiple OpenZFS implementations 112 | - [FreeNAS Provisioner](https://github.com/nmaupu/freenas-provisioner): An external provisioner for FreeNAS NFS exports 113 | 114 | # License 115 | 116 | TrueNAS(R) (C) 2025 iXsystems, Inc. 117 | 118 | TrueNAS CORE(R) (C) 2025 iXsystems, Inc. 119 | 120 | TrueNAS SCALE(R) (C) 2025 iXsystems, Inc. 121 | 122 | FreeNAS(R) is (C) 2011-2025 iXsystems 123 | 124 | TrueNAS CSP is released under the [MIT License](LICENSE). 125 | 126 | (C) Copyright 2025 Hewlett Packard Enterprise Development LP. 127 | 128 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 129 | 130 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 131 | 132 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 133 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker -------------------------------------------------------------------------------- /docs/artifacthub-repo.yml: -------------------------------------------------------------------------------- 1 | repositoryID: b3a7816b-3f2a-4aa6-b99a-27f4c767d39e 2 | owners: 3 | - name: Michael Mattsson 4 | email: michael.mattsson@gmail.com 5 | -------------------------------------------------------------------------------- /docs/assets/global-target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/assets/global-target.png -------------------------------------------------------------------------------- /docs/assets/icon-2048x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/assets/icon-2048x2048.png -------------------------------------------------------------------------------- /docs/assets/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 25 | 28 | 32 | 36 | 37 | 48 | 49 | 71 | 73 | 74 | 76 | image/svg+xml 77 | 79 | 80 | 81 | 82 | 83 | 88 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/assets/portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/assets/portal.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | This page intentionally left blank. 2 | 3 | (C) Copyright 2024 Hewlett Packard Enterprise Development LP. 4 | -------------------------------------------------------------------------------- /docs/index.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | entries: 3 | truenas-csp: 4 | - annotations: 5 | artifacthub.io/license: MIT 6 | artifacthub.io/links: | 7 | - name: HPE CSI Driver for Kubernetes 8 | url: https://scod.hpedev.io 9 | - name: Install 10 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 11 | artifacthub.io/prerelease: "false" 12 | apiVersion: v2 13 | appVersion: 2.5.2 14 | created: "2025-04-01T06:00:28.139300241Z" 15 | dependencies: 16 | - name: hpe-csi-driver 17 | repository: https://hpe-storage.github.io/co-deployments 18 | version: 2.5.2 19 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 20 | digest: e40e6897eea74edee2672a3f1075bee12a5a2907beb7a0d427d0f051e9315b92 21 | home: https://github.com/hpe-storage/truenas-csp 22 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 23 | keywords: 24 | - HPE 25 | - Storage 26 | - CSI 27 | maintainers: 28 | - email: michael.mattsson@gmail.com 29 | name: Michael Mattsson 30 | name: truenas-csp 31 | sources: 32 | - https://github.com/hpe-storage/truenas-csp 33 | type: application 34 | urls: 35 | - truenas-csp-1.2.1.tgz 36 | version: 1.2.1 37 | - annotations: 38 | artifacthub.io/license: MIT 39 | artifacthub.io/links: | 40 | - name: HPE CSI Driver for Kubernetes 41 | url: https://scod.hpedev.io 42 | - name: Install 43 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 44 | artifacthub.io/prerelease: "false" 45 | apiVersion: v2 46 | appVersion: 2.5.1 47 | created: "2024-09-13T06:57:31.896152837Z" 48 | dependencies: 49 | - name: hpe-csi-driver 50 | repository: https://hpe-storage.github.io/co-deployments 51 | version: 2.5.1 52 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 53 | digest: c60d6b6691b064885c5214e7551d2d9c3d1d6575e6c07aa03b0dc4b18f70e69b 54 | home: https://github.com/hpe-storage/truenas-csp 55 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 56 | keywords: 57 | - HPE 58 | - Storage 59 | - CSI 60 | maintainers: 61 | - email: michael.mattsson@gmail.com 62 | name: Michael Mattsson 63 | name: truenas-csp 64 | sources: 65 | - https://github.com/hpe-storage/truenas-csp 66 | type: application 67 | urls: 68 | - truenas-csp-1.2.0.tgz 69 | version: 1.2.0 70 | - annotations: 71 | artifacthub.io/license: MIT 72 | artifacthub.io/links: | 73 | - name: HPE CSI Driver for Kubernetes 74 | url: https://scod.hpedev.io 75 | - name: Install 76 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 77 | artifacthub.io/prerelease: "false" 78 | apiVersion: v2 79 | appVersion: 2.4.2 80 | created: "2024-05-05T17:25:24.566162137Z" 81 | dependencies: 82 | - name: hpe-csi-driver 83 | repository: https://hpe-storage.github.io/co-deployments 84 | version: 2.4.2 85 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 86 | digest: a0df2e41a2441fef306c2d8291b44a2b4a05eccd8a0e6d7cc4795972fca4732d 87 | home: https://github.com/hpe-storage/truenas-csp 88 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 89 | keywords: 90 | - HPE 91 | - Storage 92 | - CSI 93 | maintainers: 94 | - email: michael.mattsson@gmail.com 95 | name: Michael Mattsson 96 | name: truenas-csp 97 | sources: 98 | - https://github.com/hpe-storage/truenas-csp 99 | type: application 100 | urls: 101 | - truenas-csp-1.1.6.tgz 102 | version: 1.1.6 103 | - annotations: 104 | artifacthub.io/license: MIT 105 | artifacthub.io/links: | 106 | - name: HPE CSI Driver for Kubernetes 107 | url: https://scod.hpedev.io 108 | - name: Install 109 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 110 | artifacthub.io/prerelease: "false" 111 | apiVersion: v2 112 | appVersion: 2.4.0 113 | created: "2023-10-10T00:04:32.482481271Z" 114 | dependencies: 115 | - name: hpe-csi-driver 116 | repository: https://hpe-storage.github.io/co-deployments 117 | version: 2.4.0 118 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 119 | digest: 0e7e477e86c500aa3f91ac98fac2e32e985913c9f5f2692e9257feb8f8021810 120 | home: https://github.com/hpe-storage/truenas-csp 121 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 122 | keywords: 123 | - HPE 124 | - Storage 125 | - CSI 126 | maintainers: 127 | - email: michael.mattsson@gmail.com 128 | name: Michael Mattsson 129 | name: truenas-csp 130 | sources: 131 | - https://github.com/hpe-storage/truenas-csp 132 | type: application 133 | urls: 134 | - truenas-csp-1.1.5.tgz 135 | version: 1.1.5 136 | - annotations: 137 | artifacthub.io/license: MIT 138 | artifacthub.io/links: | 139 | - name: HPE CSI Driver for Kubernetes 140 | url: https://scod.hpedev.io 141 | - name: Install 142 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 143 | artifacthub.io/prerelease: "false" 144 | apiVersion: v2 145 | appVersion: 2.3.10 146 | created: "2023-05-07T18:50:16.384944624-07:00" 147 | dependencies: 148 | - name: hpe-csi-driver 149 | repository: https://hpe-storage.github.io/co-deployments 150 | version: 2.3.0 151 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 152 | digest: ff1b4d617477b6f55d3debd3820b69b7280acd721ad686b736025f30266df380 153 | home: https://github.com/hpe-storage/truenas-csp 154 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 155 | keywords: 156 | - HPE 157 | - Storage 158 | - CSI 159 | maintainers: 160 | - email: michael.mattsson@gmail.com 161 | name: Michael Mattsson 162 | name: truenas-csp 163 | sources: 164 | - https://github.com/hpe-storage/truenas-csp 165 | type: application 166 | urls: 167 | - truenas-csp-1.1.4.tgz 168 | version: 1.1.4 169 | - annotations: 170 | artifacthub.io/license: MIT 171 | artifacthub.io/links: | 172 | - name: HPE CSI Driver for Kubernetes 173 | url: https://scod.hpedev.io 174 | - name: Install 175 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 176 | artifacthub.io/prerelease: "false" 177 | apiVersion: v2 178 | appVersion: 2.3.0 179 | created: "2023-05-04T22:52:19.985145376-07:00" 180 | dependencies: 181 | - name: hpe-csi-driver 182 | repository: https://hpe-storage.github.io/co-deployments 183 | version: 2.3.0 184 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 185 | digest: deef9284f4a876ed74abac395992e33633c33388547ea830dc3788018931a801 186 | home: https://github.com/hpe-storage/truenas-csp 187 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 188 | keywords: 189 | - HPE 190 | - Storage 191 | - CSI 192 | maintainers: 193 | - email: michael.mattsson@gmail.com 194 | name: Michael Mattsson 195 | name: truenas-csp 196 | sources: 197 | - https://github.com/hpe-storage/truenas-csp 198 | type: application 199 | urls: 200 | - truenas-csp-1.1.3.tgz 201 | version: 1.1.3 202 | - annotations: 203 | artifacthub.io/license: MIT 204 | artifacthub.io/links: | 205 | - name: HPE CSI Driver for Kubernetes 206 | url: https://scod.hpedev.io 207 | - name: Install 208 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 209 | artifacthub.io/prerelease: "false" 210 | apiVersion: v2 211 | appVersion: 2.2.0 212 | created: "2022-09-19T15:42:52.410633239-07:00" 213 | dependencies: 214 | - name: hpe-csi-driver 215 | repository: https://hpe-storage.github.io/co-deployments 216 | version: 2.2.0 217 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 218 | digest: 529ae150e6bee241be7a06f653a6c777e311e18cb3011bf141750cf70aae9122 219 | home: https://github.com/hpe-storage/truenas-csp 220 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 221 | keywords: 222 | - HPE 223 | - Storage 224 | - CSI 225 | maintainers: 226 | - email: michael.mattsson@gmail.com 227 | name: Michael Mattsson 228 | name: truenas-csp 229 | sources: 230 | - https://github.com/hpe-storage/truenas-csp 231 | type: application 232 | urls: 233 | - truenas-csp-1.1.2.tgz 234 | version: 1.1.2 235 | - annotations: 236 | artifacthub.io/license: MIT 237 | artifacthub.io/links: | 238 | - name: HPE CSI Driver for Kubernetes 239 | url: https://scod.hpedev.io 240 | - name: Install 241 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 242 | artifacthub.io/prerelease: "false" 243 | apiVersion: v2 244 | appVersion: 2.1.1 245 | created: "2022-04-15T09:44:41.575426741-07:00" 246 | dependencies: 247 | - name: hpe-csi-driver 248 | repository: https://hpe-storage.github.io/co-deployments 249 | version: 2.1.1-0 250 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 251 | digest: 1cd17ca5b5f23b865447f7513574157a0cd42549547ee8f1bc1e242ef75a3780 252 | home: https://github.com/hpe-storage/truenas-csp 253 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 254 | keywords: 255 | - HPE 256 | - Storage 257 | - CSI 258 | maintainers: 259 | - email: michael.mattsson@gmail.com 260 | name: Michael Mattsson 261 | name: truenas-csp 262 | sources: 263 | - https://github.com/hpe-storage/truenas-csp 264 | type: application 265 | urls: 266 | - truenas-csp-1.1.1.tgz 267 | version: 1.1.1 268 | - annotations: 269 | artifacthub.io/license: MIT 270 | artifacthub.io/links: | 271 | - name: HPE CSI Driver for Kubernetes 272 | url: https://scod.hpedev.io 273 | - name: Install 274 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 275 | artifacthub.io/prerelease: "false" 276 | apiVersion: v2 277 | appVersion: 2.1.0 278 | created: "2022-01-30T18:45:32.690972362-08:00" 279 | dependencies: 280 | - name: hpe-csi-driver 281 | repository: https://hpe-storage.github.io/co-deployments 282 | version: 2.1.0 283 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 284 | digest: aaad3b72c7101dcbfbb3f4af61229979b76eeb938cb69cd1c79b8a5e5c13c005 285 | home: https://github.com/hpe-storage/truenas-csp 286 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 287 | keywords: 288 | - HPE 289 | - Storage 290 | - CSI 291 | maintainers: 292 | - email: michael.mattsson@gmail.com 293 | name: Michael Mattsson 294 | name: truenas-csp 295 | sources: 296 | - https://github.com/hpe-storage/truenas-csp 297 | type: application 298 | urls: 299 | - truenas-csp-1.1.0.tgz 300 | version: 1.1.0 301 | - annotations: 302 | artifacthub.io/license: MIT 303 | artifacthub.io/links: | 304 | - name: HPE CSI Driver for Kubernetes 305 | url: https://scod.hpedev.io 306 | - name: Install 307 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 308 | artifacthub.io/prerelease: "true" 309 | apiVersion: v2 310 | appVersion: 2.0.0 311 | created: "2021-10-02T10:25:01.735218208-07:00" 312 | dependencies: 313 | - name: hpe-csi-driver 314 | repository: "" 315 | version: 2.0.0 316 | description: TrueNAS CORE Container Storage Provider Helm chart for Kubernetes 317 | digest: 27b33b27cb4b7a7b2ecee141957346e8eb597e6ee1028a16e8c3701729f3fac3 318 | home: https://github.com/hpe-storage/truenas-csp 319 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 320 | keywords: 321 | - HPE 322 | - Storage 323 | - CSI 324 | maintainers: 325 | - email: michael.mattsson@gmail.com 326 | name: Michael Mattsson 327 | name: truenas-csp 328 | sources: 329 | - https://github.com/hpe-storage/truenas-csp 330 | type: application 331 | urls: 332 | - truenas-csp-1.0.0.tgz 333 | version: 1.0.0 334 | generated: "2025-04-01T06:00:28.137922841Z" 335 | -------------------------------------------------------------------------------- /docs/truenas-csp-1.0.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.0.0.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.0.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.1.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.2.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.3.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.3.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.4.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.4.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.5.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.5.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.1.6.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.1.6.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.2.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.2.0.tgz -------------------------------------------------------------------------------- /docs/truenas-csp-1.2.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/docs/truenas-csp-1.2.1.tgz -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | secret.yaml 2 | -------------------------------------------------------------------------------- /e2e/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM almalinux 2 | 3 | # Install stuff 4 | RUN dnf install -y curl jq && \ 5 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \ 6 | install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl 7 | 8 | # Manipulate stuff 9 | ENV HERE=/cut/csi-e2e 10 | ENV PATH=${PATH}:${HERE} 11 | RUN mkdir -p ${HERE} 12 | ADD cache ${HERE} 13 | ADD runner.sh ${HERE} 14 | WORKDIR ${HERE} 15 | -------------------------------------------------------------------------------- /e2e/README.md: -------------------------------------------------------------------------------- 1 | # Synopsis 2 | 3 | Performs CSI e2e tests. 4 | 5 | ```text 6 | kubectl apply -f resources.yaml 7 | kubectl apply -k . 8 | kubectl replace --force -f job-rwo.yaml 9 | kubectl replace --force -f job-rwx.yaml 10 | kubectl logs -n csi-e2e job/csi-e2e -f 11 | ``` 12 | -------------------------------------------------------------------------------- /e2e/job-rwo.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Job 3 | apiVersion: batch/v1 4 | metadata: 5 | name: csi-e2e 6 | namespace: csi-e2e 7 | spec: 8 | backoffLimit: 0 9 | template: 10 | spec: 11 | restartPolicy: Never 12 | containers: 13 | - name: csi-e2e 14 | image: quay.io/datamattsson/csi-e2e:v2.5.2 15 | command: 16 | - runner.sh 17 | args: 18 | - --ginkgo.fail-fast 19 | - --ginkgo.v 20 | - --ginkgo.timeout=12h 21 | - --ginkgo.focus=External.Storage.\[Driver:.csi.hpe.com\].* 22 | - --ginkgo.skip=\[Disruptive\]|\[Serial\] 23 | - --non-blocking-taints=node-role.kubernetes.io/control-plane,node-role.kubernetes.io/etcd,node-role.kubernetes.io/master 24 | - -storage.testdriver=test-driver-rwo.yaml 25 | - -report-dir=../report 26 | env: 27 | - name: ARG_DEBUG 28 | value: "" 29 | - name: FORCE_VERSION 30 | value: "" 31 | volumeMounts: 32 | - name: tests 33 | mountPath: /cut/csi-e2e/tests 34 | volumes: 35 | - name: tests 36 | projected: 37 | sources: 38 | - configMap: 39 | name: storage-class-rwx.yaml 40 | - configMap: 41 | name: storage-class-rwo.yaml 42 | - configMap: 43 | name: volume-snapshot-class.yaml 44 | - configMap: 45 | name: test-driver-rwx.yaml 46 | - configMap: 47 | name: test-driver-rwo.yaml 48 | -------------------------------------------------------------------------------- /e2e/job-rwx-block.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Job 3 | apiVersion: batch/v1 4 | metadata: 5 | name: csi-e2e 6 | namespace: csi-e2e 7 | spec: 8 | backoffLimit: 0 9 | template: 10 | spec: 11 | restartPolicy: Never 12 | containers: 13 | - name: csi-e2e 14 | image: quay.io/datamattsson/csi-e2e:v2.5.2 15 | command: 16 | - runner.sh 17 | args: 18 | - --ginkgo.fail-fast 19 | - --ginkgo.v 20 | - --ginkgo.timeout=12h 21 | - --ginkgo.focus=External.Storage.\[Driver:.csi.hpe.com\].*block.volmode.* 22 | - --non-blocking-taints=node-role.kubernetes.io/control-plane,node-role.kubernetes.io/etcd,node-role.kubernetes.io/master 23 | - -storage.testdriver=test-driver-rwx-block.yaml 24 | - -report-dir=../report 25 | - --ginkgo.skip=\[Feature:|\[Disruptive\]|\[Serial\]|.*two.volumes.with.different.volume.mode.* 26 | env: 27 | - name: ARG_DEBUG 28 | value: "" 29 | - name: FORCE_VERSION 30 | value: "" 31 | volumeMounts: 32 | - name: tests 33 | mountPath: /cut/csi-e2e/tests 34 | volumes: 35 | - name: tests 36 | projected: 37 | sources: 38 | - configMap: 39 | name: storage-class-rwx.yaml 40 | - configMap: 41 | name: storage-class-rwo.yaml 42 | - configMap: 43 | name: volume-snapshot-class.yaml 44 | - configMap: 45 | name: test-driver-rwx.yaml 46 | - configMap: 47 | name: test-driver-rwo.yaml 48 | - configMap: 49 | name: test-driver-rwx-block.yaml 50 | -------------------------------------------------------------------------------- /e2e/job-rwx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Job 3 | apiVersion: batch/v1 4 | metadata: 5 | name: csi-e2e 6 | namespace: csi-e2e 7 | spec: 8 | backoffLimit: 0 9 | template: 10 | spec: 11 | restartPolicy: Never 12 | containers: 13 | - name: csi-e2e 14 | image: quay.io/datamattsson/csi-e2e:v2.5.2 15 | command: 16 | - runner.sh 17 | args: 18 | - --ginkgo.fail-fast 19 | - --ginkgo.v 20 | - --ginkgo.timeout=12h 21 | - --ginkgo.focus=External.Storage.\[Driver:.csi.hpe.com\].* 22 | - --ginkgo.skip=\[Disruptive\]|\[Serial\] 23 | - --ginkgo.skip=.phemeral 24 | - --non-blocking-taints=node-role.kubernetes.io/control-plane,node-role.kubernetes.io/etcd,node-role.kubernetes.io/master 25 | - -storage.testdriver=test-driver-rwx.yaml 26 | - -report-dir=../report 27 | env: 28 | - name: ARG_DEBUG 29 | value: "" 30 | - name: FORCE_VERSION 31 | value: "" 32 | volumeMounts: 33 | - name: tests 34 | mountPath: /cut/csi-e2e/tests 35 | volumes: 36 | - name: tests 37 | projected: 38 | sources: 39 | - configMap: 40 | name: storage-class-rwx.yaml 41 | - configMap: 42 | name: storage-class-rwo.yaml 43 | - configMap: 44 | name: volume-snapshot-class.yaml 45 | - configMap: 46 | name: test-driver-rwx.yaml 47 | - configMap: 48 | name: test-driver-rwo.yaml 49 | -------------------------------------------------------------------------------- /e2e/kustomization.yaml: -------------------------------------------------------------------------------- 1 | namespace: csi-e2e 2 | configMapGenerator: 3 | - name: storage-class-rwo.yaml 4 | files: 5 | - tests/storage-class-rwo.yaml 6 | - name: storage-class-rwx.yaml 7 | files: 8 | - tests/storage-class-rwx.yaml 9 | - name: volume-snapshot-class.yaml 10 | files: 11 | - tests/volume-snapshot-class.yaml 12 | - name: test-driver-rwo.yaml 13 | files: 14 | - tests/test-driver-rwo.yaml 15 | - name: test-driver-rwx.yaml 16 | files: 17 | - tests/test-driver-rwx.yaml 18 | - name: test-driver-rwx-block.yaml 19 | files: 20 | - tests/test-driver-rwx-block.yaml 21 | generatorOptions: 22 | disableNameSuffixHash: true 23 | -------------------------------------------------------------------------------- /e2e/resources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: csi-e2e 5 | --- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRoleBinding 8 | metadata: 9 | name: csi-e2e 10 | subjects: 11 | - kind: ServiceAccount 12 | name: default # name of your service account 13 | namespace: csi-e2e # this is the namespace your service account is in 14 | roleRef: # referring to your ClusterRole 15 | kind: ClusterRole 16 | name: cluster-admin 17 | apiGroup: rbac.authorization.k8s.io 18 | -------------------------------------------------------------------------------- /e2e/runner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | if [[ ${ARG_DEBUG} ]]; then 6 | echo command $@ 7 | exit 0 8 | fi 9 | 10 | CUT_DIR=/cut/csi-e2e/tests 11 | PATH=${PATH}:${CUT_DIR} 12 | CUT_SYSTEM=$(uname -s | tr A-Z a-z) 13 | CUT_ARCH=$(uname -m) 14 | 15 | if [[ "${FORCE_VERSION}" ]]; then 16 | CUT_VERSION=${FORCE_VERSION} 17 | else 18 | CUT_VERSION=$(kubectl version -o json | jq -rM .serverVersion.gitVersion) 19 | fi 20 | 21 | if [[ "${CUT_ARCH}" == x86_64 ]]; then 22 | CUT_ARCH=amd64 23 | fi 24 | 25 | if [[ "${CUT_ARCH}" == aarch64 ]]; then 26 | CUT_ARCH=arm64 27 | fi 28 | 29 | if ! [[ -f "e2e.test" ]] || ! [[ -f "ginkgo" ]]; then 30 | curl --location \ 31 | "https://dl.k8s.io/${CUT_VERSION}/kubernetes-test-${CUT_SYSTEM}-${CUT_ARCH}.tar.gz" | \ 32 | tar --strip-components=3 -zxf - kubernetes/test/bin/e2e.test kubernetes/test/bin/ginkgo 33 | fi 34 | 35 | cd tests 36 | ../e2e.test $@ 37 | -------------------------------------------------------------------------------- /e2e/secret-dist.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: truenas-secret 5 | namespace: hpe-storage 6 | stringData: 7 | serviceName: truenas-csp-svc 8 | servicePort: "8080" 9 | username: hpe-csi (username is a no-op when using API key) 10 | password: API key or root password of TrueNAS/FreeNAS appliance 11 | backend: Management IP address of TrueNAS/FreeNAS appliance 12 | -------------------------------------------------------------------------------- /e2e/tests/storage-class-rwo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: e2e-standard-rwo 5 | provisioner: csi.hpe.com 6 | parameters: 7 | csi.storage.k8s.io/fstype: xfs 8 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 9 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 10 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 17 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 18 | description: "Volume created by the HPE CSI Driver for Kubernetes from {namespace}" 19 | root: tank/csi-e2e 20 | #chapSecretNamespace: hpe-storage 21 | #chapSecretName: my-chap-secret 22 | #authNetworks: 192.168.20.0/24, 192.168.10.0/24 23 | reclaimPolicy: Delete 24 | allowVolumeExpansion: true 25 | -------------------------------------------------------------------------------- /e2e/tests/storage-class-rwx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: e2e-standard-rwx 5 | provisioner: csi.hpe.com 6 | parameters: 7 | csi.storage.k8s.io/fstype: ext4 8 | csi.storage.k8s.io/controller-expand-secret-name: truenas-secret 9 | csi.storage.k8s.io/controller-expand-secret-namespace: hpe-storage 10 | csi.storage.k8s.io/controller-publish-secret-name: truenas-secret 11 | csi.storage.k8s.io/controller-publish-secret-namespace: hpe-storage 12 | csi.storage.k8s.io/node-publish-secret-name: truenas-secret 13 | csi.storage.k8s.io/node-publish-secret-namespace: hpe-storage 14 | csi.storage.k8s.io/node-stage-secret-name: truenas-secret 15 | csi.storage.k8s.io/node-stage-secret-namespace: hpe-storage 16 | csi.storage.k8s.io/provisioner-secret-name: truenas-secret 17 | csi.storage.k8s.io/provisioner-secret-namespace: hpe-storage 18 | description: "Volume created by the HPE CSI Driver for Kubernetes from {namespace}" 19 | nfsResources: "true" 20 | nfsNamespace: csi.storage.k8s.io/pvc/namespace 21 | root: tank/csi-e2e 22 | reclaimPolicy: Delete 23 | allowVolumeExpansion: false 24 | -------------------------------------------------------------------------------- /e2e/tests/test-driver-rwo.yaml: -------------------------------------------------------------------------------- 1 | StorageClass: 2 | FromFile: "csi-e2e/tests/storage-class-rwo.yaml" 3 | SnapshotClass: 4 | FromFile: "./volume-snapshot-class.yaml" 5 | DriverInfo: 6 | Name: csi.hpe.com 7 | RequiredAccessModes: 8 | - ReadWriteOnce 9 | # UNDER TEST 10 | TopologyKeys: 11 | - csi.hpe.com/zone 12 | NumAllowedTopologies: 1 13 | Capabilities: 14 | persistence: true 15 | block: true 16 | fsGroup: true 17 | exec: true 18 | snapshotDataSource: true 19 | multipods: true 20 | controllerExpansion: false 21 | nodeExpansion: true 22 | volumeLimits: false 23 | # UNDER TEST 24 | topology: true 25 | singleNodeVolume: false 26 | RWX: false 27 | pvcDataSource: true 28 | FSResizeFromSourceNotSupported: true 29 | readWriteOncePod: false 30 | SupportedFsType: 31 | ext4: {} 32 | ext3: {} 33 | xfs: {} 34 | btrfs: {} 35 | SupportedSizeRange: 36 | Min: 1Gi 37 | Max: 32Gi 38 | -------------------------------------------------------------------------------- /e2e/tests/test-driver-rwx-block.yaml: -------------------------------------------------------------------------------- 1 | StorageClass: 2 | FromFile: "csi-e2e/tests/storage-class-rwo.yaml" 3 | SnapshotClass: 4 | FromFile: "./volume-snapshot-class.yaml" 5 | DriverInfo: 6 | Name: csi.hpe.com 7 | RequiredAccessModes: 8 | - ReadWriteMany 9 | Capabilities: 10 | persistence: true 11 | block: true 12 | fsGroup: true 13 | exec: true 14 | snapshotDataSource: true 15 | multipods: true 16 | controllerExpansion: false 17 | nodeExpansion: true 18 | volumeLimits: false 19 | topology: false 20 | singleNodeVolume: false 21 | RWX: false 22 | pvcDataSource: true 23 | FSResizeFromSourceNotSupported: true 24 | readWriteOncePod: false 25 | SupportedFsType: 26 | ext4: {} 27 | ext3: {} 28 | xfs: {} 29 | btrfs: {} 30 | SupportedSizeRange: 31 | Min: 1Gi 32 | Max: 32Gi 33 | -------------------------------------------------------------------------------- /e2e/tests/test-driver-rwx.yaml: -------------------------------------------------------------------------------- 1 | StorageClass: 2 | FromFile: "csi-e2e/tests/storage-class-rwx.yaml" 3 | SnapshotClass: 4 | FromFile: "./volume-snapshot-class.yaml" 5 | DriverInfo: 6 | Name: csi.hpe.com 7 | RequiredAccessModes: 8 | - ReadWriteMany 9 | Capabilities: 10 | persistence: true 11 | block: false 12 | fsGroup: false 13 | exec: true 14 | snapshotDataSource: true 15 | multipods: true 16 | controllerExpansion: true 17 | nodeExpansion: false 18 | volumeLimits: false 19 | topology: false 20 | singleNodeVolume: false 21 | RWX: true 22 | pvcDataSource: false 23 | FSResizeFromSourceNotSupported: true 24 | readWriteOncePod: false 25 | SupportedSizeRange: 26 | Min: 4Gi 27 | Max: 32Gi 28 | -------------------------------------------------------------------------------- /e2e/tests/volume-snapshot-class.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1 2 | kind: VolumeSnapshotClass 3 | metadata: 4 | name: e2e-snapshot 5 | driver: csi.hpe.com 6 | deletionPolicy: Delete 7 | parameters: 8 | description: "Snapshot created by the HPE CSI Driver" 9 | csi.storage.k8s.io/snapshotter-secret-name: truenas-secret 10 | csi.storage.k8s.io/snapshotter-secret-namespace: hpe-storage 11 | csi.storage.k8s.io/snapshotter-list-secret-name: truenas-secret 12 | csi.storage.k8s.io/snapshotter-list-secret-namespace: hpe-storage 13 | -------------------------------------------------------------------------------- /helm/charts/Makefile: -------------------------------------------------------------------------------- 1 | CHART_TARGET:=../../docs 2 | 3 | .PHONY: truenas-csp 4 | all: truenas-csp 5 | truenas-csp: 6 | helm dependency update $@ 7 | helm dependency build $@ 8 | helm lint $@ 9 | helm package $@ -d . 10 | helm repo index --merge $(CHART_TARGET)/index.yaml . 11 | mv *.tgz $(CHART_TARGET) 12 | mv index.yaml $(CHART_TARGET) 13 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: hpe-csi-driver 3 | repository: https://hpe-storage.github.io/co-deployments 4 | version: 2.5.2 5 | digest: sha256:7a48bbb08bd3b39427ad0a9035fac9a62f1376cca06a197a23c5d8796289bebc 6 | generated: "2025-03-16T08:25:03.041416938Z" 7 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: truenas-csp 4 | type: application 5 | description: TrueNAS Container Storage Provider Helm chart for Kubernetes 6 | icon: https://hpe-storage.github.io/truenas-csp/assets/icon.svg 7 | annotations: 8 | artifacthub.io/license: MIT 9 | artifacthub.io/links: | 10 | - name: HPE CSI Driver for Kubernetes 11 | url: https://scod.hpedev.io 12 | - name: Install 13 | url: https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md 14 | artifacthub.io/prerelease: "false" 15 | version: "1.2.1" 16 | appVersion: "2.5.2" 17 | maintainers: 18 | - name: Michael Mattsson 19 | email: michael.mattsson@gmail.com 20 | sources: 21 | - https://github.com/hpe-storage/truenas-csp 22 | home: https://github.com/hpe-storage/truenas-csp 23 | dependencies: 24 | - name: hpe-csi-driver 25 | version: 2.5.2 26 | repository: "https://hpe-storage.github.io/co-deployments" 27 | keywords: 28 | - HPE 29 | - Storage 30 | - CSI 31 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/README.md: -------------------------------------------------------------------------------- 1 | # TrueNAS Container Storage Provider for Kubernetes Helm chart 2 | 3 | This Chart provide means to install the dependent [HPE CSI Driver for Kubernetes](https://scod.hpedev.io/csi_driver) to provide persistent storage for Kubernetes workloads using [TrueNAS Container Storage Provider](https://github.com/hpe-storage/truenas-csp). 4 | 5 | ## Prerequisites 6 | 7 | - TrueNAS 12.0 or later 8 | - TrueNAS SCALE 22.02 or later (see note below) 9 | - FreeNAS 11.2-U3 or later 10 | 11 | **Note:** TrueNAS SCALE 25.04 is currently NOT supported. 12 | 13 | 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. 14 | 15 | **IMPORTANT:** Do **NOT** install this chart if the HPE CSI Driver for Kubernetes is already installed! 16 | 17 | ## Configuration and installation 18 | 19 | The following table lists the configurable parameters of the chart and their default values. 20 | 21 | | Parameter | Description | Default | 22 | |---------------------------|------------------------------------------------------------------------------------|------------------| 23 | | logDebug | Log extensive debug information on stdout of the CSP | false | 24 | | optimizeFor | Set to "FreeNAS" to apply minimal amount of threads and short timeouts for the CSP | "Default" | 25 | | images.trueNasCSP | Use this particular fully qualified image name for the TrueNAS CSP | From values.yaml | 26 | 27 | **Hint:** The usual Helm decorations are available for the CSP, see [values.yaml](https://github.com/hpe-storage/truenas-csp/blob/master/helm/charts/truenas-csp/values.yaml). 28 | 29 | ### Installing the chart 30 | 31 | To install the chart with the name `my-truenas-csp`: 32 | 33 | Add the helm repo: 34 | 35 | ``` 36 | helm repo add truenas-csp https://hpe-storage.github.io/truenas-csp/ 37 | helm repo update 38 | ``` 39 | 40 | Install the latest chart: 41 | 42 | ``` 43 | helm install my-truenas-csp truenas-csp/truenas-csp --create-namespace -n hpe-storage 44 | ``` 45 | 46 | **Note**: Pay attention to what the latest version of the chart is. If it's labeled with `prerelease` and a "beta" tag, add `--version X.Y.Z` to install a "stable" chart. 47 | 48 | ### Upgrading the chart 49 | 50 | Due to the [helm limitation](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations) to not support upgrade of CRDs between different chart versions, helm chart upgrade is not supported. 51 | 52 | Our recommendation is to uninstall the existing chart and install the chart with the desired version. CRDs will be preserved between uninstall and install. 53 | 54 | ### Uninstalling the chart 55 | 56 | To uninstall the `my-truenas-csp` chart: 57 | 58 | ``` 59 | helm uninstall my-truenas-csp -n hpe-storage 60 | ``` 61 | 62 | **Note**: Due to a limitation in Helm, CRDs are not deleted as part of the chart uninstall. 63 | 64 | ## Provisioning persistent storage to Kubernetes with TrueNAS and FreeNAS 65 | 66 | The appliance that is intended to be used with the CSI driver must be configured properly before it can be used. Follow the [INSTALL](https://github.com/hpe-storage/truenas-csp/blob/master/INSTALL.md#configure-csi-driver) document to learn more. 67 | 68 | Also, it's helpful to be familiar with [persistent storage concepts](https://kubernetes.io/docs/concepts/storage/) in Kubernetes prior to deploying stateful workloads. 69 | 70 | ## Community 71 | 72 | Please file any issues, questions or feature requests you may have [here](https://github.com/hpe-storage/truenas-csp/issues) (do not use this facility for support inquiries of your storage product). You may also join our Slack community to chat with some of the HPE folks close to this project. We hang out in `#NimbleStorage`, `#3par-primera`, and `#Kubernetes`. Sign up at [developer.hpe.com](https://developer.hpe.com/slack-signup) and login at [hpedev.slack.com](https://hpedev.slack.com/) 73 | 74 | ## Contributing 75 | 76 | We value all feedback and contributions. If you find any issues or want to contribute, please feel free to open an issue or file a PR. More details in [CONTRIBUTING.md](https://github.com/hpe-storage/truenas-csp/blob/master/CONTRIBUTING.md) 77 | 78 | ## License 79 | 80 | This is open source software licensed using the MIT license. Please see [LICENSE](https://github.com/hpe-storage/truenas-csp/blob/master/LICENSE) for details. 81 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/charts/hpe-csi-driver-2.5.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpe-storage/truenas-csp/cd591d6db10fdb29db0d131e811be16b5aaefa71/helm/charts/truenas-csp/charts/hpe-csi-driver-2.5.2.tgz -------------------------------------------------------------------------------- /helm/charts/truenas-csp/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "truenas-csp.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "truenas-csp.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "truenas-csp.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "truenas-csp.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "truenas-csp.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "truenas-csp.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "truenas-csp.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "truenas-csp.labels" -}} 37 | helm.sh/chart: {{ include "truenas-csp.chart" . }} 38 | {{ include "truenas-csp.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "truenas-csp.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "truenas-csp.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "truenas-csp.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "truenas-csp.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: truenas-csp 5 | labels: 6 | {{- include "truenas-csp.labels" . | nindent 4 }} 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | {{- include "truenas-csp.selectorLabels" . | nindent 6 }} 12 | template: 13 | metadata: 14 | {{- with .Values.podAnnotations }} 15 | annotations: 16 | {{- toYaml . | nindent 8 }} 17 | {{- end }} 18 | labels: 19 | {{- include "truenas-csp.selectorLabels" . | nindent 8 }} 20 | spec: 21 | {{- with .Values.imagePullSecrets }} 22 | imagePullSecrets: 23 | {{- toYaml . | nindent 8 }} 24 | {{- end }} 25 | serviceAccountName: {{ include "truenas-csp.serviceAccountName" . }} 26 | securityContext: 27 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 28 | containers: 29 | - name: {{ .Chart.Name }} 30 | securityContext: 31 | {{- toYaml .Values.securityContext | nindent 12 }} 32 | image: {{ .Values.images.trueNasCSP }} 33 | imagePullPolicy: {{ .Values.imagePullPolicy }} 34 | {{ if .Values.logDebug -}} 35 | env: 36 | - name: LOG_DEBUG 37 | value: "1" 38 | {{- end }} 39 | {{ if eq .Values.optimizeFor "FreeNAS" -}} 40 | command: 41 | - /app/bin/gunicorn 42 | args: 43 | - "--bind=0.0.0.0:8080" 44 | - "--workers=1" 45 | - "--threads=1" 46 | - "--timeout=60" 47 | - "--preload" 48 | - "csp:SERVE" 49 | {{- end }} 50 | ports: 51 | - name: http 52 | containerPort: 8080 53 | protocol: TCP 54 | readinessProbe: 55 | tcpSocket: 56 | port: 8080 57 | initialDelaySeconds: 5 58 | periodSeconds: 10 59 | livenessProbe: 60 | tcpSocket: 61 | port: 8080 62 | initialDelaySeconds: 15 63 | periodSeconds: 20 64 | resources: 65 | {{- toYaml .Values.resources | nindent 12 }} 66 | {{- with .Values.nodeSelector }} 67 | nodeSelector: 68 | {{- toYaml . | nindent 8 }} 69 | {{- end }} 70 | {{- with .Values.affinity }} 71 | affinity: 72 | {{- toYaml . | nindent 8 }} 73 | {{- end }} 74 | {{- with .Values.tolerations }} 75 | tolerations: 76 | {{- toYaml . | nindent 8 }} 77 | {{- end }} 78 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/templates/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: truenas-csp-svc 6 | labels: 7 | {{- include "truenas-csp.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.service.type }} 10 | ports: 11 | - port: {{ .Values.service.port }} 12 | targetPort: http 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "truenas-csp.selectorLabels" . | nindent 4 }} 17 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "truenas-csp.serviceAccountName" . }} 6 | labels: 7 | {{- include "truenas-csp.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "http://example.com/example.json", 4 | "type": "object", 5 | "title": "The root schema", 6 | "description": "The root schema comprises the entire JSON document.", 7 | "default": {}, 8 | "required": [ 9 | "logDebug", 10 | "optimizeFor", 11 | "images", 12 | "imagePullPolicy", 13 | "imagePullSecrets", 14 | "nameOverride", 15 | "fullnameOverride", 16 | "serviceAccount", 17 | "podAnnotations", 18 | "podSecurityContext", 19 | "securityContext", 20 | "service", 21 | "ingress", 22 | "resources", 23 | "nodeSelector", 24 | "tolerations", 25 | "affinity", 26 | "hpe-csi-driver" 27 | ], 28 | "properties": { 29 | "logDebug": { 30 | "$id": "#/properties/logDebug", 31 | "type": "boolean", 32 | "title": "The logDebug schema", 33 | "description": "An explanation about the purpose of this instance.", 34 | "default": false 35 | }, 36 | "optimizeFor": { 37 | "$id": "#/properties/optimizeFor", 38 | "type": "string", 39 | "title": "The optimizeFor schema", 40 | "description": "An explanation about the purpose of this instance.", 41 | "enum": [ "FreeNAS", "Default" ], 42 | "default": "Default" 43 | }, 44 | "images": { 45 | "$id": "#/properties/images", 46 | "type": "object", 47 | "title": "The images schema", 48 | "description": "An explanation about the purpose of this instance.", 49 | "default": {}, 50 | "required": [ 51 | "trueNasCSP" 52 | ], 53 | "properties": { 54 | "trueNasCSP": { 55 | "$id": "#/properties/images/properties/truenascsp", 56 | "type": "string", 57 | "title": "The truenascsp schema", 58 | "description": "An explanation about the purpose of this instance.", 59 | "default": "" 60 | } 61 | }, 62 | "additionalProperties": true 63 | }, 64 | "imagePullPolicy": { 65 | "$id": "#/properties/imagePullPolicy", 66 | "title": "TrueNAS CSP image pull policy", 67 | "type": "string", 68 | "default": "IfNotPresent", 69 | "enum": [ "Always", "IfNotPresent", "Never" ] 70 | }, 71 | "imagePullSecrets": { 72 | "$id": "#/properties/imagePullSecrets", 73 | "type": "array", 74 | "title": "The imagePullSecrets schema", 75 | "description": "An explanation about the purpose of this instance.", 76 | "default": [], 77 | "additionalItems": true, 78 | "items": { 79 | "$id": "#/properties/imagePullSecrets/items" 80 | } 81 | }, 82 | "nameOverride": { 83 | "$id": "#/properties/nameOverride", 84 | "type": "string", 85 | "title": "The nameOverride schema", 86 | "description": "An explanation about the purpose of this instance.", 87 | "default": "" 88 | }, 89 | "fullnameOverride": { 90 | "$id": "#/properties/fullnameOverride", 91 | "type": "string", 92 | "title": "The fullnameOverride schema", 93 | "description": "An explanation about the purpose of this instance.", 94 | "default": "" 95 | }, 96 | "serviceAccount": { 97 | "$id": "#/properties/serviceAccount", 98 | "type": "object", 99 | "title": "The serviceAccount schema", 100 | "description": "An explanation about the purpose of this instance.", 101 | "default": {}, 102 | "required": [ 103 | "create", 104 | "annotations", 105 | "name" 106 | ], 107 | "properties": { 108 | "create": { 109 | "$id": "#/properties/serviceAccount/properties/create", 110 | "type": "boolean", 111 | "title": "The create schema", 112 | "description": "An explanation about the purpose of this instance.", 113 | "default": false 114 | }, 115 | "annotations": { 116 | "$id": "#/properties/serviceAccount/properties/annotations", 117 | "type": "object", 118 | "title": "The annotations schema", 119 | "description": "An explanation about the purpose of this instance.", 120 | "default": {}, 121 | "required": [], 122 | "additionalProperties": true 123 | }, 124 | "name": { 125 | "$id": "#/properties/serviceAccount/properties/name", 126 | "type": "string", 127 | "title": "The name schema", 128 | "description": "An explanation about the purpose of this instance.", 129 | "default": "" 130 | } 131 | }, 132 | "additionalProperties": true 133 | }, 134 | "podAnnotations": { 135 | "$id": "#/properties/podAnnotations", 136 | "type": "object", 137 | "title": "The podAnnotations schema", 138 | "description": "An explanation about the purpose of this instance.", 139 | "default": {}, 140 | "required": [], 141 | "additionalProperties": true 142 | }, 143 | "podSecurityContext": { 144 | "$id": "#/properties/podSecurityContext", 145 | "type": "object", 146 | "title": "The podSecurityContext schema", 147 | "description": "An explanation about the purpose of this instance.", 148 | "default": {}, 149 | "required": [], 150 | "additionalProperties": true 151 | }, 152 | "securityContext": { 153 | "$id": "#/properties/securityContext", 154 | "type": "object", 155 | "title": "The securityContext schema", 156 | "description": "An explanation about the purpose of this instance.", 157 | "default": {}, 158 | "required": [], 159 | "additionalProperties": true 160 | }, 161 | "service": { 162 | "$id": "#/properties/service", 163 | "type": "object", 164 | "title": "The service schema", 165 | "description": "An explanation about the purpose of this instance.", 166 | "default": {}, 167 | "required": [ 168 | "type", 169 | "port" 170 | ], 171 | "properties": { 172 | "type": { 173 | "$id": "#/properties/service/properties/type", 174 | "type": "string", 175 | "title": "The type schema", 176 | "description": "An explanation about the purpose of this instance.", 177 | "default": "" 178 | }, 179 | "port": { 180 | "$id": "#/properties/service/properties/port", 181 | "type": "integer", 182 | "title": "The port schema", 183 | "description": "An explanation about the purpose of this instance.", 184 | "default": 8080 185 | } 186 | }, 187 | "additionalProperties": true 188 | }, 189 | "ingress": { 190 | "$id": "#/properties/ingress", 191 | "type": "object", 192 | "title": "The ingress schema", 193 | "description": "An explanation about the purpose of this instance.", 194 | "default": {}, 195 | "required": [ 196 | "enabled", 197 | "className", 198 | "annotations", 199 | "hosts", 200 | "tls" 201 | ], 202 | "properties": { 203 | "enabled": { 204 | "$id": "#/properties/ingress/properties/enabled", 205 | "type": "boolean", 206 | "title": "The enabled schema", 207 | "description": "An explanation about the purpose of this instance.", 208 | "default": false 209 | }, 210 | "className": { 211 | "$id": "#/properties/ingress/properties/className", 212 | "type": "string", 213 | "title": "The className schema", 214 | "description": "An explanation about the purpose of this instance.", 215 | "default": "" 216 | }, 217 | "annotations": { 218 | "$id": "#/properties/ingress/properties/annotations", 219 | "type": "object", 220 | "title": "The annotations schema", 221 | "description": "An explanation about the purpose of this instance.", 222 | "default": {}, 223 | "required": [], 224 | "additionalProperties": true 225 | }, 226 | "hosts": { 227 | "$id": "#/properties/ingress/properties/hosts", 228 | "type": "array", 229 | "title": "The hosts schema", 230 | "description": "An explanation about the purpose of this instance.", 231 | "default": [], 232 | "additionalItems": true, 233 | "items": { 234 | "$id": "#/properties/ingress/properties/hosts/items", 235 | "anyOf": [ 236 | { 237 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0", 238 | "type": "object", 239 | "title": "The first anyOf schema", 240 | "description": "An explanation about the purpose of this instance.", 241 | "default": {}, 242 | "examples": [ 243 | { 244 | "host": "chart-example.local", 245 | "paths": [ 246 | { 247 | "path": "/", 248 | "pathType": "ImplementationSpecific" 249 | } 250 | ] 251 | } 252 | ], 253 | "required": [ 254 | "host", 255 | "paths" 256 | ], 257 | "properties": { 258 | "host": { 259 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0/properties/host", 260 | "type": "string", 261 | "title": "The host schema", 262 | "description": "An explanation about the purpose of this instance.", 263 | "default": "", 264 | "examples": [ 265 | "chart-example.local" 266 | ] 267 | }, 268 | "paths": { 269 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0/properties/paths", 270 | "type": "array", 271 | "title": "The paths schema", 272 | "description": "An explanation about the purpose of this instance.", 273 | "default": [], 274 | "additionalItems": true, 275 | "items": { 276 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0/properties/paths/items", 277 | "anyOf": [ 278 | { 279 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0/properties/paths/items/anyOf/0", 280 | "type": "object", 281 | "title": "The first anyOf schema", 282 | "description": "An explanation about the purpose of this instance.", 283 | "default": {}, 284 | "required": [ 285 | "path", 286 | "pathType" 287 | ], 288 | "properties": { 289 | "path": { 290 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0/properties/paths/items/anyOf/0/properties/path", 291 | "type": "string", 292 | "title": "The path schema", 293 | "description": "An explanation about the purpose of this instance.", 294 | "default": "" 295 | }, 296 | "pathType": { 297 | "$id": "#/properties/ingress/properties/hosts/items/anyOf/0/properties/paths/items/anyOf/0/properties/pathType", 298 | "type": "string", 299 | "title": "The pathType schema", 300 | "description": "An explanation about the purpose of this instance.", 301 | "default": "" 302 | } 303 | }, 304 | "additionalProperties": false 305 | } 306 | ] 307 | } 308 | } 309 | }, 310 | "additionalProperties": false 311 | } 312 | ] 313 | } 314 | }, 315 | "tls": { 316 | "$id": "#/properties/ingress/properties/tls", 317 | "type": "array", 318 | "title": "The tls schema", 319 | "description": "An explanation about the purpose of this instance.", 320 | "default": [], 321 | "additionalItems": true, 322 | "items": { 323 | "$id": "#/properties/ingress/properties/tls/items" 324 | } 325 | } 326 | }, 327 | "additionalProperties": false 328 | }, 329 | "resources": { 330 | "$id": "#/properties/resources", 331 | "type": "object", 332 | "title": "resource requests and limits", 333 | "additionalProperties": false, 334 | "required": ["limits", "requests"], 335 | "description": "See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", 336 | "properties": { 337 | "limits": { 338 | "type": "object", 339 | "title": "resource limits", 340 | "default": {} 341 | }, 342 | "requests": { 343 | "type": "object", 344 | "title": "resource requests", 345 | "default": {} } 346 | } 347 | }, 348 | "nodeSelector": { 349 | "$id": "#/properties/nodeSelector", 350 | "type": "object", 351 | "title": "The nodeSelector schema", 352 | "description": "An explanation about the purpose of this instance.", 353 | "default": {}, 354 | "required": [], 355 | "additionalProperties": false 356 | }, 357 | "tolerations": { 358 | "$id": "#/properties/tolerations", 359 | "type": "array", 360 | "title": "The tolerations schema", 361 | "description": "An explanation about the purpose of this instance.", 362 | "default": [], 363 | "additionalItems": true, 364 | "items": { 365 | "$id": "#/properties/tolerations/items" 366 | } 367 | }, 368 | "affinity": { 369 | "$id": "#/properties/affinity", 370 | "type": "object", 371 | "title": "The affinity schema", 372 | "description": "An explanation about the purpose of this instance.", 373 | "default": {}, 374 | "required": [], 375 | "additionalProperties": false 376 | }, 377 | "hpe-csi-driver": { 378 | "$id": "#/properties/hpe-csi-driver", 379 | "type": "object", 380 | "title": "The hpe-csi-driver schema", 381 | "description": "An explanation about the purpose of this instance.", 382 | "default": {}, 383 | "required": [ 384 | "disable" 385 | ], 386 | "properties": { 387 | "disable": { 388 | "$id": "#/properties/hpe-csi-driver/properties/disable", 389 | "type": "object", 390 | "title": "The disable schema", 391 | "description": "An explanation about the purpose of this instance.", 392 | "default": {}, 393 | "required": [ 394 | "nimble", 395 | "primera", 396 | "alletra6000", 397 | "alletra9000", 398 | "alletraStorageMP" 399 | ], 400 | "properties": { 401 | "nimble": { 402 | "$id": "#/properties/hpe-csi-driver/properties/disable/properties/nimble", 403 | "type": "boolean", 404 | "title": "The nimble schema", 405 | "description": "An explanation about the purpose of this instance.", 406 | "default": false 407 | }, 408 | "primera": { 409 | "$id": "#/properties/hpe-csi-driver/properties/disable/properties/primera", 410 | "type": "boolean", 411 | "title": "The primera schema", 412 | "description": "An explanation about the purpose of this instance.", 413 | "default": false 414 | }, 415 | "alletra6000": { 416 | "$id": "#/properties/hpe-csi-driver/properties/disable/properties/alletra6000", 417 | "type": "boolean", 418 | "title": "The alletra6000 schema", 419 | "description": "An explanation about the purpose of this instance.", 420 | "default": false 421 | }, 422 | "alletra9000": { 423 | "$id": "#/properties/hpe-csi-driver/properties/disable/properties/alletra9000", 424 | "type": "boolean", 425 | "title": "The alletra9000 schema", 426 | "description": "An explanation about the purpose of this instance.", 427 | "default": false 428 | }, 429 | "alletraStorageMP": { 430 | "$id": "#/properties/hpe-csi-driver/properties/disable/properties/alletraStorageMP", 431 | "type": "boolean", 432 | "title": "The alletraStorageMP schema", 433 | "description": "An explanation about the purpose of this instance.", 434 | "default": false 435 | } 436 | }, 437 | "additionalProperties": false 438 | } 439 | }, 440 | "additionalProperties": true 441 | }, 442 | "global": {} 443 | }, 444 | "additionalProperties": false 445 | } 446 | -------------------------------------------------------------------------------- /helm/charts/truenas-csp/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Default values for truenas-csp. 3 | # This is a YAML-formatted file. 4 | # Declare variables to be passed into your templates. 5 | 6 | # VERY verbose 7 | logDebug: false 8 | 9 | # Tunes the CSP backend API requests 10 | optimizeFor: "Default" 11 | 12 | # Pull policy 13 | imagePullPolicy: IfNotPresent 14 | 15 | images: 16 | trueNasCSP: quay.io/datamattsson/truenas-csp:v2.5.2 17 | 18 | imagePullSecrets: [] 19 | nameOverride: "" 20 | fullnameOverride: "" 21 | 22 | serviceAccount: 23 | # Specifies whether a service account should be created 24 | create: true 25 | # Annotations to add to the service account 26 | annotations: {} 27 | # The name of the service account to use. 28 | # If not set and create is true, a name is gene'd using the fullname template 29 | name: "" 30 | 31 | podAnnotations: {} 32 | 33 | podSecurityContext: {} 34 | # fsGroup: 2000 35 | 36 | securityContext: {} 37 | # capabilities: 38 | # drop: 39 | # - ALL 40 | # readOnlyRootFilesystem: true 41 | # runAsNonRoot: true 42 | # runAsUser: 1000 43 | 44 | service: 45 | type: ClusterIP 46 | port: 8080 47 | 48 | ingress: 49 | enabled: false 50 | className: "" 51 | annotations: {} 52 | # kubernetes.io/ingress.class: nginx 53 | # kubernetes.io/tls-acme: "true" 54 | hosts: 55 | - host: chart-example.local 56 | paths: 57 | - path: / 58 | pathType: ImplementationSpecific 59 | tls: [] 60 | # - secretName: chart-example-tls 61 | # hosts: 62 | # - chart-example.local 63 | 64 | resources: 65 | limits: 66 | cpu: 1000m 67 | memory: 1Gi 68 | requests: 69 | cpu: 100m 70 | memory: 256Mi 71 | 72 | nodeSelector: {} 73 | 74 | tolerations: 75 | - effect: NoExecute 76 | key: node.kubernetes.io/not-ready 77 | operator: Exists 78 | tolerationSeconds: 30 79 | - effect: NoExecute 80 | key: node.kubernetes.io/unreachable 81 | operator: Exists 82 | tolerationSeconds: 30 83 | 84 | affinity: {} 85 | 86 | # Dependencies 87 | hpe-csi-driver: 88 | disable: 89 | nimble: true 90 | primera: true 91 | alletra6000: true 92 | alletra9000: true 93 | alletraStorageMP: true 94 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | falcon==2.0.0 2 | gunicorn==23.0.0 3 | requests==2.32.3 4 | -------------------------------------------------------------------------------- /tests/csp/clone.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-new-volume17", 3 | "size": "1073741824", 4 | "description": "my first clone volume", 5 | "clone": "true", 6 | "base_snapshot_id": "tank_my-new-volume16@my-first-snapshot", 7 | "config": { 8 | "compression": "gzip-1", 9 | "deduplication": "off", 10 | "sparse": true, 11 | "volblocksize": "16K", 12 | "sync": "always", 13 | "zpool": "tank" 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/csp/initiator-chap.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "host-02.lab.internet.com", 3 | "uuid": "41302701-0196-420f-b319-834a79891db2", 4 | "iqns": [ 5 | "iqn.2019-07.com.nimblestorage:foo-iqn", 6 | "iqn.2019-06.com.cloudvolumes:foo-iqn" 7 | ], 8 | "networks": [ 9 | "172.28.12.162/20", 10 | "10.234.63.106/20", 11 | "8.8.8.8/8" 12 | ], 13 | "chap_user": "makefile", 14 | "chap_password": "make567890abcdef", 15 | "wwpns": [] 16 | } 17 | -------------------------------------------------------------------------------- /tests/csp/initiator-multi.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "host-02.lab.internet.com", 3 | "uuid": "41302701-0196-420f-b319-834a79891db1", 4 | "iqns": [ 5 | "iqn.2019-07.com.nimblestorage:awe-iqn", 6 | "iqn.2019-06.com.cloudvolumes:awesome-iqn" 7 | ], 8 | "networks": [ 9 | "172.28.12.162/20", 10 | "10.234.63.106/20" 11 | ], 12 | "wwpns": [] 13 | } 14 | -------------------------------------------------------------------------------- /tests/csp/initiator.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "host-01.lab.internet.com", 3 | "uuid": "41302701-0196-420f-b319-834a79891db0", 4 | "iqns": [ 5 | "iqn.2019-07.com.nimblestorage:cool-iqn", 6 | "iqn.2019-06.com.cloudvolumes:cooler-iqn" 7 | ], 8 | "networks": [ 9 | "172.28.12.161/20", 10 | "10.234.63.105/20" 11 | ], 12 | "wwpns": [] 13 | } 14 | -------------------------------------------------------------------------------- /tests/csp/mutator-negative.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "notvalid": "nope" 4 | 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/csp/mutator.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "compression": "LZ4" 4 | 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/csp/mutators.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "size": "2147483648", 3 | "description": "my other description", 4 | "config": { 5 | "compression": "LZ4", 6 | "deduplication": "ON", 7 | "sync": "ALWAYS" 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/csp/publish-chap.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "host_uuid": "41302701-0196-420f-b319-834a79891db2", 3 | "access_protocol": "iscsi" 4 | } 5 | -------------------------------------------------------------------------------- /tests/csp/publish-multi.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "host_uuid": "41302701-0196-420f-b319-834a79891db1", 3 | "access_protocol": "iscsi" 4 | } 5 | -------------------------------------------------------------------------------- /tests/csp/publish.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "host_uuid": "41302701-0196-420f-b319-834a79891db0", 3 | "access_protocol": "iscsi" 4 | } 5 | -------------------------------------------------------------------------------- /tests/csp/snapshot1.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-first-snapshot", 3 | "description": "my first snapshot", 4 | "volume_id": "tank_my-new-volume16", 5 | "config": {} 6 | } 7 | -------------------------------------------------------------------------------- /tests/csp/snapshot2.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-second-snapshot", 3 | "description": "my second snapshot", 4 | "volume_id": "tank_my-new-volume16", 5 | "config": {} 6 | } 7 | -------------------------------------------------------------------------------- /tests/csp/unpublish-chap.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "host_uuid": "41302701-0196-420f-b319-834a79891db2" 3 | } 4 | -------------------------------------------------------------------------------- /tests/csp/unpublish-multi.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "host_uuid": "41302701-0196-420f-b319-834a79891db1" 3 | } 4 | -------------------------------------------------------------------------------- /tests/csp/unpublish.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "host_uuid": "41302701-0196-420f-b319-834a79891db0" 3 | } 4 | -------------------------------------------------------------------------------- /tests/csp/volume-chap.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-new-volume377", 3 | "size": "1073741824", 4 | "description": "my CHAP volume {pvc}", 5 | "config": { 6 | "csi.storage.k8s.io/pvc/name": "my-whatever-volume", 7 | "authNetworks": "192.168.30.0/24, 192.168.31.0/24", 8 | "compression": "GZIP-1", 9 | "deduplication": "OFF", 10 | "sparse": "true", 11 | "volblocksize": "16K", 12 | "sync": "ALWAYS", 13 | "zpool": "tank" 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/csp/volume-thick.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-new-volume18", 3 | "size": "1073741824", 4 | "description": "my thick volume {pvc}", 5 | "config": { 6 | "csi.storage.k8s.io/pvc/name": "my-thick-volume", 7 | "compression": "GZIP-1", 8 | "deduplication": "OFF", 9 | "sparse": "false", 10 | "volblocksize": "16K", 11 | "sync": "ALWAYS", 12 | "zpool": "tank" 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/csp/volume.yaml: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-new-volume16", 3 | "size": "1073741824", 4 | "description": "my first volume {pvc}", 5 | "config": { 6 | "csi.storage.k8s.io/pvc/name": "my-first-volume", 7 | "compression": "GZIP-1", 8 | "deduplication": "OFF", 9 | "sparse": "true", 10 | "volblocksize": "16K", 11 | "sync": "ALWAYS", 12 | "zpool": "tank" 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/kubevirt/disk-alpine.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: disk-alpine 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 32Gi 12 | storageClassName: e2e-standard-rwo 13 | volumeMode: Block 14 | -------------------------------------------------------------------------------- /tests/kubevirt/vm-alpine.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://github.com/kubevirt/kubevirt/tree/main/examples 3 | apiVersion: kubevirt.io/v1 4 | kind: VirtualMachine 5 | metadata: 6 | name: vm-alpine 7 | spec: 8 | runStrategy: Always 9 | template: 10 | spec: 11 | networks: 12 | - name: default 13 | pod: {} 14 | domain: 15 | devices: 16 | interfaces: 17 | - masquerade: {} 18 | name: default 19 | disks: 20 | - disk: 21 | bus: virtio 22 | name: containerdisk 23 | - disk: 24 | bus: virtio 25 | name: my-pvc 26 | resources: 27 | requests: 28 | memory: 128Mi 29 | terminationGracePeriodSeconds: 0 30 | volumes: 31 | - name: containerdisk 32 | containerDisk: 33 | image: kubevirt/alpine-container-disk-demo:devel 34 | - name: my-pvc 35 | persistentVolumeClaim: 36 | claimName: disk-alpine 37 | -------------------------------------------------------------------------------- /tests/sts/sts.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: web-1 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: nginx # has to match .spec.template.metadata.labels 9 | serviceName: "nginx" 10 | replicas: 5 # by default is 1 11 | minReadySeconds: 10 # by default is 0 12 | template: 13 | metadata: 14 | labels: 15 | app: nginx # has to match .spec.selector.matchLabels 16 | spec: 17 | terminationGracePeriodSeconds: 10 18 | containers: 19 | - name: nginx 20 | image: registry.k8s.io/nginx-slim:0.24 21 | ports: 22 | - containerPort: 80 23 | name: web 24 | volumeMounts: 25 | - name: www 26 | mountPath: /usr/share/nginx/html 27 | volumeClaimTemplates: 28 | - metadata: 29 | name: www 30 | spec: 31 | accessModes: [ "ReadWriteOnce" ] 32 | storageClassName: "e2e-standard-rwo" 33 | resources: 34 | requests: 35 | storage: 1Gi 36 | --- 37 | apiVersion: apps/v1 38 | kind: StatefulSet 39 | metadata: 40 | name: web-2 41 | spec: 42 | selector: 43 | matchLabels: 44 | app: nginx # has to match .spec.template.metadata.labels 45 | serviceName: "nginx" 46 | replicas: 5 # by default is 1 47 | minReadySeconds: 10 # by default is 0 48 | template: 49 | metadata: 50 | labels: 51 | app: nginx # has to match .spec.selector.matchLabels 52 | spec: 53 | terminationGracePeriodSeconds: 10 54 | containers: 55 | - name: nginx 56 | image: registry.k8s.io/nginx-slim:0.24 57 | ports: 58 | - containerPort: 80 59 | name: web 60 | volumeMounts: 61 | - name: www 62 | mountPath: /usr/share/nginx/html 63 | volumeClaimTemplates: 64 | - metadata: 65 | name: www 66 | spec: 67 | accessModes: [ "ReadWriteOnce" ] 68 | storageClassName: "e2e-standard-rwo" 69 | resources: 70 | requests: 71 | storage: 1Gi 72 | --- 73 | apiVersion: apps/v1 74 | kind: StatefulSet 75 | metadata: 76 | name: web-3 77 | spec: 78 | selector: 79 | matchLabels: 80 | app: nginx # has to match .spec.template.metadata.labels 81 | serviceName: "nginx" 82 | replicas: 5 # by default is 1 83 | minReadySeconds: 10 # by default is 0 84 | template: 85 | metadata: 86 | labels: 87 | app: nginx # has to match .spec.selector.matchLabels 88 | spec: 89 | terminationGracePeriodSeconds: 10 90 | containers: 91 | - name: nginx 92 | image: registry.k8s.io/nginx-slim:0.24 93 | ports: 94 | - containerPort: 80 95 | name: web 96 | volumeMounts: 97 | - name: www 98 | mountPath: /usr/share/nginx/html 99 | volumeClaimTemplates: 100 | - metadata: 101 | name: www 102 | spec: 103 | accessModes: [ "ReadWriteOnce" ] 104 | storageClassName: "e2e-standard-rwo" 105 | resources: 106 | requests: 107 | storage: 1Gi 108 | -------------------------------------------------------------------------------- /truenascsp/csp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # (C) Copyright 2024 Hewlett Packard Enterprise Development LP. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | import falcon 26 | import backend 27 | import truenascsp 28 | 29 | from falcon.http_error import HTTPError 30 | 31 | class CSPError(HTTPError): 32 | 33 | def __init__(self, status, error): 34 | super(CSPError, self).__init__(status) 35 | self.status = status 36 | self.error = {"errors":[{"code": status,"message": error }]} 37 | 38 | def to_dict(self, obj_type=dict): 39 | super(CSPError, self).to_dict(obj_type) 40 | obj = self.error 41 | return obj 42 | 43 | class PostLogger: 44 | def process_response(self, req, resp, resource, req_succeded): 45 | api = req.context 46 | 47 | api.logger.debug('Falcon Response (to HPE CSI): %s', resp.status) 48 | api.logger.debug('Last backend requests Response: %s', api.resp_msg) 49 | 50 | 51 | class TokenHandler: 52 | def process_request(self, req, resp): 53 | content = req.media 54 | token = None 55 | array = None 56 | tokens_url = req.url.find('/containers/v1/tokens/') 57 | 58 | api = backend.Handler() 59 | req.context = api 60 | 61 | if tokens_url != -1 and req.method == 'DELETE': 62 | req.context = api 63 | return 64 | 65 | if content: 66 | token = content.get('password') 67 | array = content.get('array_ip') 68 | 69 | if None in (token, array): 70 | token = req.get_header('x-auth-token') 71 | array = req.get_header('x-array-ip') 72 | 73 | if not token: 74 | reason = falcon.HTTP_400 75 | description = 'Missing x-auth-token in header or password in Tokens request' 76 | api.logger.info('%s: %s', reason, description) 77 | raise CSPError(reason, description) 78 | 79 | if not array: 80 | reason = falcon.HTTP_400 81 | description = 'Missing x-array-ip in header or array_ip in Tokens request' 82 | api.logger.info('%s: %s', reason, description) 83 | raise CSPError(reason, description) 84 | 85 | api.backend = array 86 | api.token = token 87 | 88 | api.ping(req) 89 | 90 | if not api.pong: 91 | reason = falcon.HTTP_401 92 | description = 'Unable to authenticate with provided credentials' 93 | api.logger.info('%s: %s', reason, description) 94 | raise CSPError(reason, description) 95 | 96 | # Serve! 97 | SERVE = falcon.API(middleware=[TokenHandler(), PostLogger()]) 98 | 99 | # Routes 100 | SERVE.add_route('/containers/v1/tokens/{token_id:int}', truenascsp.Tokens()) 101 | SERVE.add_route('/containers/v1/tokens', truenascsp.Tokens()) 102 | 103 | SERVE.add_route('/containers/v1/hosts/{host_id}', truenascsp.Hosts()) 104 | SERVE.add_route('/containers/v1/hosts', truenascsp.Hosts()) 105 | 106 | SERVE.add_route('/containers/v1/volumes/{volume_id}', truenascsp.Volume()) 107 | SERVE.add_route('/containers/v1/volumes', truenascsp.Volumes()) 108 | 109 | SERVE.add_route('/containers/v1/volumes/{volume_id}/actions/publish', truenascsp.Publish()) 110 | SERVE.add_route('/containers/v1/volumes/{volume_id}/actions/unpublish', truenascsp.Unpublish()) 111 | 112 | SERVE.add_route('/containers/v1/snapshots/{snapshot_id}', truenascsp.Snapshot()) 113 | SERVE.add_route('/containers/v1/snapshots', truenascsp.Snapshots()) 114 | -------------------------------------------------------------------------------- /truenascsp/truenascsp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # (C) Copyright 2024 Hewlett Packard Enterprise Development LP. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | from time import time 26 | from time import sleep 27 | from multiprocessing import Lock 28 | import re 29 | import traceback 30 | import json 31 | import falcon 32 | import backend 33 | 34 | publish_lock = Lock() 35 | unpublish_lock = Lock() 36 | hosts_lock = Lock() 37 | 38 | class Unpublish: 39 | def on_put(self, req, resp, volume_id): 40 | unpublish_lock.acquire() 41 | api = req.context 42 | content = req.media 43 | system_version = api.version() 44 | 45 | try: 46 | dataset_name = api.xslt_volume_id_to_name(volume_id) 47 | access_name = api.access_name.format(dataset_name=dataset_name) 48 | 49 | # get target from volume name 50 | target = api.fetch('iscsi/target', field='name', value=access_name) 51 | 52 | api.logger.debug('Target being updated: %s', target) 53 | 54 | # find ID of initiator being removed 55 | initiator = {} 56 | 57 | if target: 58 | # get initiators from host 59 | host = api.fetch('iscsi/initiator', field='comment', 60 | value=content.get('host_uuid'), returnBy=dict) 61 | 62 | # get initiators from access_name 63 | initiator = api.fetch('iscsi/initiator', field='comment', 64 | value=access_name, returnBy=dict) 65 | 66 | if host and initiator: 67 | api.logger.debug('Initiator host requested to be unpublished: %s', host.get('id')) 68 | api.logger.debug('Initiator target requested to be unpublished: %s', initiator.get('id')) 69 | 70 | new_initiators = [] 71 | 72 | # Remove host initiator from target initiator 73 | for initiator_preserve in initiator.get('initiators'): 74 | if initiator_preserve not in host.get('initiators'): 75 | new_initiators.append(initiator_preserve) 76 | api.logger.debug('Initiator to be preserved: %s', initiator_preserve) 77 | 78 | api.logger.debug('Initiators left intact: %s', new_initiators) 79 | 80 | req_backend = {'initiators': new_initiators } 81 | 82 | else: 83 | req_backend = {'initiators': [] } 84 | 85 | if initiator: # if initiator was deleted manually 86 | if req_backend.get('initiators'): 87 | api.put('iscsi/initiator/id/{tid}'.format(tid=initiator.get('id')), req_backend) 88 | api.logger.info('Updating IQNs on target initiator: %s', access_name) 89 | else: 90 | api.delete('iscsi/initiator/id/{tid}'.format(tid=initiator.get('id'))) 91 | api.logger.info('Deleted target initiator: %s', access_name) 92 | 93 | # FreeNAS 94 | if system_version == 'LEGACY': 95 | api.delete('iscsi/target/id/{tid}'.format(tid=target.get('id'))) 96 | api.logger.info('Deleted residual target on FreeNAS: %s', target.get('name')) 97 | residual_extent = api.fetch('iscsi/extent', field='name', 98 | value=access_name) 99 | if residual_extent: 100 | api.delete('iscsi/extent/id/{eid}'.format(eid=residual_extent.get('id'))) 101 | api.logger.info('Deleted residual extent on FreeNAS: %s', residual_extent.get('name')) 102 | 103 | resp.status = falcon.HTTP_204 104 | api.logger.info('Volume unpublished: %s', volume_id) 105 | 106 | except Exception: 107 | resp.body = api.csp_error( 108 | 'Exception during unpublish', traceback.format_exc()) 109 | resp.status = falcon.HTTP_500 110 | 111 | finally: 112 | unpublish_lock.release() 113 | 114 | 115 | class Publish: 116 | def on_put(self, req, resp, volume_id): 117 | publish_lock.acquire() 118 | api = req.context 119 | 120 | try: 121 | content = req.media 122 | 123 | dataset_name = api.xslt_volume_id_to_name(volume_id) 124 | dataset_id = api.xslt_id_to_dataset(volume_id) 125 | access_name = api.access_name.format(dataset_name=dataset_name) 126 | 127 | publish = api.apply_publish(access_name, content=content, 128 | dataset=api.fetch('pool/dataset', field='id', 129 | value=dataset_id)) 130 | 131 | api.logger.debug('Backend publish results: %s', publish) 132 | api.logger.debug('Frontend publish content: %s', content) 133 | 134 | auth = api.fetch('iscsi/auth', field='tag', value=int(api.chap_tag), returnBy=dict) 135 | 136 | # respond to CSI 137 | if publish.get('target', {}).get('extent', {}).get('naa') and publish.get('iscsi_config', {}).get('basename'): 138 | csi_resp = { 139 | 'discovery_ips': api.discovery_ips(), 140 | 'access_protocol': 'iscsi', 141 | 'lun_id': 0, 142 | 'serial_number': publish.get('target').get('extent').get('naa').lstrip('0x'), 143 | 'chap_user': auth.get('user', ''), 144 | 'chap_password': auth.get('secret',''), 145 | 'target_names': [ 146 | '{base}:{access_name}'.format( 147 | base=publish.get('iscsi_config').get('basename'), 148 | access_name=access_name) 149 | ] 150 | } 151 | 152 | resp.body = json.dumps(csi_resp) 153 | resp.status = falcon.HTTP_200 154 | else: 155 | resp.body = api.csp_error('Exception', 156 | 'Unable to publish volume: {trace}'.format(trace=traceback.format_exc())) 157 | resp.status = falcon.HTTP_500 158 | 159 | api.logger.debug('CSP response: %s', resp.body) 160 | api.logger.info('Volume published: %s', volume_id) 161 | 162 | except Exception: 163 | resp.body = api.csp_error('Exception', traceback.format_exc()) 164 | resp.status = falcon.HTTP_500 165 | 166 | finally: 167 | publish_lock.release() 168 | 169 | 170 | class Volume: 171 | def on_put(self, req, resp, volume_id): 172 | api = req.context 173 | try: 174 | dataset = api.fetch('pool/dataset', field='name', 175 | value=api.xslt_id_to_dataset(volume_id)) 176 | 177 | if dataset: 178 | content = req.media 179 | 180 | req_backend = {} 181 | 182 | if content.get('size'): 183 | req_backend.update({'volsize': int(content.get('size'))}) 184 | if content.get('description'): 185 | req_backend.update({'comments': content.get('description')}) 186 | 187 | config = content.get('config') 188 | 189 | if config: 190 | for key in config: 191 | if key in api.dataset_mutables: 192 | req_backend.update({key: config.get(key)}) 193 | else: 194 | resp.body = api.csp_error('Bad Request', 195 | ('The request could not ' 196 | 'be understood by the ' 197 | 'server. Unexpected argument ' 198 | '"{key}"'.format(key=key))) 199 | resp.status = falcon.HTTP_400 200 | return 201 | 202 | api.put(api.uri_id('pool/dataset', 203 | dataset.get('name')), req_backend) 204 | 205 | if api.req_backend.status_code != 200: 206 | resp.body = api.csp_error('Bad Request', 207 | 'TrueNAS API returned: {content}'.format(content=api.req_backend.content.decode('utf-8'))) 208 | resp.status = falcon.HTTP_500 209 | return 210 | 211 | dataset = api.fetch( 212 | 'pool/dataset', field='name', value=api.xslt_id_to_dataset(volume_id)) 213 | csi_resp = api.dataset_to_volume(dataset) 214 | resp.body = json.dumps(csi_resp) 215 | 216 | api.logger.debug('CSP response: %s', resp.body) 217 | api.logger.info('Volume updated: %s', csi_resp.get('id')) 218 | 219 | except Exception: 220 | resp.body = api.csp_error('Exception', traceback.format_exc()) 221 | resp.status = falcon.HTTP_500 222 | 223 | def on_get(self, req, resp, volume_id): 224 | api = req.context 225 | try: 226 | dataset = api.fetch('pool/dataset', field='name', 227 | value=api.xslt_id_to_dataset(volume_id)) 228 | 229 | if dataset: 230 | csi_resp = api.dataset_to_volume(dataset) 231 | resp.body = json.dumps(csi_resp) 232 | 233 | api.logger.debug('CSP response: %s', resp.body) 234 | api.logger.info('Volume found: %s', volume_id) 235 | else: 236 | resp.body = api.csp_error( 237 | 'Not found', 'Volume with id {volume_id} not found.'.format(volume_id=volume_id)) 238 | resp.status = falcon.HTTP_404 239 | 240 | except Exception: 241 | resp.body = api.csp_error('Exception', traceback.format_exc()) 242 | resp.status = falcon.HTTP_500 243 | 244 | def on_delete(self, req, resp, volume_id): 245 | api = req.context 246 | 247 | try: 248 | dataset_name = api.xslt_volume_id_to_name(volume_id) 249 | access_name = api.access_name.format(dataset_name=dataset_name) 250 | 251 | # delete dataset 252 | dataset = api.fetch('pool/dataset', field='name', value=api.xslt_id_to_dataset(volume_id)) 253 | 254 | if dataset: 255 | csi_volume = api.dataset_to_volume(dataset) 256 | 257 | if csi_volume.get('published'): 258 | resp.body = api.csp_error( 259 | 'Bad Request', 'Cannot delete a published volume') 260 | resp.status = falcon.HTTP_400 261 | else: 262 | if api.dataset_is_busy(dataset): 263 | resp.body = api.csp_error( 264 | 'Conflict', '{volume_id} has snapshots with holds or dependent clones'.format(volume_id=volume_id)) 265 | resp.status = falcon.HTTP_409 266 | else: 267 | api.delete(api.uri_id('pool/dataset', 268 | dataset.get('name')), body='{"recursive": true, "force": true}') 269 | 270 | # things might be pending 271 | dataset_deletion = api.backend_retries 272 | 273 | while api.fetch('pool/dataset', field='name', 274 | value=api.xslt_id_to_dataset(volume_id)) and dataset_deletion: 275 | dataset_deletion -= 1 276 | sleep(api.backend_delay) 277 | api.delete(api.uri_id('pool/dataset', 278 | dataset.get('name')), body='{"recursive": true, "force": true}') 279 | api.logger.info('Dataset deletion retried: %s', volume_id) 280 | 281 | resp.status = falcon.HTTP_204 282 | api.logger.info('Volume deleted with id: %s', volume_id) 283 | else: 284 | resp.status = falcon.HTTP_404 285 | 286 | except Exception: 287 | resp.body = api.csp_error('Exception', 'Unable to delete {volume_id}: {trace}'.format( 288 | volume_id=volume_id, trace=traceback.format_exc())) 289 | resp.status = falcon.HTTP_500 290 | 291 | 292 | class Volumes: 293 | def on_get(self, req, resp): 294 | api = req.context 295 | try: 296 | if req.params.get('name'): 297 | dataset = api.fetch('pool/dataset', field='name', 298 | value='/{name}'.format(name=req.params.get('name')), operator='$') 299 | 300 | if dataset: 301 | csi_resp = [api.dataset_to_volume(dataset)] 302 | resp.body = json.dumps(csi_resp) 303 | 304 | api.logger.debug('CSP response: %s', resp.body) 305 | api.logger.info('Volume found: %s', req.params.get('name')) 306 | 307 | else: 308 | resp.body = api.csp_error('Not found', 'Volume with name {volume_name} not found.'.format( 309 | volume_name=req.params.get('name'))) 310 | resp.status = falcon.HTTP_404 311 | else: 312 | pass # FIXME 313 | 314 | except Exception: 315 | resp.body = api.csp_error('Exception', traceback.format_exc()) 316 | resp.status = falcon.HTTP_500 317 | 318 | def on_post(self, req, resp): 319 | api = req.context 320 | 321 | try: 322 | content = req.media 323 | root = content.get('config').get('root', api.dataset_defaults.get('root')) 324 | 325 | if content.get('clone'): 326 | req_backend = { 327 | 'snapshot': api.xslt_id_to_dataset(content.get('base_snapshot_id')), 328 | 'dataset_dst': '{root}/{volume_name}'.format(volume_name=content.get('name'), root=root), 329 | } 330 | api.post('zfs/snapshot/clone', req_backend) 331 | 332 | dataset = api.fetch('pool/dataset', field='name', 333 | value='{root}/{volume_name}'.format(volume_name=content.get('name'), root=root)) 334 | else: 335 | req_backend = { 336 | 'type': 'VOLUME', 337 | # FIXME 338 | 'comments': content.get('description', api.dataset_defaults.get('description')).format( 339 | pvc=content.get('config').get('csi.storage.k8s.io/pvc/name', 'pvc'), 340 | namespace=content.get('config').get('csi.storage.k8s.io/pvc/namespace', 'namespace'), 341 | pv=content.get('config').get('csi.storage.k8s.io/pv/name', 'pv') 342 | ), 343 | 'name': '{root}/{volume_name}'.format(volume_name=content.get('name'), root=root), 344 | 'volsize': '{size}'.format(size=int(content.get('size'))), 345 | 'volblocksize': content.get('config').get('volblocksize', api.dataset_defaults.get('volblocksize')), 346 | 'sparse': json.loads(content.get('config').get('sparse', api.dataset_defaults.get('sparse')).lower()), 347 | 'deduplication': content.get('config').get('deduplication', api.dataset_defaults.get('deduplication')), 348 | 'sync': content.get('config').get('sync', api.dataset_defaults.get('sync')), 349 | 'compression': content.get('config').get('compression', api.dataset_defaults.get('compression')) 350 | } 351 | api.post('pool/dataset', req_backend) 352 | 353 | dataset = api.req_backend.json() 354 | 355 | if api.req_backend.status_code != 200: 356 | resp.body = api.csp_error('Bad Request', 357 | 'TrueNAS API returned: {content}'.format(content=api.req_backend.content.decode('utf-8'))) 358 | resp.status = falcon.HTTP_500 359 | return 360 | 361 | # create target 362 | res = api.create_target(dataset, content=content) 363 | 364 | # respond to CSI driver 365 | csi_resp = api.dataset_to_volume(dataset) 366 | resp.body = json.dumps(csi_resp) 367 | 368 | api.logger.debug('Target details: %s', res) 369 | api.logger.debug('CSP response: %s', resp.body) 370 | api.logger.info('Volume created: %s', csi_resp.get('name')) 371 | 372 | except Exception: 373 | resp.body = api.csp_error('Exception', 374 | 'Unable to create new volume: {trace}'.format(trace=traceback.format_exc())) 375 | resp.status = falcon.HTTP_500 376 | 377 | 378 | class Hosts: 379 | def on_post(self, req, resp): 380 | hosts_lock.acquire() 381 | api = req.context 382 | 383 | content = req.media 384 | 385 | try: 386 | payload = api.apply_initiator(content.get('uuid'), content=content) 387 | 388 | csi_resp = { 389 | 'id': payload.get('id'), 390 | 'name': payload.get('comment'), 391 | 'uuid': payload.get('comment'), 392 | 'iqns': payload.get('initiators'), 393 | 'networks': content.get('networks'), 394 | 'chap_user': content.get('chap_user', ''), 395 | 'chap_password': content.get('chap_password', ''), 396 | 'wwpns': [] 397 | } 398 | 399 | resp.body = json.dumps(csi_resp) 400 | 401 | api.logger.debug('CSP response: %s', resp.body) 402 | api.logger.info('Host initiator created: %s', payload.get('comment')) 403 | 404 | except Exception: 405 | resp.body = api.csp_error('Exception', traceback.format_exc()) 406 | resp.status = falcon.HTTP_500 407 | finally: 408 | hosts_lock.release() 409 | 410 | def on_delete(self, req, resp, host_id): 411 | api = req.context 412 | 413 | try: 414 | initiator = api.fetch( 415 | 'iscsi/initiator', field='comment', value=host_id) 416 | 417 | if initiator: 418 | api.delete( 419 | 'iscsi/initiator/id/{id}'.format(id=str(initiator.get('id')))) 420 | resp.status = api.resp_msg 421 | api.logger.info('Host initiator deleted: %s', initiator.get('comment')) 422 | else: 423 | api.logger.info('Host initiator not found: %s', host_id) 424 | resp.status = falcon.HTTP_404 425 | except Exception: 426 | resp.body = api.csp_error('Exception', traceback.format_exc()) 427 | resp.status = falcon.HTTP_500 428 | 429 | 430 | class Tokens: 431 | def on_post(self, req, resp): 432 | api = req.context 433 | 434 | try: 435 | iscsi_config = api.fetch('iscsi/global') 436 | 437 | if not api.valid_iscsi_basename(iscsi_config.get('basename')): 438 | resp.body = api.csp_error('Unconfigured', 439 | '{base} is not a valid basename, use {basenames}'.format( 440 | base=iscsi_config.get('basename'), 441 | basenames=' or '.join(api.target_basenames))) 442 | resp.status = falcon.HTTP_400 443 | return 444 | 445 | portal = api.fetch('iscsi/portal', field='comment', 446 | value=api.target_portal) 447 | 448 | if isinstance(portal, list): 449 | resp.body = api.csp_error('Unconfigured', 450 | 'No single iSCSI portal named "{comment}" found (duplicates are not allowed)'.format(comment=api.target_portal)) 451 | resp.status = falcon.HTTP_400 452 | return 453 | 454 | ips = api.discovery_ips() 455 | 456 | if not ips: 457 | resp.body = api.csp_error('Unconfigured', 458 | 'No IP addresses found on the portal') 459 | resp.status = falcon.HTTP_400 460 | return 461 | 462 | if '0.0.0.0' in ips or '::' in ips: 463 | resp.body = api.csp_error('Unconfigured', 464 | 'Using "0.0.0.0" or "::" as listenining inferface on the portal is not supported') 465 | resp.status = falcon.HTTP_400 466 | return 467 | 468 | csi_resp = { 469 | 'id': str(time()), 470 | 'session_token': api.token, 471 | 'array_ip': api.backend, 472 | 'username': req.params.get('username'), 473 | 'creation_time': int(time()), 474 | 'expiry_time': int(time()) + 86400 475 | } 476 | 477 | resp.body = json.dumps(csi_resp) 478 | 479 | api.logger.debug('CSP response: %s', resp.body) 480 | api.logger.info('Token created (not logged)') 481 | 482 | except Exception: 483 | resp.body = api.csp_error('Exception', traceback.format_exc()) 484 | resp.status = falcon.HTTP_500 485 | 486 | def on_delete(self, req, resp, token_id): 487 | resp.status = falcon.HTTP_204 488 | 489 | 490 | class Snapshots: 491 | def on_post(self, req, resp): 492 | api = req.context 493 | 494 | content = req.media 495 | system_version = api.version() 496 | 497 | try: 498 | snapshot_name = content.get('name') 499 | dataset_name = api.xslt_id_to_dataset(content.get('volume_id')) 500 | 501 | # TrueNAS API is broken 502 | snapshot = api.fetch('zfs/snapshot', field='name', 503 | value='{dataset_name}@{snapshot_name}'.format(dataset_name=dataset_name, 504 | snapshot_name=snapshot_name)) 505 | 506 | api.logger.debug('Snapshot exists: %s', snapshot) 507 | 508 | if not snapshot: 509 | req_backend = { 510 | 'name': snapshot_name, 511 | 'dataset': dataset_name, 512 | } 513 | api.post('zfs/snapshot', req_backend) 514 | 515 | if api.req_backend.status_code != 200: 516 | resp.body = api.csp_error('Bad Request', 517 | 'TrueNAS API returned: {content}'.format(content=api.req_backend.content.decode('utf-8'))) 518 | resp.status = falcon.HTTP_500 519 | return 520 | 521 | # TrueNAS API is broken 522 | snapshot = api.fetch('zfs/snapshot', field='name', 523 | value='{dataset_name}@{snapshot_name}'.format(dataset_name=dataset_name, 524 | snapshot_name=snapshot_name)) 525 | 526 | csi_resp = api.snapshot_to_snapshot(snapshot) 527 | resp.body = json.dumps(csi_resp) 528 | 529 | api.logger.debug('CSP response: %s', resp.body) 530 | api.logger.info('Snapshot created: %s', csi_resp.get('name')) 531 | 532 | # create a hold if VolumeSnapshot res 533 | if api.clone_from_pvc_prefix not in snapshot.get('id') and system_version == 'SCALE': 534 | req_backend = { 'id': snapshot.get('id') } 535 | api.post('zfs/snapshot/hold', req_backend) 536 | api.logger.info('Dataset held: %s', snapshot.get('id')) 537 | 538 | except Exception: 539 | resp.body = api.csp_error('Exception', traceback.format_exc()) 540 | resp.status = falcon.HTTP_500 541 | 542 | def on_get(self, req, resp): 543 | api = req.context 544 | try: 545 | csi_resp = [] 546 | 547 | if req.params.get('name'): 548 | snapshot = api.fetch('zfs/snapshot', field='snapshot_name', 549 | extras={"holds": True}, value=api.xslt_id_to_dataset(req.params.get('name'))) 550 | 551 | if snapshot and snapshot.get('holds'): 552 | csi_resp = [api.snapshot_to_snapshot(snapshot)] 553 | else: 554 | # assuming too much here FIXME 555 | snapshots = api.fetch('zfs/snapshot', field='dataset', 556 | extras={"holds": True }, returnBy=list, value=api.xslt_id_to_dataset(req.params.get('volume_id'))) 557 | 558 | for snapshot in snapshots: 559 | if snapshot.get('holds'): 560 | csi_resp.append(api.snapshot_to_snapshot(snapshot)) 561 | 562 | if csi_resp: 563 | resp.body = json.dumps(csi_resp) 564 | api.logger.debug('CSP response: %s', resp.body) 565 | api.logger.info('Snapshot(s) found on volume %s', 566 | req.params.get('volume_id')) 567 | 568 | else: 569 | if req.params.get('name'): 570 | resp.status = falcon.HTTP_404 571 | else: 572 | resp.status = falcon.HTTP_200 573 | resp.body = json.dumps(csi_resp) 574 | api.logger.debug('No snapshots found on volume %s', req.params.get('volume_id')) 575 | 576 | except Exception: 577 | resp.body = api.csp_error('Exception', traceback.format_exc()) 578 | resp.status = falcon.HTTP_500 579 | return 580 | 581 | 582 | class Snapshot: 583 | def on_get(self, req, resp, snapshot_id): 584 | api = req.context 585 | try: 586 | snapshot = api.fetch('zfs/snapshot', field='id', 587 | value=api.xslt_id_to_dataset(snapshot_id)) 588 | 589 | if snapshot: 590 | csi_resp = api.snapshot_to_snapshot(snapshot) 591 | resp.body = json.dumps(csi_resp) 592 | 593 | api.logger.debug('CSP response: %s', resp.body) 594 | api.logger.info('Snapshot found %s', snapshot_id) 595 | 596 | else: 597 | resp.body = api.csp_error( 598 | 'Not found', 'Snapshot not found {snapshot_id}'.format(snapshot_id=snapshot_id)) 599 | resp.status = falcon.HTTP_404 600 | 601 | except Exception: 602 | resp.body = api.csp_error('Exception', traceback.format_exc()) 603 | resp.status = falcon.HTTP_500 604 | 605 | def on_delete(self, req, resp, snapshot_id): 606 | api = req.context 607 | system_version = api.version() 608 | 609 | try: 610 | snapshot = api.fetch('zfs/snapshot', field='id', 611 | value=api.xslt_id_to_dataset(snapshot_id), 612 | returnBy=dict) 613 | 614 | if snapshot and isinstance(snapshot, dict): 615 | snapshot_clones = api.backend_retries 616 | 617 | # pretend snapshot is deleted if it has clones, but wait first 618 | while int(snapshot.get('properties').get('numclones').get('value')) > 0 and snapshot_clones: 619 | api.logger.info('Snapshot has clones, waiting: %s', snapshot_id) 620 | sleep(api.backend_delay) 621 | snapshot = api.fetch('zfs/snapshot', field='id', 622 | value=api.xslt_id_to_dataset(snapshot_id)) 623 | snapshot_clones -= 1 624 | 625 | if snapshot_clones == 0: 626 | api.logger.info('Snapshot had clones, not deleted: %s', snapshot_id) 627 | 628 | # release the snapshot hold 629 | req_backend = { 'id': snapshot.get('id') } 630 | if system_version == 'SCALE': 631 | api.post('zfs/snapshot/release', req_backend) 632 | api.logger.info('Dataset released: %s', snapshot.get('id')) 633 | 634 | resp.status = falcon.HTTP_204 635 | return 636 | 637 | # FIXME dupe code 638 | req_backend = { 'id': snapshot.get('id') } 639 | if system_version == 'SCALE': 640 | api.post('zfs/snapshot/release', req_backend) 641 | api.logger.info('Dataset released: %s', snapshot.get('id')) 642 | 643 | api.delete(api.uri_id('zfs/snapshot', snapshot.get('id'))) 644 | 645 | # things might be pending 646 | snapshot_deletion = api.backend_retries 647 | 648 | while api.fetch('zfs/snapshot', field='id', 649 | value=api.xslt_id_to_dataset(snapshot_id)) and snapshot_deletion: 650 | snapshot_deletion -= 1 651 | sleep(api.backend_delay) 652 | api.delete(api.uri_id('zfs/snapshot', snapshot.get('id'))) 653 | api.logger.info('Snapshot deletion retried: %s', snapshot_id) 654 | 655 | resp.status = falcon.HTTP_204 656 | api.logger.info('Snapshot deleted: %s', snapshot_id) 657 | else: 658 | api.logger.info('Snapshot not found: %s', snapshot_id) 659 | resp.status = falcon.HTTP_404 660 | except Exception: 661 | resp.body = api.csp_error('Exception', traceback.format_exc()) 662 | resp.status = falcon.HTTP_500 663 | --------------------------------------------------------------------------------