├── .github ├── CODEOWNERS ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── common-workflows.yaml │ ├── go-version.yaml │ ├── image-version-update.yaml │ ├── release.yaml │ ├── update-libraries-to-commits.yaml │ └── update-libraries.yaml ├── .gitignore ├── .trivyignore ├── Dockerfile ├── Gopkg.toml ├── LICENSE ├── Makefile ├── README.md ├── common ├── constants │ ├── consts.go │ └── envvars.go ├── k8sutils │ ├── k8sutils.go │ └── k8sutils_test.go └── utils │ ├── logging.go │ ├── utils.go │ └── utils_test.go ├── core ├── .gitignore ├── core.go ├── semver.tpl └── semver │ ├── semver.go │ └── semver_test.go ├── csi-utils ├── csiutils.go └── csiutils_test.go ├── dell-csi-helm-installer ├── .gitignore ├── README.md ├── common.sh ├── csi-install.sh ├── csi-offline-bundle.md ├── csi-offline-bundle.sh ├── csi-uninstall.sh ├── verify-csi-isilon.sh └── verify.sh ├── docker.mk ├── go.mod ├── go.sum ├── licenses └── LICENSE ├── main.go ├── main_test.go ├── overrides.mk ├── provider ├── provider.go └── provider_test.go ├── samples ├── persistentvolumeclaim │ ├── pvc-from-pvc.yaml │ ├── pvc-from-snapshot.yaml │ └── pvc.yaml ├── pod │ ├── inline-volume.yaml │ └── nginx.yaml ├── secret │ ├── empty-secret.yaml │ ├── karavi-authorization-config.json │ └── secret.yaml ├── storageclass │ ├── isilon-replication.yaml │ └── isilon.yaml ├── volumesnapshot │ └── snapshot-of-test-pvc.yaml └── volumesnapshotclass │ └── isilon-volumesnapshotclass-v1.yaml ├── service ├── controller.go ├── controllerNodeToArrayConnectivity.go ├── controllerNodeToArrayConnectivity_test.go ├── controller_test.go ├── csi_extension_server.go ├── features │ ├── controller_create_delete_snapshot.feature │ ├── controller_create_delete_volume.feature │ ├── controller_expand_volume.feature │ ├── csi_extension.feature │ ├── isiService.feature │ ├── node_publish_unpublish.feature │ ├── replication.feature │ └── service.feature ├── identity.go ├── interceptor │ ├── interceptor.go │ └── interceptor_test.go ├── isiService.go ├── isiService_test.go ├── mock │ ├── cluster │ │ └── get_cluster_config.txt │ ├── export │ │ ├── create_export_557.txt │ │ ├── export_not_found_by_id.txt │ │ ├── get_all_exports_including_volume2.txt │ │ ├── get_export_557.txt │ │ ├── get_export_not_found.txt │ │ ├── get_export_snapVol3.txt │ │ ├── get_exports_snapVol2.txt │ │ ├── get_exports_with_invalid_resume.txt │ │ ├── get_exports_with_limit.txt │ │ └── get_exports_with_resume.txt │ ├── jobs │ │ ├── created.json │ │ ├── empty.json │ │ └── running.json │ ├── k8s │ │ ├── admin.conf │ │ └── fakeNodeCreator.go │ ├── loglevel │ │ ├── logBackup.yaml │ │ ├── logConfig.yaml │ │ ├── logConfigError.yaml │ │ └── logLevelInfo.yaml │ ├── policy │ │ ├── empty.txt │ │ ├── get_policies.txt │ │ ├── get_policies2.txt │ │ ├── get_policies_sync.txt │ │ ├── get_target_policies.txt │ │ ├── get_target_policies2.txt │ │ └── tp_failed.txt │ ├── quota │ │ ├── create_quota.txt │ │ ├── get_quota_by_id.txt │ │ ├── get_quota_license.txt │ │ ├── invalid_quota.txt │ │ └── quota_not_found.txt │ ├── report │ │ ├── get_report_by_policy.txt │ │ └── get_report_no_error.txt │ ├── secret │ │ └── secret.yaml │ ├── snapshot │ │ ├── create_snapshot.txt │ │ ├── get_existent_compatible_snapshot.txt │ │ ├── get_existent_snapshot_2.txt │ │ ├── get_existent_snapshot_4.txt │ │ ├── get_non_existent_snapshot.txt │ │ ├── get_snapshot_size.txt │ │ └── get_zone_by_name.txt │ ├── statistics │ │ └── IO_not_inprogress.txt │ └── volume │ │ ├── get_non_existent_volume.txt │ │ ├── get_volume2_without_metadata.txt │ │ └── get_volume_size.txt ├── mount.go ├── mount_test.go ├── node.go ├── nodeConnectivityChecker.go ├── nodeConnectivityChecker_test.go ├── node_test.go ├── replication.go ├── replication_test.go ├── service.go ├── service_test.go ├── step_defs_test.go ├── step_handlers_test.go └── test │ └── tmp │ ├── datafile │ └── datafile2 └── test ├── helm ├── .gitignore ├── 10vols │ ├── Chart.yaml │ └── templates │ │ ├── pvc.yaml │ │ └── test.yaml ├── 1vol │ ├── Chart.yaml │ └── templates │ │ ├── createSnapshot.yaml │ │ ├── createVolumeFromSnapshot.yaml │ │ ├── createVolumeFromVolume.yaml │ │ ├── pvc0.yaml │ │ ├── test_pod.yaml │ │ └── test_statefulset.yaml ├── 2vols+restore │ ├── Chart.yaml │ └── templates │ │ ├── createFromSnap.yaml │ │ ├── pvc0.yaml │ │ ├── pvc1.yaml │ │ └── test.yaml ├── 2vols │ ├── Chart.yaml │ └── templates │ │ ├── pvc0.yaml │ │ ├── pvc1.yaml │ │ └── test.yaml ├── 7vols │ ├── Chart.yaml │ └── templates │ │ ├── pvc.yaml │ │ └── test.yaml ├── README.md ├── deletepvcs.sh ├── get.volume.ids ├── logit.sh ├── snap1.yaml ├── snap2.yaml ├── snaprestoretest.sh ├── snaptest.sh ├── starttest.sh └── stoptest.sh ├── ingestion ├── README.md ├── ingestion_test.sh └── sample │ ├── isilonstaticpv.yaml │ └── isilonstaticpvc.yaml ├── integration ├── README.md ├── config ├── env_Custom_Topology_Enabled.sh ├── env_Quota_Enabled.sh ├── env_Quota_notEnabled.sh ├── env_nodeIP1.sh ├── env_nodeIP2.sh ├── features │ ├── integration.feature │ ├── main_integration.feature │ └── mock_different_nodeIPs.feature ├── integration_test.go ├── kubevirt │ ├── README.md │ ├── isilon-sc.yaml │ └── manifest.yaml ├── run.sh └── step_defs_test.go └── scale_longevity ├── README.md ├── env.sh ├── longevity.sh ├── scaletest.sh └── volumes ├── Chart.yaml ├── templates └── test.yaml └── values.yaml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS 2 | # 3 | # documentation for this file can be found at: 4 | # https://help.github.com/en/articles/about-code-owners 5 | 6 | # These are the default owners for the code and will 7 | # be requested for review when someone opens a pull request. 8 | # order is alphabetical for easier maintenance. 9 | # 10 | # Aaron Tye (atye) 11 | # Alik Saring (alikdell) 12 | # Bahubali Jain (bpjain2004) 13 | # Chiman Jain (chimanjain) 14 | # Christian Coffield (ChristianAtDell) 15 | # Don Khan (donatwork) 16 | # Harish H (HarishH-DELL) 17 | # Meghana GM (meggm) 18 | # Nitesh Rewatkar (nitesh3108) 19 | # Prasanna Muthukumaraswamy (prablr79) 20 | # Rajkumar Palani (rajkumar-palani) 21 | # Sakshi Makkar (Sakshi-dell) 22 | # Santhosh Lakshmanan (santhoshatdell) 23 | # Shayna Finocchiaro (shaynafinocchiaro) 24 | # Sharmila Ramamoorthy (sharmilarama) 25 | # Shefali Malhotra (shefali-malhotra) 26 | 27 | # for all files: 28 | * @atye @alikdell @bpjain2004 @chimanjain @ChristianAtDell @donatwork @HarishH-DELL @meggm @nitesh3108 @prablr79 @rajkumar-palani @Sakshi-dell @santhoshatdell @shaynafinocchiaro @sharmilarama @shefali-malhotra 29 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # To get started with Dependabot version updates, you'll need to specify which 3 | # package ecosystems to update and where the package manifests are located. 4 | # Please see the documentation for all configuration options: 5 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 6 | 7 | version: 2 8 | updates: 9 | # Schedule for go module updates 10 | - package-ecosystem: "gomod" 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | day: "sunday" 15 | time: "18:00" 16 | allow: 17 | # Allow direct updates for packages 18 | - dependency-type: direct 19 | ignore: 20 | - dependency-name: "*" 21 | update-types: 22 | - version-update:semver-patch 23 | # a group of dependencies will be updated together in one pull request 24 | groups: 25 | golang: 26 | # group all semantic versioning levels together in one pull request 27 | update-types: 28 | - major 29 | - minor 30 | patterns: 31 | - "*" 32 | 33 | # github actions 34 | - package-ecosystem: "github-actions" 35 | directory: "/" 36 | schedule: 37 | # Check for updates to GitHub Actions every week 38 | interval: "weekly" 39 | day: "saturday" 40 | groups: 41 | github-actions: 42 | patterns: 43 | - "*" 44 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | A few sentences describing the overall goals of the pull request's commits. 3 | 4 | # GitHub Issues 5 | List the GitHub issues impacted by this PR: 6 | 7 | | GitHub Issue # | 8 | | -------------- | 9 | | | 10 | 11 | # Checklist: 12 | 13 | - [ ] I have performed a self-review of my own code to ensure there are no formatting, vetting, linting, or security issues 14 | - [ ] I have verified that new and existing unit tests pass locally with my changes 15 | - [ ] I have not allowed coverage numbers to degenerate 16 | - [ ] I have maintained at least 90% code coverage 17 | - [ ] I have commented my code, particularly in hard-to-understand areas 18 | - [ ] I have made corresponding changes to the documentation 19 | - [ ] I have added tests that prove my fix is effective or that my feature works 20 | - [ ] Backward compatibility is not broken 21 | 22 | # How Has This Been Tested? 23 | Please describe the tests that you ran to verify your changes. Please also list any relevant details for your test configuration 24 | 25 | - [ ] Test A 26 | - [ ] Test B 27 | -------------------------------------------------------------------------------- /.github/workflows/common-workflows.yaml: -------------------------------------------------------------------------------- 1 | name: Common Workflows 2 | on: # yamllint disable-line rule:truthy 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: ["**"] 7 | 8 | jobs: 9 | 10 | # golang static analysis checks 11 | go-static-analysis: 12 | uses: dell/common-github-actions/.github/workflows/go-static-analysis.yaml@main 13 | name: Golang Validation 14 | 15 | common: 16 | name: Quality Checks 17 | uses: dell/common-github-actions/.github/workflows/go-common.yml@main 18 | -------------------------------------------------------------------------------- /.github/workflows/go-version.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Dell Inc., or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Reusable workflow to perform go version update on Golang based projects 10 | name: Go Version Update 11 | 12 | on: # yamllint disable-line rule:truthy 13 | workflow_dispatch: 14 | repository_dispatch: 15 | types: [go-update-workflow] 16 | 17 | jobs: 18 | # go version update 19 | go-version-update: 20 | uses: dell/common-github-actions/.github/workflows/go-version-workflow.yaml@main 21 | name: Go Version Update 22 | secrets: inherit 23 | -------------------------------------------------------------------------------- /.github/workflows/image-version-update.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025 Dell Inc., or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Reusable workflow to perform image version update on Golang based projects 10 | name: Image Version Update 11 | 12 | on: # yamllint disable-line rule:truthy 13 | workflow_dispatch: 14 | inputs: 15 | version: 16 | description: "Version to release (major, minor, patch) Ex: minor" 17 | required: true 18 | repository_dispatch: 19 | types: [image-update-workflow] 20 | 21 | jobs: 22 | # image version update 23 | image-version-update: 24 | uses: dell/common-github-actions/.github/workflows/image-version-workflow.yaml@main 25 | with: 26 | version: "${{ github.event.inputs.version || 'minor' }}" 27 | secrets: inherit 28 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release CSI-Powerscale 2 | # Invocable as a reusable workflow 3 | # Can be manually triggered 4 | on: # yamllint disable-line rule:truthy 5 | workflow_call: 6 | workflow_dispatch: 7 | inputs: 8 | option: 9 | description: 'Select version to release' 10 | required: true 11 | type: choice 12 | default: 'minor' 13 | options: 14 | - major 15 | - minor 16 | - patch 17 | - n-1/n-2 patch (Provide input in the below box) 18 | version: 19 | description: "Patch version to release. example: 2.1.x (Use this only if n-1/n-2 patch is selected)" 20 | required: false 21 | type: string 22 | repository_dispatch: 23 | types: [auto-release-workflow] 24 | jobs: 25 | process-inputs: 26 | name: Process Inputs 27 | runs-on: ubuntu-latest 28 | outputs: 29 | processedVersion: ${{ steps.set-version.outputs.versionEnv }} 30 | steps: 31 | - name: Process input 32 | id: set-version 33 | shell: bash 34 | run: | 35 | echo "Triggered by: ${{ github.event_name }}" 36 | if [[ "${{ github.event_name }}" == "repository_dispatch" ]]; then 37 | echo "versionEnv=minor" >> $GITHUB_OUTPUT 38 | exit 0 39 | fi 40 | if [[ "${{ github.event.inputs.version }}" != "" && "${{ github.event.inputs.option }}" == "n-1/n-2 patch (Provide input in the below box)" ]]; then 41 | # if both version and option are provided, then version takes precedence i.e. patch release for n-1/n-2 42 | echo "versionEnv=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT 43 | exit 0 44 | fi 45 | if [[ "${{ github.event.inputs.option }}" != "n-1/n-2 patch (Provide input in the below box)" ]]; then 46 | # if only option is provided, then option takes precedence i.e. minor, major or patch release 47 | echo "versionEnv=${{ github.event.inputs.option }}" >> $GITHUB_OUTPUT 48 | exit 0 49 | fi 50 | # if neither option nor version is provided, then minor release is taken by default (Auto-release) 51 | echo "versionEnv=minor" >> $GITHUB_OUTPUT 52 | csm-release: 53 | needs: [process-inputs] 54 | uses: dell/common-github-actions/.github/workflows/csm-release-driver-module.yaml@main 55 | name: Release CSM Drivers and Modules 56 | with: 57 | version: ${{ needs.process-inputs.outputs.processedVersion }} 58 | images: 'csi-isilon' 59 | secrets: inherit 60 | -------------------------------------------------------------------------------- /.github/workflows/update-libraries-to-commits.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025 Dell Inc., or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Reusable workflow to perform updates of Dell client libraries to latest commits 10 | name: Dell Libraries Commit Update 11 | on: # yamllint disable-line rule:truthy 12 | workflow_dispatch: 13 | repository_dispatch: 14 | types: [latest-commits-libraries] 15 | 16 | jobs: 17 | package-update: 18 | uses: dell/common-github-actions/.github/workflows/update-libraries-to-commits.yml@main 19 | name: Dell Libraries Update 20 | secrets: inherit 21 | -------------------------------------------------------------------------------- /.github/workflows/update-libraries.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025 Dell Inc., or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Reusable workflow to perform updates of Dell client libraries 10 | name: Dell Libraries Release Update 11 | on: # yamllint disable-line rule:truthy 12 | workflow_dispatch: 13 | repository_dispatch: 14 | types: [latest-released-libraries] 15 | 16 | jobs: 17 | package-update: 18 | uses: dell/common-github-actions/.github/workflows/update-libraries.yml@main 19 | name: Dell Libraries Update 20 | secrets: inherit 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | *.html 14 | 15 | # reports 16 | *.csv 17 | 18 | *.swp 19 | helm/myvalues.yaml 20 | semver.mk 21 | goisilon 22 | gocsi 23 | .idea 24 | -------------------------------------------------------------------------------- /.trivyignore: -------------------------------------------------------------------------------- 1 | CVE-2019-1010022 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright © 2021-2025 Dell Inc. or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License 12 | 13 | # some arguments that must be supplied 14 | ARG GOPROXY 15 | ARG GOIMAGE 16 | ARG BASEIMAGE 17 | 18 | # Stage to build the driver 19 | FROM $GOIMAGE as builder 20 | ARG GOPROXY 21 | RUN mkdir -p /go/src 22 | COPY ./ /go/src/ 23 | WORKDIR /go/src/ 24 | RUN CGO_ENABLED=0 \ 25 | make build 26 | 27 | # Stage to build the driver image 28 | FROM $BASEIMAGE AS final 29 | 30 | # copy in the driver 31 | COPY --from=builder /go/src/csi-isilon / 32 | ENTRYPOINT ["/csi-isilon"] 33 | 34 | LABEL vendor="Dell Technologies" \ 35 | maintainer="Dell Technologies" \ 36 | name="csi-isilon" \ 37 | summary="CSI Driver for Dell EMC PowerScale" \ 38 | description="CSI Driver for provisioning persistent storage from Dell EMC PowerScale" \ 39 | release="1.14.0" \ 40 | version="2.14.0" \ 41 | license="Apache-2.0" 42 | 43 | COPY ./licenses /licenses 44 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Copyright © 2019-2021 Dell Inc. or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License 12 | 13 | 14 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 15 | # for detailed Gopkg.toml documentation. 16 | # 17 | # Refer to https://github.com/toml-lang/toml for detailed TOML docs. 18 | 19 | [prune] 20 | non-go = true 21 | go-tests = true 22 | unused-packages = true 23 | 24 | [[constraint]] 25 | name = "github.com/dell/gocsi" 26 | version = "1.2.3" 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # default target 2 | all: help 3 | 4 | # include an overrides file, which sets up default values and allows user overrides 5 | include overrides.mk 6 | 7 | # Help target, prints usefule information 8 | help: 9 | @echo 10 | @echo "The following targets are commonly used:" 11 | @echo 12 | @echo "build - Builds the code locally" 13 | @echo "clean - Cleans the local build" 14 | @echo "docker - Builds the code within a golang container and then creates the driver image" 15 | @echo "integration-test - Runs the integration tests. Requires access to an array" 16 | @echo "push - Pushes the built container to a target registry" 17 | @echo "unit-test - Runs the unit tests" 18 | @echo 19 | @make -s overrides-help 20 | 21 | # Clean the build 22 | clean: 23 | rm -f core/core_generated.go 24 | rm -f semver.mk 25 | go clean 26 | 27 | # Dependencies 28 | dependencies: 29 | go generate 30 | go run core/semver/semver.go -f mk >semver.mk 31 | 32 | format: 33 | @gofmt -w -s . 34 | 35 | # Build the driver locally 36 | build: dependencies 37 | GOOS=linux CGO_ENABLED=0 go build 38 | 39 | # Generates the docker container (but does not push) 40 | podman-build: 41 | make -f docker.mk podman-build 42 | 43 | # Generates the docker container without using cache(but does not push) 44 | podman-build-no-cache: 45 | make -f docker.mk podman-build-no-cache 46 | 47 | docker: build 48 | make -f docker.mk docker 49 | 50 | # Pushes container to the repository 51 | podman-build-image-push: podman-build 52 | make -f docker.mk podman-build-image-push 53 | 54 | dev-build-image-push: dev-build 55 | make -f docker.mk docker-build-image-push 56 | 57 | # Windows or Linux; requires no hardware 58 | unit-test: 59 | ( cd service; go clean -cache; go test -v -coverprofile=c.out ./... ) 60 | 61 | coverage: 62 | cd service; go tool cover -html=c.out -o coverage.html 63 | 64 | # Linux only; populate env.sh with the hardware parameters 65 | integration-test: 66 | ( cd test/integration; sh run.sh ) 67 | 68 | version: 69 | go generate 70 | go run core/semver/semver.go -f mk >semver.mk 71 | make -f docker.mk version 72 | 73 | gosec: 74 | gosec -quiet -log gosec.log -out=gosecresults.csv -fmt=csv ./... 75 | 76 | .PHONY: actions action-help 77 | actions: ## Run all GitHub Action checks that run on a pull request creation 78 | @echo "Running all GitHub Action checks for pull request events..." 79 | @act -l | grep -v ^Stage | grep pull_request | grep -v image_security_scan | awk '{print $$2}' | while read WF; do \ 80 | echo "Running workflow: $${WF}"; \ 81 | act pull_request --no-cache-server --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest --job "$${WF}"; \ 82 | done 83 | 84 | action-help: ## Echo instructions to run one specific workflow locally 85 | @echo "GitHub Workflows can be run locally with the following command:" 86 | @echo "act pull_request --no-cache-server --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest --job " 87 | @echo "" 88 | @echo "Where '' is a Job ID returned by the command:" 89 | @echo "act -l" 90 | @echo "" 91 | @echo "NOTE: if act is not installed, it can be downloaded from https://github.com/nektos/act" 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSI Driver for Dell EMC PowerScale 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/dell/csi-isilon?style=flat-square)](https://goreportcard.com/report/github.com/dell/csi-isilon) 4 | [![License](https://img.shields.io/github/license/dell/csi-isilon?style=flat-square&color=blue&label=License)](https://github.com/dell/csi-isilon/blob/main/LICENSE) 5 | [![Docker](https://img.shields.io/docker/pulls/dellemc/csi-isilon.svg?logo=docker&style=flat-square&label=Pulls)](https://hub.docker.com/r/dellemc/csi-isilon) 6 | [![Last Release](https://img.shields.io/github/v/release/dell/csi-isilon?label=Latest&style=flat-square&logo=go)](https://github.com/dell/csi-isilon/releases) 7 | 8 | **Repository for CSI Driver for Dell EMC PowerScale** 9 | 10 | ## Description 11 | 12 | CSI Driver for PowerScale is part of the [CSM (Container Storage Modules)](https://github.com/dell/csm) open-source suite of Kubernetes storage enablers for Dell Technology (Dell) products. CSI Driver for PowerScale is a Container Storage Interface (CSI) driver that provides support for provisioning persistent storage using Dell PowerScale storage array. 13 | 14 | This project may be compiled as a stand-alone binary using Golang that, when run, provides a valid CSI endpoint. It also can be used as a precompiled container image. 15 | 16 | ## Table of Contents 17 | 18 | * [Code of Conduct](https://github.com/dell/csm/blob/main/docs/CODE_OF_CONDUCT.md) 19 | * [Maintainer Guide](https://github.com/dell/csm/blob/main/docs/MAINTAINER_GUIDE.md) 20 | * [Committer Guide](https://github.com/dell/csm/blob/main/docs/COMMITTER_GUIDE.md) 21 | * [Contributing Guide](https://github.com/dell/csm/blob/main/docs/CONTRIBUTING.md) 22 | * [List of Adopters](https://github.com/dell/csm/blob/main/docs/ADOPTERS.md) 23 | * [Support](#support) 24 | * [Security](https://github.com/dell/csm/blob/main/docs/SECURITY.md) 25 | * [Building](#building) 26 | * [Runtime Dependecies](#runtime-dependencies) 27 | * [Documentation](#documentation) 28 | 29 | ## Support 30 | For any issues, questions or feedback, please contact [Dell support](https://www.dell.com/support/incidents-online/en-us/contactus/product/container-storage-modules). 31 | 32 | ## Building 33 | 34 | This project is a Go module (see golang.org Module information for explanation). 35 | The dependencies for this project are in the go.mod file. 36 | 37 | To build the source, execute `make clean build`. 38 | 39 | To run unit tests, execute `make unit-test`. 40 | 41 | To build a podman based image, execute `make podman-build`. 42 | 43 | You can run an integration test on a Linux system by populating the env files at `test/integration/` with values for your Dell EMC PowerScale systems and then run "`make integration-test`". 44 | 45 | ## Runtime Dependencies 46 | 47 | Both the Controller and the Node portions of the driver can only be run on nodes which have network connectivity to a “`PowerScale Cluster`” (which is used by the driver). 48 | 49 | ## Documentation 50 | 51 | For more detailed information on the driver, please refer to [Container Storage Modules documentation](https://dell.github.io/csm-docs/). 52 | -------------------------------------------------------------------------------- /common/constants/consts.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | import "github.com/sirupsen/logrus" 4 | 5 | /* 6 | Copyright (c) 2019-2022 Dell Inc, or its subsidiaries. 7 | 8 | Licensed under the Apache License, Version 2.0 (the "License"); 9 | you may not use this file except in compliance with the License. 10 | You may obtain a copy of the License at 11 | 12 | http://www.apache.org/licenses/LICENSE-2.0 13 | 14 | Unless required by applicable law or agreed to in writing, software 15 | distributed under the License is distributed on an "AS IS" BASIS, 16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | See the License for the specific language governing permissions and 18 | limitations under the License. 19 | */ 20 | 21 | const ( 22 | // PluginName is the name of the CSI plug-in. 23 | PluginName = "csi-isilon.dellemc.com" 24 | 25 | // DefaultAccessZone is "System" 26 | DefaultAccessZone = "System" 27 | // ModeNode is csi driver's "mode "deployment mode 28 | ModeNode = "node" 29 | // ModeController is csi driver's "controller "deployment mode 30 | ModeController = "controller" 31 | 32 | // DefaultVolumeSizeInBytes is default volume sgolang/protobuf/blob/master/ptypesize to create on an Isilon 33 | // cluster when no size is given, expressed in bytes 34 | DefaultVolumeSizeInBytes = 3 * BytesInGiB 35 | 36 | // BytesInGiB is the number of bytes in a gigabyte 37 | BytesInGiB = 1024 * 1024 * 1024 38 | // TRUE constant 39 | TRUE = "TRUE" 40 | // FALSE constant 41 | FALSE = "FALSE" 42 | 43 | // DefaultPortNumber is the port number in default to set the HTTPS port number of the Isilon OneFS API server 44 | DefaultPortNumber = "8080" 45 | 46 | // DefaultIsiPath is the default isiPath which will be used if there's 47 | // no proper isiPath value set in neither storageclass.yaml nor values.yaml 48 | DefaultIsiPath = "/ifs" 49 | 50 | // DefaultIsiVolumePathPermissions are the default permissions for volume directory path 51 | DefaultIsiVolumePathPermissions = "0777" 52 | 53 | // MaxIsiConnRetries is the max number of retries to validate connection to PowerScale Array 54 | MaxIsiConnRetries = 10 55 | 56 | // KubeConfig of kubernetes cluster 57 | KubeConfig = "KUBECONFIG" 58 | 59 | // IsilonConfigFile isilon-creds file with credential info of isilon clusters 60 | IsilonConfigFile = "/isilon-configs/config" 61 | 62 | // DefaultLogLevel for csi logs 63 | DefaultLogLevel = logrus.DebugLevel 64 | 65 | // ParamCSILogLevel csi driver log level 66 | ParamCSILogLevel = "CSI_LOG_LEVEL" 67 | 68 | // DefaultPodmonAPIPortNumber is the port number in default to expose internal health APIs 69 | DefaultPodmonAPIPortNumber = "8083" 70 | 71 | // DefaultPodmonPollRate is the default polling frequency to check for array connectivity 72 | DefaultPodmonPollRate = 60 73 | 74 | // DefaultCsiVolumePrefix defines the default volume prefix used for the names of PersistentVolumes created 75 | DefaultCsiVolumePrefix = "csivol" 76 | ) 77 | -------------------------------------------------------------------------------- /common/constants/envvars.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | /* 4 | Copyright (c) 2019 Dell Inc, or its subsidiaries. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | const ( 20 | 21 | // EnvCSIEndpoint is the name of the unix domain socket that the csi driver is listening on 22 | EnvCSIEndpoint = "CSI_ENDPOINT" 23 | 24 | // EnvPort is the name of the enviroment variable used to set the 25 | // HTTPS port number of the Isilon OneFS API server 26 | EnvPort = "X_CSI_ISI_PORT" 27 | 28 | // EnvSkipCertificateValidation is the name of the enviroment variable used to specify 29 | // that the Isilon OneFS API server's certificate chain and host name should not 30 | // be verified 31 | EnvSkipCertificateValidation = "X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION" 32 | 33 | // EnvIsiAuthType sets the default Authentication method as Basic Authentication 34 | EnvIsiAuthType = "X_CSI_ISI_AUTH_TYPE" 35 | 36 | // EnvPath is the root path under which all the volumes (directories) will be provisioned, e.g. /ifs/engineering 37 | EnvPath = "X_CSI_ISI_PATH" 38 | 39 | // EnvIsiVolumePathPermissions is the default permissions for volume directory path, e.g. 0777 40 | EnvIsiVolumePathPermissions = "X_CSI_ISI_VOLUME_PATH_PERMISSIONS" 41 | 42 | // EnvIgnoreUnresolvableHosts exhibits default OneFS behavior of failing to add export if any of existing hosts from 43 | // same export is unresolvable 44 | EnvIgnoreUnresolvableHosts = "X_CSI_ISI_IGNORE_UNRESOLVABLE_HOSTS" 45 | 46 | // EnvAutoProbe is the name of the environment variable used to specify 47 | // that the controller service should automatically probe itself if it 48 | // receives incoming requests before having been probed, in direct 49 | // violation of the CSI spec 50 | EnvAutoProbe = "X_CSI_ISI_AUTOPROBE" 51 | 52 | // EnvGOCSIDebug indicates whether to print REQUESTs and RESPONSEs of all CSI method calls(from gocsi) 53 | EnvGOCSIDebug = "X_CSI_DEBUG" 54 | 55 | // EnvVerbose indicates whether the driver should log OneFS REST API response body content 56 | EnvVerbose = "X_CSI_VERBOSE" 57 | 58 | // EnvQuotaEnabled is the boolean flag that indicates whether the provisioner should attempt to set (later unset) quota on a newly provisioned volume 59 | EnvQuotaEnabled = "X_CSI_ISI_QUOTA_ENABLED" 60 | 61 | // EnvAccessZone is the name of the access zone a volume can be created in, e.g. "System" 62 | EnvAccessZone = "X_CSI_ISI_ACCESS_ZONE" 63 | 64 | // EnvNoProbeOnStart indicates whether a probe should be attempted upon start 65 | EnvNoProbeOnStart = "X_CSI_ISI_NO_PROBE_ON_START" 66 | 67 | // EnvNodeName is the name of a k8s node 68 | EnvNodeName = "X_CSI_NODE_NAME" 69 | 70 | // EnvNodeIP is the ip address of a k8s node 71 | EnvNodeIP = "X_CSI_NODE_IP" 72 | 73 | // EnvCustomTopologyEnabled indicates if custom topology has to be used by CSI Driver 74 | EnvCustomTopologyEnabled = "X_CSI_CUSTOM_TOPOLOGY_ENABLED" 75 | 76 | // EnvKubeConfigPath indicates kubernetes configuration that has to be used by CSI Driver 77 | EnvKubeConfigPath = "KUBECONFIG" 78 | 79 | // EnvAllowedNetworks indicates list of networks on which NFS traffic is allowed 80 | EnvAllowedNetworks = "X_CSI_ALLOWED_NETWORKS" 81 | 82 | // EnvIsilonConfigFile specifies the filepath containing Isilon cluster's config details 83 | EnvIsilonConfigFile = "X_CSI_ISI_CONFIG_PATH" 84 | 85 | // EnvMaxVolumesPerNode specifies maximum number of volumes that controller can publish to the node. 86 | EnvMaxVolumesPerNode = "X_CSI_MAX_VOLUMES_PER_NODE" 87 | 88 | // EnvIsHealthMonitorEnabled specifies if health monitor is enabled. 89 | EnvIsHealthMonitorEnabled = "X_CSI_HEALTH_MONITOR_ENABLED" 90 | 91 | // EnvReplicationContextPrefix enables sidecars to read required information from volume context 92 | EnvReplicationContextPrefix = "X_CSI_REPLICATION_CONTEXT_PREFIX" 93 | 94 | // EnvReplicationPrefix is used as a prefix to find out if replication is enabled 95 | EnvReplicationPrefix = "X_CSI_REPLICATION_PREFIX" // #nosec G101 96 | 97 | // EnvPodmonEnabled indicates that podmon is enabled 98 | EnvPodmonEnabled = "X_CSI_PODMON_ENABLED" 99 | 100 | // EnvPodmonAPIPORT indicates the port to be used for exposing podmon API health 101 | EnvPodmonAPIPORT = "X_CSI_PODMON_API_PORT" 102 | 103 | // EnvPodmonArrayConnectivityPollRate indicates the polling frequency to check array connectivity 104 | EnvPodmonArrayConnectivityPollRate = "X_CSI_PODMON_ARRAY_CONNECTIVITY_POLL_RATE" 105 | 106 | // EnvMetadataRetrieverEndpoint specifies the endpoint address for csi-metadata-retriever sidecar 107 | EnvMetadataRetrieverEndpoint = "CSI_RETRIEVER_ENDPOINT" 108 | 109 | // EnvCsiVolPrefix specifies the volume prefix used for the names of PersistentVolumes created 110 | EnvCsiVolPrefix = "X_CSI_VOL_PREFIX" 111 | ) 112 | -------------------------------------------------------------------------------- /common/k8sutils/k8sutils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Dell Inc, or its subsidiaries. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package k8sutils 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "os" 23 | "time" 24 | 25 | "github.com/dell/gofsutil" 26 | "github.com/kubernetes-csi/csi-lib-utils/leaderelection" 27 | "google.golang.org/grpc/codes" 28 | "google.golang.org/grpc/status" 29 | "k8s.io/client-go/kubernetes" 30 | "k8s.io/client-go/rest" 31 | "k8s.io/client-go/tools/clientcmd" 32 | ) 33 | 34 | var ( 35 | buildConfigFromFlags = clientcmd.BuildConfigFromFlags 36 | newForConfig = kubernetes.NewForConfig 37 | inClusterConfig = rest.InClusterConfig 38 | ) 39 | 40 | var fsInfo = func(ctx context.Context, path string) (int64, int64, int64, int64, int64, int64, error) { 41 | return gofsutil.FsInfo(ctx, path) 42 | } 43 | 44 | type leaderElection interface { 45 | Run() error 46 | WithNamespace(namespace string) 47 | } 48 | 49 | // CreateKubeClientSet - Returns kubeclient set 50 | func CreateKubeClientSet(kubeconfig string) (*kubernetes.Clientset, error) { 51 | var clientset *kubernetes.Clientset 52 | if kubeconfig != "" { 53 | // use the current context in kubeconfig 54 | config, err := buildConfigFromFlags("", kubeconfig) 55 | if err != nil { 56 | return nil, err 57 | } 58 | // create the clientset 59 | clientset, err = newForConfig(config) 60 | if err != nil { 61 | return nil, err 62 | } 63 | } else { 64 | config, err := inClusterConfig() 65 | if err != nil { 66 | return nil, err 67 | } 68 | // creates the clientset 69 | clientset, err = newForConfig(config) 70 | if err != nil { 71 | return nil, err 72 | } 73 | } 74 | return clientset, nil 75 | } 76 | 77 | // LeaderElection - Initialize leader election 78 | func LeaderElection(clientset *kubernetes.Clientset, lockName string, namespace string, 79 | leaderElectionRenewDeadline, leaderElectionLeaseDuration, leaderElectionRetryPeriod time.Duration, runFunc func(ctx context.Context), 80 | ) { 81 | le := leaderelection.NewLeaderElection(clientset, lockName, runFunc) 82 | le.WithNamespace(namespace) 83 | le.WithLeaseDuration(leaderElectionLeaseDuration) 84 | le.WithRenewDeadline(leaderElectionRenewDeadline) 85 | le.WithRetryPeriod(leaderElectionRetryPeriod) 86 | if err := le.Run(); err != nil { 87 | _, _ = fmt.Fprintf(os.Stderr, "failed to initialize leader election: %v", err) 88 | os.Exit(1) 89 | } 90 | } 91 | 92 | // GetStats - Returns the stats for the volume mounted on given volume path 93 | func GetStats(ctx context.Context, volumePath string) (int64, int64, int64, int64, int64, int64, error) { 94 | availableBytes, totalBytes, usedBytes, totalInodes, freeInodes, usedInodes, err := fsInfo(ctx, volumePath) 95 | if err != nil { 96 | return 0, 0, 0, 0, 0, 0, status.Error(codes.Internal, fmt.Sprintf( 97 | "failed to get volume stats: %s", err)) 98 | } 99 | return availableBytes, totalBytes, usedBytes, totalInodes, freeInodes, usedInodes, err 100 | } 101 | -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | core_generated.go 2 | -------------------------------------------------------------------------------- /core/core.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | /* 4 | Copyright (c) 2019 Dell Inc, or its subsidiaries. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | //go:generate go run semver/semver.go -f semver.tpl -o core_generated.go 19 | 20 | import "time" 21 | 22 | var ( 23 | // SemVer is the semantic version. 24 | SemVer = "unknown" 25 | 26 | // CommitSha7 is the short version of the commit hash from which 27 | // this program was built. 28 | CommitSha7 string 29 | 30 | // CommitSha32 is the long version of the commit hash from which 31 | // this program was built. 32 | CommitSha32 string 33 | 34 | // CommitTime is the commit timestamp of the commit from which 35 | // this program was built. 36 | CommitTime time.Time 37 | ) 38 | -------------------------------------------------------------------------------- /core/semver.tpl: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "time" 4 | 5 | func init() { 6 | SemVer = "{{.SemVer}}" 7 | CommitSha7 = "{{.Sha7}}" 8 | CommitSha32 = "{{.Sha32}}" 9 | CommitTime = time.Unix({{.Epoch}}, 0) 10 | } 11 | -------------------------------------------------------------------------------- /csi-utils/csiutils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021-2025 Dell Inc, or its subsidiaries. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package csiutils 18 | 19 | import ( 20 | "fmt" 21 | "net" 22 | 23 | "github.com/dell/csi-isilon/v2/common/utils" 24 | ) 25 | 26 | var interfaceAddrs = func() ([]net.Addr, error) { 27 | return net.InterfaceAddrs() 28 | } 29 | 30 | var parseCIDR = func(s string) (net.IP, *net.IPNet, error) { 31 | return net.ParseCIDR(s) 32 | } 33 | 34 | // GetNFSClientIP is used to fetch IP address from networks on which NFS traffic is allowed 35 | func GetNFSClientIP(allowedNetworks []string) (string, error) { 36 | var nodeIP string 37 | log := utils.GetLogger() 38 | addrs, err := interfaceAddrs() 39 | if err != nil { 40 | log.Errorf("Encountered error while fetching system IP addresses: %+v\n", err.Error()) 41 | return "", err 42 | } 43 | 44 | // Populate map to optimize the algorithm for O(n) 45 | networks := make(map[string]bool) 46 | for _, cnet := range allowedNetworks { 47 | networks[cnet] = false 48 | } 49 | 50 | for _, a := range addrs { 51 | switch v := a.(type) { 52 | case *net.IPNet: 53 | if v.IP.To4() != nil { 54 | ip, cnet, err := parseCIDR(a.String()) 55 | log.Debugf("IP address: %s and Network: %s", ip, cnet) 56 | if err != nil { 57 | log.Errorf("Encountered error while parsing IP address %v", a) 58 | continue 59 | } 60 | 61 | if _, ok := networks[cnet.String()]; ok { 62 | log.Infof("Found IP address: %s", ip) 63 | nodeIP = ip.String() 64 | return nodeIP, nil 65 | } 66 | } 67 | } 68 | } 69 | 70 | // If a valid IP address matching allowedNetworks is not found return error 71 | if nodeIP == "" { 72 | return "", fmt.Errorf("no valid IP address found matching against allowedNetworks %v", allowedNetworks) 73 | } 74 | 75 | return nodeIP, nil 76 | } 77 | -------------------------------------------------------------------------------- /csi-utils/csiutils_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2025 Dell Inc, or its subsidiaries. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package csiutils 18 | 19 | import ( 20 | "errors" 21 | "net" 22 | "testing" 23 | ) 24 | 25 | func TestGetNFSClientIP(t *testing.T) { 26 | defaulInterfaceAddrsFn := interfaceAddrs 27 | defaultParseCIDRFn := parseCIDR 28 | 29 | afterEach := func() { 30 | interfaceAddrs = defaulInterfaceAddrsFn 31 | parseCIDR = defaultParseCIDRFn 32 | } 33 | 34 | tests := []struct { 35 | name string 36 | allowedNetworks []string 37 | interfaceAddrsFn func() ([]net.Addr, error) 38 | parseCIDRFn func(s string) (net.IP, *net.IPNet, error) 39 | expectError bool 40 | }{ 41 | { 42 | name: "Valid_Network", 43 | allowedNetworks: []string{ 44 | "10.247.96.0/21", 45 | "10.244.0.0/24", 46 | }, 47 | interfaceAddrsFn: func() ([]net.Addr, error) { 48 | return []net.Addr{ 49 | &net.IPNet{ 50 | IP: net.IPv4(10, 244, 0, 0), 51 | Mask: net.CIDRMask(24, 32), 52 | }, 53 | }, nil 54 | }, 55 | expectError: false, 56 | }, 57 | { 58 | name: "No_Matching_Network", 59 | allowedNetworks: []string{ 60 | "192.168.1.0/24", // No matching IP in this range 61 | }, 62 | expectError: true, 63 | }, 64 | { 65 | name: "Invalid_CIDR_Format", 66 | allowedNetworks: []string{ 67 | "10.247.96.999/21", // Invalid CIDR 68 | }, 69 | expectError: true, 70 | }, 71 | { 72 | name: "Invalid_CIDR_Format_Parsing_Error", 73 | allowedNetworks: []string{ 74 | "invalid_subnet", // This will trigger net.ParseCIDR() failure 75 | }, 76 | expectError: true, 77 | }, 78 | { 79 | name: "Empty_Network_List", 80 | allowedNetworks: []string{}, 81 | expectError: true, 82 | }, 83 | { 84 | name: "Error_getting_network_interfaces", 85 | allowedNetworks: []string{}, 86 | interfaceAddrsFn: func() ([]net.Addr, error) { 87 | return nil, errors.New("error") 88 | }, 89 | expectError: true, 90 | }, 91 | { 92 | name: "Error_parsing_cidr", 93 | allowedNetworks: []string{}, 94 | parseCIDRFn: func(_ string) (net.IP, *net.IPNet, error) { 95 | return nil, nil, errors.New("error") 96 | }, 97 | expectError: true, 98 | }, 99 | } 100 | 101 | for _, tt := range tests { 102 | t.Run(tt.name, func(t *testing.T) { 103 | if tt.interfaceAddrsFn != nil { 104 | interfaceAddrs = tt.interfaceAddrsFn 105 | } 106 | if tt.parseCIDRFn != nil { 107 | parseCIDR = tt.parseCIDRFn 108 | } 109 | defer afterEach() 110 | 111 | ip, err := GetNFSClientIP(tt.allowedNetworks) 112 | 113 | if tt.expectError { 114 | if err == nil { 115 | t.Fatalf("Expected error but got none") 116 | } 117 | t.Logf("Received expected error: %v", err) 118 | } else { 119 | if err != nil { 120 | t.Fatalf("Unexpected error: %v", err) 121 | } 122 | t.Logf("Detected IP: %s", ip) 123 | } 124 | }) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /dell-csi-helm-installer/.gitignore: -------------------------------------------------------------------------------- 1 | images.manifest 2 | images.tar 3 | -------------------------------------------------------------------------------- /dell-csi-helm-installer/csi-uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright © 2021 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | DRIVERDIR="${SCRIPTDIR}/../helm-charts/charts" 16 | PROG="${0}" 17 | DRIVER="csi-isilon" 18 | # export the name of the debug log, so child processes will see it 19 | export DEBUGLOG="${SCRIPTDIR}/uninstall-debug.log" 20 | 21 | declare -a VALIDDRIVERS 22 | 23 | source "$SCRIPTDIR"/common.sh 24 | 25 | if [ -f "${DEBUGLOG}" ]; then 26 | rm -f "${DEBUGLOG}" 27 | fi 28 | 29 | # 30 | # usage will print command execution help and then exit 31 | function usage() { 32 | decho "Help for $PROG" 33 | decho 34 | decho "Usage: $PROG options..." 35 | decho "Options:" 36 | decho " Required" 37 | decho " --namespace[=] Kubernetes namespace to uninstall the CSI driver from" 38 | 39 | decho " Optional" 40 | decho " --release[=] Name to register with helm, default value will match the driver name" 41 | decho " -h Help" 42 | decho 43 | 44 | exit 0 45 | } 46 | 47 | 48 | 49 | # 50 | # validate_params will validate the parameters passed in 51 | function validate_params() { 52 | # make sure the driver was specified 53 | if [ -z "${DRIVER}" ]; then 54 | decho "No driver specified" 55 | exit 1 56 | fi 57 | 58 | # the namespace is required 59 | if [ -z "${NAMESPACE}" ]; then 60 | decho "No namespace specified" 61 | usage 62 | exit 1 63 | fi 64 | } 65 | 66 | 67 | # check_for_driver will see if the driver is installed within the namespace provided 68 | function check_for_driver() { 69 | NUM=$(run_command helm list --namespace "${NAMESPACE}" | grep "^${RELEASE}\b" | wc -l) 70 | if [ "${NUM}" == "0" ]; then 71 | log uninstall_error "The CSI Driver is not installed." 72 | exit 1 73 | fi 74 | } 75 | 76 | while getopts ":h-:" optchar; do 77 | case "${optchar}" in 78 | -) 79 | case "${OPTARG}" in 80 | # NAMESPACE 81 | namespace) 82 | NAMESPACE="${!OPTIND}" 83 | OPTIND=$((OPTIND + 1)) 84 | ;; 85 | namespace=*) 86 | NAMESPACE=${OPTARG#*=} 87 | ;; 88 | # RELEASE 89 | release) 90 | RELEASE="${!OPTIND}" 91 | OPTIND=$((OPTIND + 1)) 92 | ;; 93 | release=*) 94 | RELEASE=${OPTARG#*=} 95 | ;; 96 | *) 97 | decho "Unknown option --${OPTARG}" 98 | decho "For help, run $PROG -h" 99 | exit 1 100 | ;; 101 | esac 102 | ;; 103 | h) 104 | usage 105 | ;; 106 | *) 107 | decho "Unknown option -${OPTARG}" 108 | decho "For help, run $PROG -h" 109 | exit 1 110 | ;; 111 | esac 112 | done 113 | 114 | # by default the NAME of the helm release of the driver is the same as the driver name 115 | RELEASE=$(get_release_name "${DRIVER}") 116 | 117 | # validate the parameters passed in 118 | validate_params 119 | 120 | check_for_driver 121 | run_command helm delete -n "${NAMESPACE}" "${RELEASE}" 122 | if [ $? -ne 0 ]; then 123 | decho "Removal of the CSI Driver was unsuccessful" 124 | exit 1 125 | fi 126 | 127 | decho "Removal of the CSI Driver is in progress." 128 | decho "It may take a few minutes for all pods to terminate." 129 | 130 | -------------------------------------------------------------------------------- /dell-csi-helm-installer/verify-csi-isilon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright © 2020-2025 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # 15 | # verify-csi-isilon method 16 | function verify-csi-isilon() { 17 | verify_k8s_versions "1.31" "1.33" 18 | verify_openshift_versions "4.18" "4.19" 19 | verify_namespace "${NS}" 20 | verify_required_secrets "${RELEASE}-creds" 21 | verify_optional_secrets "${RELEASE}-certs" 22 | verify_alpha_snap_resources 23 | verify_snap_requirements 24 | verify_helm_3 25 | verify_helm_values_version "${DRIVER_VERSION}" 26 | verify_authorization_proxy_server 27 | } 28 | -------------------------------------------------------------------------------- /docker.mk: -------------------------------------------------------------------------------- 1 | # docker makefile, included from Makefile, will build/push images with docker or podman 2 | 3 | docker: download-csm-common 4 | $(eval include csm-common.mk) 5 | @echo "Building docker image: $(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" 6 | docker build --pull -t "$(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" --build-arg GOPROXY=$(GOPROXY) --build-arg BASEIMAGE=$(CSM_BASEIMAGE) --build-arg GOIMAGE=$(DEFAULT_GOIMAGE) . 7 | 8 | docker-push: 9 | @echo "Pushing: $(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" 10 | docker push "$(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" 11 | 12 | podman-build: download-csm-common 13 | $(eval include csm-common.mk) 14 | @echo "Building: $(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" 15 | @echo "Using Golang Image $(DEFAULT_GOIMAGE)" 16 | $(BUILDER) build --pull $(NOCACHE) -t "$(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" --build-arg GOPROXY=$(GOPROXY) --build-arg BASEIMAGE=$(CSM_BASEIMAGE) --build-arg GOIMAGE=$(DEFAULT_GOIMAGE) . 17 | 18 | podman-build-no-cache: 19 | @echo "Building with --no-cache ..." 20 | @make podman-build NOCACHE=--no-cache 21 | 22 | podman-build-image-push: 23 | @echo "Pushing: $(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" 24 | $(BUILDER) push "$(REGISTRY)/$(IMAGENAME):$(IMAGETAG)" 25 | 26 | version: 27 | @echo "MAJOR $(MAJOR) MINOR $(MINOR) PATCH $(PATCH) BUILD ${BUILD} TYPE ${TYPE} RELNOTE $(RELNOTE) SEMVER $(SEMVER)" 28 | @echo "Target Version: $(VERSION)" 29 | 30 | download-csm-common: 31 | curl -O -L https://raw.githubusercontent.com/dell/csm/main/config/csm-common.mk -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dell/csi-isilon/v2 2 | 3 | go 1.24.0 4 | 5 | toolchain go1.24.3 6 | 7 | require ( 8 | github.com/Showmax/go-fqdn v1.0.0 9 | github.com/akutz/gosync v0.1.0 10 | github.com/akutz/gournal v0.5.0 11 | github.com/container-storage-interface/spec v1.6.0 12 | github.com/cucumber/godog v0.15.0 13 | github.com/dell/csi-metadata-retriever v1.11.1-0.20250529172548-aa16d68dc33f 14 | github.com/dell/dell-csi-extensions/common v1.8.1-0.20250514175456-5ddd200c5e5c 15 | github.com/dell/dell-csi-extensions/podmon v1.8.0 16 | github.com/dell/dell-csi-extensions/replication v1.11.0 17 | github.com/dell/dell-csi-extensions/volumeGroupSnapshot v1.8.1 18 | github.com/dell/gocsi v1.14.0 19 | github.com/dell/gofsutil v1.19.0 20 | github.com/dell/goisilon v1.19.0 21 | github.com/fsnotify/fsnotify v1.9.0 22 | github.com/google/uuid v1.6.0 23 | github.com/gorilla/mux v1.8.1 24 | github.com/kubernetes-csi/csi-lib-utils v0.11.0 25 | github.com/sirupsen/logrus v1.9.3 26 | github.com/spf13/viper v1.20.0 27 | github.com/stretchr/testify v1.10.0 28 | golang.org/x/net v0.40.0 29 | google.golang.org/grpc v1.72.0 30 | google.golang.org/protobuf v1.36.5 31 | gopkg.in/yaml.v3 v3.0.1 32 | k8s.io/api v0.33.0 33 | k8s.io/apimachinery v0.33.0 34 | k8s.io/client-go v0.33.0 35 | ) 36 | 37 | require ( 38 | github.com/PuerkitoBio/goquery v1.10.2 // indirect 39 | github.com/andybalholm/cascadia v1.3.3 // indirect 40 | github.com/beorn7/perks v1.0.1 // indirect 41 | github.com/blang/semver/v4 v4.0.0 // indirect 42 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 43 | github.com/coreos/go-semver v0.3.1 // indirect 44 | github.com/coreos/go-systemd/v22 v22.5.0 // indirect 45 | github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect 46 | github.com/cucumber/messages/go/v21 v21.0.1 // indirect 47 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 48 | github.com/emicklei/go-restful/v3 v3.12.1 // indirect 49 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 50 | github.com/go-logr/logr v1.4.2 // indirect 51 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 52 | github.com/go-openapi/jsonreference v0.21.0 // indirect 53 | github.com/go-openapi/swag v0.23.0 // indirect 54 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 55 | github.com/gofrs/uuid v4.4.0+incompatible // indirect 56 | github.com/gogo/protobuf v1.3.2 // indirect 57 | github.com/golang/protobuf v1.5.4 // indirect 58 | github.com/google/gnostic-models v0.6.9 // indirect 59 | github.com/google/go-cmp v0.7.0 // indirect 60 | github.com/hashicorp/go-immutable-radix v1.3.1 // indirect 61 | github.com/hashicorp/go-memdb v1.3.4 // indirect 62 | github.com/hashicorp/golang-lru v1.0.2 // indirect 63 | github.com/josharian/intern v1.0.0 // indirect 64 | github.com/json-iterator/go v1.1.12 // indirect 65 | github.com/klauspost/compress v1.17.11 // indirect 66 | github.com/mailru/easyjson v0.9.0 // indirect 67 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 68 | github.com/modern-go/reflect2 v1.0.2 // indirect 69 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 70 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect 71 | github.com/pkg/errors v0.9.1 // indirect 72 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 73 | github.com/prometheus/client_golang v1.20.5 // indirect 74 | github.com/prometheus/client_model v0.6.1 // indirect 75 | github.com/prometheus/common v0.62.0 // indirect 76 | github.com/prometheus/procfs v0.15.1 // indirect 77 | github.com/sagikazarmark/locafero v0.7.0 // indirect 78 | github.com/sourcegraph/conc v0.3.0 // indirect 79 | github.com/spf13/afero v1.12.0 // indirect 80 | github.com/spf13/cast v1.7.1 // indirect 81 | github.com/spf13/pflag v1.0.6 // indirect 82 | github.com/stretchr/objx v0.5.2 // indirect 83 | github.com/subosito/gotenv v1.6.0 // indirect 84 | github.com/x448/float16 v0.8.4 // indirect 85 | go.etcd.io/etcd/api/v3 v3.5.18 // indirect 86 | go.etcd.io/etcd/client/pkg/v3 v3.5.18 // indirect 87 | go.etcd.io/etcd/client/v3 v3.5.18 // indirect 88 | go.opentelemetry.io/otel v1.34.0 // indirect 89 | go.opentelemetry.io/otel/trace v1.34.0 // indirect 90 | go.uber.org/multierr v1.11.0 // indirect 91 | go.uber.org/zap v1.27.0 // indirect 92 | golang.org/x/oauth2 v0.27.0 // indirect 93 | golang.org/x/sys v0.33.0 // indirect 94 | golang.org/x/term v0.32.0 // indirect 95 | golang.org/x/text v0.25.0 // indirect 96 | golang.org/x/time v0.9.0 // indirect 97 | google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect 98 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 99 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 100 | gopkg.in/inf.v0 v0.9.1 // indirect 101 | k8s.io/component-base v0.32.1 // indirect 102 | k8s.io/klog/v2 v2.130.1 // indirect 103 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect 104 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect 105 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 106 | sigs.k8s.io/randfill v1.0.0 // indirect 107 | sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect 108 | sigs.k8s.io/yaml v1.4.0 // indirect 109 | ) 110 | -------------------------------------------------------------------------------- /overrides.mk: -------------------------------------------------------------------------------- 1 | # Copyright © 2020-2023 Dell Inc. or its subsidiaries. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License 12 | 13 | # overrides file 14 | # this file, included from the Makefile, will overlay default values with environment variables 15 | # 16 | 17 | # DEFAULT values 18 | DEFAULT_GOVERSION="1.21" 19 | DEFAULT_REGISTRY="" 20 | DEFAULT_IMAGENAME="isilon" 21 | DEFAULT_BUILDSTAGE="final" 22 | ifeq ($(origin BUILD_TIMESTAMP), undefined) 23 | BUILD_TIMESTAMP := $(shell date +%Y%m%d%H%M%S) 24 | endif 25 | DEFAULT_IMAGETAG=$(BUILD_TIMESTAMP) 26 | DEFAULT_GOPROXY="" 27 | 28 | # set the GOVERSION if needed 29 | ifeq ($(GOVERSION),) 30 | export GOVERSION="$(DEFAULT_GOVERSION)" 31 | endif 32 | 33 | # set the REGISTRY if needed 34 | ifeq ($(REGISTRY),) 35 | export REGISTRY="$(DEFAULT_REGISTRY)" 36 | endif 37 | 38 | # set the IMAGENAME if needed 39 | ifeq ($(IMAGENAME),) 40 | export IMAGENAME="$(DEFAULT_IMAGENAME)" 41 | endif 42 | 43 | # set the IMAGETAG if needed 44 | ifeq ($(IMAGETAG),) 45 | export IMAGETAG="$(DEFAULT_IMAGETAG)" 46 | endif 47 | 48 | # set the GOPROXY if needed 49 | ifeq ($(GOPROXY),) 50 | export GOPROXY="$(DEFAULT_GOPROXY)" 51 | endif 52 | 53 | # figure out if podman or docker should be used (use podman if found) 54 | ifneq (, $(shell which podman 2>/dev/null)) 55 | export BUILDER=podman 56 | else 57 | export BUILDER=docker 58 | endif 59 | 60 | # target to print some help regarding these overrides and how to use them 61 | overrides-help: 62 | @echo 63 | @echo "The following environment variables can be set to control the build" 64 | @echo 65 | @echo "GOVERSION - The version of Go to build with, default is: $(DEFAULT_GOVERSION)" 66 | @echo " Current setting is: $(GOVERSION)" 67 | @echo "REGISTRY - The registry to push images to, default is: $(DEFAULT_REGISTRY)" 68 | @echo " Current setting is: $(REGISTRY)" 69 | @echo "IMAGENAME - The image name to be built, defaut is: $(DEFAULT_IMAGENAME)" 70 | @echo " Current setting is: $(IMAGENAME)" 71 | @echo "IMAGETAG - The image tag to be built, default is an empty string which will determine the tag by examining annotated tags in the repo." 72 | @echo " Current setting is: $(IMAGETAG)" 73 | @echo "GOPROXY - The goproxy to be used for resolving dependencies, default is: $(DEFAULT_GOPROXY)" 74 | @echo " Current setting is: $(GOPROXY)" 75 | @echo 76 | -------------------------------------------------------------------------------- /provider/provider.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | /* 4 | Copyright (c) 2021-2022 Dell Inc, or its subsidiaries. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | import ( 20 | "github.com/dell/csi-isilon/v2/common/utils" 21 | "github.com/dell/csi-isilon/v2/service" 22 | "github.com/dell/csi-isilon/v2/service/interceptor" 23 | "github.com/dell/gocsi" 24 | "google.golang.org/grpc" 25 | ) 26 | 27 | // New returns a new Storage Plug-in Provider. 28 | func New() gocsi.StoragePluginProvider { 29 | log := utils.GetLogger() 30 | 31 | // TODO during the test, for some reason, when the controller & node pods start, 32 | // the sock files always exist right from the beginning, even if you manually 33 | // remove them prior to using helm to install the csi driver. Need to find out why. 34 | // For the time being, manually remove the sock files right at the beginning to 35 | // avoid the "...address is in use..." error 36 | if err := utils.RemoveExistingCSISockFile(); err != nil { 37 | log.Error("failed to call utils.RemoveExistingCSISockFile") 38 | } 39 | // Get the MaxConcurrentStreams server option and configure it. 40 | maxStreams := grpc.MaxConcurrentStreams(8) 41 | serverOptions := make([]grpc.ServerOption, 1) 42 | serverOptions[0] = maxStreams 43 | svc := service.New() 44 | 45 | interList := []grpc.UnaryServerInterceptor{ 46 | interceptor.NewCustomSerialLock(), 47 | interceptor.NewRewriteRequestIDInterceptor(), 48 | } 49 | return &gocsi.StoragePlugin{ 50 | Controller: svc, 51 | Identity: svc, 52 | Node: svc, 53 | Interceptors: interList, 54 | BeforeServe: svc.BeforeServe, 55 | ServerOpts: serverOptions, 56 | RegisterAdditionalServers: svc.RegisterAdditionalServers, 57 | 58 | EnvVars: []string{ 59 | // Enable request validation 60 | gocsi.EnvVarSpecReqValidation + "=true", 61 | 62 | // Enable serial volume access 63 | gocsi.EnvVarSerialVolAccess + "=true", 64 | }, 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /provider/provider_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2025 Dell Inc, or its subsidiaries. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package provider 18 | 19 | import ( 20 | "bytes" 21 | "errors" 22 | "testing" 23 | 24 | "github.com/dell/csi-isilon/v2/common/utils" 25 | "github.com/dell/gocsi" 26 | "github.com/sirupsen/logrus" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | // Mocking utility functions 31 | var ( 32 | mockGetLogger = func() *logrus.Entry { 33 | logger := logrus.New() 34 | logger.SetLevel(logrus.DebugLevel) 35 | var logBuffer bytes.Buffer 36 | logger.SetOutput(&logBuffer) 37 | return logrus.NewEntry(logger) 38 | } 39 | mockRemoveExistingCSISockFile = func() error { 40 | return errors.New("failed to remove existing CSI sock file") 41 | } 42 | ) 43 | 44 | func TestNew(t *testing.T) { 45 | // Inject the mock functions 46 | newTest := New() 47 | 48 | // Type assertion to access the fields of gocsi.StoragePlugin 49 | plugin, ok := newTest.(*gocsi.StoragePlugin) 50 | assert.True(t, ok, "newTest should be of type *gocsi.StoragePlugin") 51 | 52 | // Assertions 53 | assert.NotNil(t, plugin) 54 | assert.Equal(t, plugin.Controller, plugin.Identity) 55 | assert.Equal(t, plugin.Controller, plugin.Node) 56 | assert.Len(t, plugin.Interceptors, 2) 57 | assert.Len(t, plugin.ServerOpts, 1) 58 | assert.NotNil(t, plugin.BeforeServe) 59 | assert.NotNil(t, plugin.RegisterAdditionalServers) 60 | assert.Len(t, plugin.EnvVars, 2) 61 | 62 | // Test case: Removing existing CSI sock file succeeds 63 | utils.RemoveExistingCSISockFile = func() error { 64 | return errors.New("failed to remove existing CSI sock file") 65 | } 66 | 67 | newTest = New() 68 | plugin, ok = newTest.(*gocsi.StoragePlugin) 69 | assert.True(t, ok, "newTest should be of type *gocsi.StoragePlugin") 70 | 71 | // Assertions 72 | assert.NotNil(t, plugin) 73 | assert.Equal(t, plugin.Controller, plugin.Identity) 74 | assert.Equal(t, plugin.Controller, plugin.Node) 75 | assert.Len(t, plugin.Interceptors, 2) 76 | assert.Len(t, plugin.ServerOpts, 1) 77 | assert.NotNil(t, plugin.BeforeServe) 78 | assert.NotNil(t, plugin.RegisterAdditionalServers) 79 | assert.Len(t, plugin.EnvVars, 2) 80 | } 81 | -------------------------------------------------------------------------------- /samples/persistentvolumeclaim/pvc-from-pvc.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-from-pvc 5 | namespace: default 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 5Gi 13 | storageClassName: isilon 14 | dataSource: 15 | kind: PersistentVolumeClaim 16 | name: test-pvc 17 | apiGroup: "" 18 | -------------------------------------------------------------------------------- /samples/persistentvolumeclaim/pvc-from-snapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: pvc-from-snapshot 5 | namespace: default 6 | spec: 7 | storageClassName: isilon 8 | dataSource: 9 | name: snapshot-of-test-pvc 10 | kind: VolumeSnapshot 11 | apiGroup: snapshot.storage.k8s.io 12 | accessModes: 13 | - ReadWriteMany 14 | resources: 15 | requests: 16 | storage: 5Gi 17 | -------------------------------------------------------------------------------- /samples/persistentvolumeclaim/pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: test-pvc 5 | # Uncomment below 4 lines to set quota limit parameters 6 | # labels: 7 | # pvcSoftLimit: "10" 8 | # pvcAdvisoryLimit: "50" 9 | # pvcSoftGracePrd : "85400" 10 | spec: 11 | accessModes: 12 | - ReadWriteOnce 13 | resources: 14 | requests: 15 | storage: 5Gi 16 | storageClassName: isilon 17 | -------------------------------------------------------------------------------- /samples/pod/inline-volume.yaml: -------------------------------------------------------------------------------- 1 | kind: Pod 2 | apiVersion: v1 3 | metadata: 4 | name: my-csi-app-inline-volume 5 | spec: 6 | containers: 7 | - name: my-frontend 8 | image: busybox 9 | command: ["sleep", "100000"] 10 | volumeMounts: 11 | - mountPath: "/data" 12 | name: my-csi-volume 13 | volumes: 14 | - name: my-csi-volume 15 | csi: 16 | driver: csi-isilon.dellemc.com 17 | volumeAttributes: 18 | size: "2Gi" 19 | ClusterName: "cluster1" 20 | -------------------------------------------------------------------------------- /samples/pod/nginx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: nginx-pv-pod 5 | spec: 6 | containers: 7 | - name: task-pv-container 8 | image: nginx 9 | ports: 10 | - containerPort: 80 11 | name: "http-server" 12 | volumeMounts: 13 | - mountPath: "/usr/share/nginx/html" 14 | name: task-pv-storage 15 | volumes: 16 | - name: task-pv-storage 17 | persistentVolumeClaim: 18 | claimName: test-pvc 19 | -------------------------------------------------------------------------------- /samples/secret/empty-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: isilon-certs-0 5 | namespace: isilon 6 | type: Opaque 7 | data: 8 | cert-0: "" 9 | -------------------------------------------------------------------------------- /samples/secret/karavi-authorization-config.json: -------------------------------------------------------------------------------- 1 | [{"username":"-","password":"-","intendedEndpoint":"https://10.0.0.1:8080","endpoint":"https://localhost:9400","systemID":"myIsilonClusterName","skipCertificateValidation":true,"isDefault":true}] 2 | -------------------------------------------------------------------------------- /samples/secret/secret.yaml: -------------------------------------------------------------------------------- 1 | isilonClusters: 2 | # logical name of PowerScale Cluster 3 | - clusterName: "cluster1" 4 | 5 | # username for connecting to PowerScale OneFS API server 6 | # if authorization is enabled, username will be ignored 7 | # Default value: None 8 | username: "user" 9 | 10 | # password for connecting to PowerScale OneFS API server 11 | # if authorization is enabled, password will be ignored 12 | password: "password" 13 | 14 | # HTTPS endpoint of the PowerScale OneFS API server 15 | # if authorization is enabled, the endpont should be the localhost address of the csm-authorization-sidecar 16 | # Default value: None 17 | # Examples: "1.2.3.4", "https://1.2.3.4", "https://abc.myonefs.com" 18 | endpoint: "1.2.3.4" 19 | 20 | # endpointPort: Specify the HTTPs port number of the PowerScale OneFS API server 21 | # Formerly this attribute was named as "isiPort" 22 | # If authorization is enabled, endpointPort must match the port specified in the endpoint parameter of the karavi-authorization-config secret 23 | # Allowed value: valid port number 24 | # Default value: 8080 25 | # endpointPort: 8080 26 | 27 | # Is this a default cluster (would be used by storage classes without ClusterName parameter) 28 | # Allowed values: 29 | # true: mark this cluster config as default 30 | # false: mark this cluster config as not default 31 | # Default value: false 32 | isDefault: true 33 | 34 | # Specify whether the PowerScale OneFS API server's certificate chain and host name should be verified. 35 | # Allowed values: 36 | # true: skip OneFS API server's certificate verification 37 | # false: verify OneFS API server's certificates 38 | # Default value: default value specified in values.yaml 39 | # skipCertificateValidation: true 40 | 41 | # The base path for the volumes to be created on PowerScale cluster 42 | # This will be used if a storage class does not have the IsiPath parameter specified. 43 | # Ensure that this path exists on PowerScale cluster. 44 | # Allowed values: unix absolute path 45 | # Default value: default value specified in values.yaml 46 | # Examples: "/ifs/data/csi", "/ifs/engineering" 47 | # isiPath: "/ifs/data/csi" 48 | 49 | # The permissions for isi volume directory path 50 | # This will be used if a storage class does not have the IsiVolumePathPermissions parameter specified. 51 | # Allowed values: valid octal mode number 52 | # Default value: "0777" 53 | # Examples: "0777", "777", "0755" 54 | # isiVolumePathPermissions: "0777" 55 | 56 | # ignoreUnresolvableHosts: Ignore unresolvable hosts on the OneFS 57 | # When set to true, OneFS allows new host to add to existing export list though any of the existing hosts from the 58 | # same exports are unresolvable/doesn't exist anymore. 59 | # Allowed values: 60 | # true: ignore existing unresolvable hosts and append new host to the existing export 61 | # false: exhibits OneFS default behavior i.e. if any of existing hosts are unresolvable while adding new one it fails 62 | # Default value: false 63 | # ignoreUnresolvableHosts: false 64 | 65 | # Unique ID if the certificate is used to encrypt replication policy 66 | # This will be used if a replication encrypted is enabled, leave empty in case you use unecrypted replication 67 | # Allowed values: string, unique id of the certificate 68 | # Default value: "" 69 | # Examples: "dd9c736cc17e6dd5f7d85fe13528cfc20f3b4b0af4f26595d22328c8d1f461af" 70 | # replicationCertificateID: "" 71 | 72 | # To add more PowerScale systems, uncomment the following lines and provide the required values 73 | # - clusterName: "cluster2" 74 | # username: "user" 75 | # password: "password" 76 | # endpoint: "1.2.3.4" 77 | # endpointPort: "8080" 78 | -------------------------------------------------------------------------------- /samples/storageclass/isilon.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: isilon 5 | provisioner: csi-isilon.dellemc.com 6 | reclaimPolicy: Delete 7 | allowVolumeExpansion: true 8 | parameters: 9 | 10 | # The name of the access zone a volume can be created in 11 | # Optional: true 12 | # Default value: default value specified in values.yaml 13 | # Examples: System, zone1 14 | AccessZone: System 15 | 16 | # The base path for the volumes to be created on PowerScale cluster. 17 | # Ensure that this path exists on PowerScale cluster. 18 | # Allowed values: unix absolute path 19 | # Optional: true 20 | # Default value: value specified in values.yaml for isiPath 21 | # Examples: /ifs/data/csi, /ifs/engineering 22 | IsiPath: /ifs/data/csi 23 | 24 | # Parameter to set Advisory Limit to quota 25 | # Optional: true 26 | # Default Behaviour : Limit not set 27 | # AdvisoryLimit: "50" 28 | # Parameter to set soft limit to quota 29 | # Optional: true 30 | # Default Behaviour: Limit not set 31 | # SoftLimit: "80" 32 | # Parameter which must be mentioned along with Soft Limit 33 | # Soft Limit can be exceeded until the grace period 34 | # Optional: true 35 | # Default Behaviour : Limit not set 36 | # SoftGracePrd: "86400" 37 | 38 | # The permissions for isi volume directory path 39 | # This value overrides the isiVolumePathPermissions attribute of corresponding cluster config in secret, if present 40 | # Allowed values: valid octal mode number 41 | # Default value: "0777" 42 | # Examples: "0777", "777", "0755" 43 | # IsiVolumePathPermissions: "0777" 44 | 45 | # AccessZone groupnet service IP. Update AzServiceIP if different than endpoint. 46 | # Optional: true 47 | # Default value: endpoint of the cluster ClusterName 48 | # AzServiceIP : 192.168.2.1 49 | 50 | # When a PVC is being created, this parameter determines, when a node mounts the PVC, 51 | # whether to add the k8s node to the "Root clients" field or "Clients" field of the NFS export 52 | # Allowed values: 53 | # "true": adds k8s node to the "Root clients" field of the NFS export 54 | # "false": adds k8s node to the "Clients" field of the NFS export 55 | # Optional: true 56 | # Default value: "false" 57 | RootClientEnabled: "false" 58 | 59 | # Name of PowerScale cluster, where pv will be provisioned. 60 | # This name should match with name of one of the cluster configs in isilon-creds secret. 61 | # If this parameter is not specified, then default cluster config in isilon-creds secret 62 | # will be considered if available. 63 | # Optional: true 64 | # ClusterName: 65 | 66 | # Sets the filesystem type which will be used to format the new volume 67 | # Optional: true 68 | # Default value: None 69 | # csi.storage.k8s.io/fstype: "nfs" 70 | 71 | # volumeBindingMode controls when volume binding and dynamic provisioning should occur. 72 | # Allowed values: 73 | # Immediate: indicates that volume binding and dynamic provisioning occurs once the 74 | # PersistentVolumeClaim is created 75 | # WaitForFirstConsumer: will delay the binding and provisioning of a PersistentVolume 76 | # until a Pod using the PersistentVolumeClaim is created 77 | # Default value: Immediate 78 | volumeBindingMode: Immediate 79 | 80 | # allowedTopologies helps scheduling pods on worker nodes which match all of below expressions. 81 | # If enableCustomTopology is set to true in helm values.yaml, then do not specify allowedTopologies 82 | # Change all instances of to the IP of the PowerScale OneFS API server 83 | # allowedTopologies: 84 | # - matchLabelExpressions: 85 | # - key: csi-isilon.dellemc.com/ 86 | # values: 87 | # - csi-isilon.dellemc.com 88 | 89 | # specify additional mount options for when a Persistent Volume is being mounted on a node. 90 | # To mount volume with NFSv4, specify mount option vers=4. Make sure NFSv4 is enabled on the Isilon Cluster 91 | # mountOptions: ["", "", ..., ""] 92 | -------------------------------------------------------------------------------- /samples/volumesnapshot/snapshot-of-test-pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: snapshot-of-test-pvc 5 | namespace: default 6 | spec: 7 | volumeSnapshotClassName: isilon-snapclass 8 | source: 9 | persistentVolumeClaimName: test-pvc 10 | -------------------------------------------------------------------------------- /samples/volumesnapshotclass/isilon-volumesnapshotclass-v1.yaml: -------------------------------------------------------------------------------- 1 | # For kubernetes version 20 (v1 snaps) 2 | apiVersion: snapshot.storage.k8s.io/v1 3 | kind: VolumeSnapshotClass 4 | metadata: 5 | name: isilon-snapclass 6 | driver: csi-isilon.dellemc.com 7 | 8 | # Configure what happens to a VolumeSnapshotContent when the VolumeSnapshot object 9 | # it is bound to is to be deleted 10 | # Allowed values: 11 | # Delete: the underlying storage snapshot will be deleted along with the VolumeSnapshotContent object. 12 | # Retain: both the underlying snapshot and VolumeSnapshotContent remain. 13 | deletionPolicy: Delete 14 | -------------------------------------------------------------------------------- /service/controllerNodeToArrayConnectivity.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | /* 4 | Copyright (c) 2022-2025 Dell Inc, or its subsidiaries. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | import ( 20 | "context" 21 | "encoding/json" 22 | "io" 23 | "net/http" 24 | "time" 25 | ) 26 | 27 | // timeout for making http requests 28 | var timeout = time.Second * 5 29 | 30 | var ( 31 | GetHTTPNewRequestWithContext = http.NewRequestWithContext 32 | GetIoReadAll = io.ReadAll 33 | ) 34 | 35 | // queryStatus make API call to the specified url to retrieve connection status 36 | func (s *service) queryArrayStatus(ctx context.Context, url string) (bool, error) { 37 | ctx, log, _ := GetRunIDLog(ctx) 38 | defer func() { 39 | if err := recover(); err != nil { 40 | log.Println("panic occurred in queryStatus:", err) 41 | } 42 | }() 43 | log.Infof("Calling API %s with timeout %v", url, timeout) 44 | timeOutCtx, cancel := context.WithTimeout(ctx, timeout) 45 | defer cancel() 46 | 47 | req, err := GetHTTPNewRequestWithContext(timeOutCtx, "GET", url, nil) 48 | if err != nil { 49 | log.Errorf("failed to create request for API %s due to %s ", url, err.Error()) 50 | return false, err 51 | } 52 | req.Header.Add("Accept", "application/json") 53 | req.Header.Add("Content-Type", "application/json") 54 | log.Debugf("Making %s url request %+v", url, req) 55 | 56 | client := &http.Client{} 57 | resp, err := client.Do(req) 58 | log.Debugf("Received response %+v for url %s", resp, url) 59 | if err != nil { 60 | log.Errorf("failed to call API %s due to %s ", url, err.Error()) 61 | return false, err 62 | } 63 | defer func() { 64 | if err := resp.Body.Close(); err != nil { 65 | log.Printf("Error closing HTTP response: %s", err.Error()) 66 | } 67 | }() 68 | bodyBytes, err := GetIoReadAll(resp.Body) 69 | if err != nil { 70 | log.Errorf("failed to read API response due to %s ", err.Error()) 71 | return false, err 72 | } 73 | var statusResponse ArrayConnectivityStatus 74 | err = json.Unmarshal(bodyBytes, &statusResponse) 75 | if err != nil { 76 | log.Errorf("unable to unmarshal and determine connectivity due to %s ", err) 77 | return false, err 78 | } 79 | log.Infof("API Response received is %+v\n", statusResponse) 80 | // responseObject has last success and last attempt timestamp in Unix format 81 | timeDiff := statusResponse.LastAttempt - statusResponse.LastSuccess 82 | tolerance := setPollingFrequency(ctx) 83 | currTime := time.Now().Unix() 84 | // checking if the status response is stale and connectivity test is still running 85 | // since nodeProbe is run at frequency tolerance/2, ideally below check should never be true 86 | if (currTime - statusResponse.LastAttempt) > tolerance*2 { 87 | log.Errorf("seems like connectivity test is not being run, current time is %d and last run was at %d", currTime, statusResponse.LastAttempt) 88 | // considering connectivity is broken 89 | return false, nil 90 | } 91 | log.Debugf("last connectivity was %d sec back, tolerance is %d sec", timeDiff, tolerance) 92 | // give 2s leeway for tolerance check 93 | if timeDiff <= tolerance+2 { 94 | return true, nil 95 | } 96 | return false, nil 97 | } 98 | -------------------------------------------------------------------------------- /service/features/controller_create_delete_snapshot.feature: -------------------------------------------------------------------------------- 1 | Feature: Isilon CSI interface 2 | As a consumer of the CSI interface 3 | I want to test list service methods 4 | So that they are known to work 5 | 6 | @createSnapshot 7 | @v1.0.0 8 | Scenario: Create snapshot good scenario 9 | Given a Isilon service 10 | When I call Probe 11 | And I call CreateSnapshot "volume2" "volume2=_=_=19=_=_=System" "create_snapshot_name" 12 | Then a valid CreateSnapshotResponse is returned 13 | 14 | Scenario: Create snapshot with cluster name in volume id good scenario 15 | Given a Isilon service 16 | When I call Probe 17 | And I call CreateSnapshot "volume2" "volume2=_=_=19=_=_=System=_=_=cluster1" "create_snapshot_name" 18 | Then a valid CreateSnapshotResponse is returned 19 | 20 | Scenario: Create snapshot with cluster name in volume id whose config doesn't exists 21 | Given a Isilon service 22 | When I call Probe 23 | And I call CreateSnapshot "volume2" "volume2=_=_=19=_=_=System=_=_=cluster2" "create_snapshot_name" 24 | Then the error contains "failed to get cluster config details for clusterName: 'cluster2'" 25 | 26 | Scenario: Create snapshot with internal server error 27 | Given a Isilon service 28 | When I call Probe 29 | And I induce error "CreateSnapshotError" 30 | And I call CreateSnapshot "volume2" "volume2=_=_=19=_=_=System" "create_snapshot_name" 31 | Then the error contains "EOF" 32 | 33 | Scenario Outline: Create snapshot with negative or idempotent arguments 34 | Given a Isilon service 35 | When I call CreateSnapshot 36 | Then the error contains 37 | 38 | Examples: 39 | | volName | volumeID | snapshotName | errormsg | 40 | | "volume1" | "volume1=_=_=10=_=_=System" | "create_snapshot_name" | "source volume id is invalid" | 41 | | "volume2" | "volume2=_=_=19=_=_=System" | "existent_snapshot_name" | "already exists but is incompatible" | 42 | | "volume2" | "volume2=_=_=19=_=_=System" | "existent_comp_snapshot_name" | "none" | 43 | | "volume2" | "volume2=_=_=19=_=_=System" | "existent_comp_snapshot_name_longer_than_max" | "already exists but is incompatible" | 44 | | "volume2" | "volume2=_=_=19" | "existent_comp_snapshot_name" | "cannot be split into tokens" | 45 | | "volume2" | "volume2=_=_=19=_=_=System" | "" | "name cannot be empty" | 46 | 47 | @todo 48 | @createROVolumeFromSnapshot 49 | Scenario: Create RO volume from snapshot good scenario 50 | Given a Isilon service 51 | When I call Probe 52 | And I call CreateROVolumeFromSnapshot "2" "volume1" 53 | Then a valid CreateVolumeResponse is returned 54 | 55 | @deleteSnapshot 56 | @v1.0.0 57 | Scenario Outline: Delete snapshot with various induced error use cases from examples 58 | Given a Isilon service 59 | When I call Probe 60 | And I induce error 61 | And I call DeleteSnapshot "34" 62 | Then the error contains 63 | 64 | Examples: 65 | | induced | errormsg | 66 | | "GetSnapshotError" | "cannot check the existence of the snapshot" | 67 | 68 | Scenario Outline: Controller delete snapshot various use cases from examples 69 | Given a Isilon service 70 | When I call Probe 71 | And I call DeleteSnapshot 72 | Then the error contains 73 | 74 | Examples: 75 | | snapshotId | errormsg | 76 | | "34=_=_=cluster2=_=_=System" | "failed to get cluster config details for clusterName: 'cluster2'" | 77 | | "" | "snapshot id to be deleted is required" | 78 | | "34=_=_=cluster2" | "access zone not found in snapshot ID" | 79 | | "404" | "none" | 80 | | "str" | "cannot convert snapshot to integer" | 81 | 82 | Scenario: Calling Snapshot create and delete functionality 83 | Given a Isilon service 84 | When I call CreateVolume "volume2" 85 | And I call ControllerPublishVolume with "single-writer" to "vpi7125=#=#=vpi7125.a.b.com=#=#=1.1.1.1" 86 | And I call DeleteVolume "volume2=_=_=43=_=_=System" 87 | And I call ValidateVolumeCapabilities with voltype "mount" access "single-writer" 88 | And I call GetCapacity 89 | And I call CreateSnapshot "volume2=_=_=43=_=_=System" "existent_comp_snapshot_name" "/ifs/data/csi-isilon" 90 | And I call DeleteSnapshot "34" 91 | And I call NodePublishVolume 92 | And I call NodeUnpublishVolume 93 | Then the error contains "none" 94 | -------------------------------------------------------------------------------- /service/features/controller_expand_volume.feature: -------------------------------------------------------------------------------- 1 | Feature: Isilon CSI interface 2 | As a consumer of the CSI interface 3 | I want to test volume expansion service methods 4 | So that they are known to work 5 | 6 | @expandVolume 7 | @v1.1.0 8 | Scenario: Controller Expand volume good scenario with Quota enabled 9 | Given a Isilon service 10 | And I enable quota 11 | When I call ControllerExpandVolume "volume1=_=_=557=_=_=System" "108589934592" 12 | Then a valid ControllerExpandVolumeResponse is returned 13 | 14 | Scenario: Controller Expand volume good scenario with Quota enabled and non-existing volume 15 | Given a Isilon service 16 | And I enable quota 17 | When I call ControllerExpandVolume "volume1=_=_=557=_=_=System=_=_=cluster1" "108589934592" 18 | Then a valid ControllerExpandVolumeResponse is returned 19 | 20 | Scenario: Controller Expand volume negative scenario with Quota enabled 21 | Given a Isilon service 22 | And I enable quota 23 | When I call ControllerExpandVolume "volume1=_=_=557=_=_=System=_=_=cluster2" "108589934592" 24 | Then the error contains "failed to get cluster config details for clusterName: 'cluster2'" 25 | 26 | Scenario: Controller Expand volume good scenario with Quota disabled 27 | Given a Isilon service 28 | When I call ControllerExpandVolume "volume1=_=_=557=_=_=System" "108589934592" 29 | Then a valid ControllerExpandVolumeResponse is returned 30 | 31 | Scenario: Controller Expand volume idempotent scenario with Quota enabled 32 | Given a Isilon service 33 | And I enable quota 34 | When I call ControllerExpandVolume "volume1=_=_=557=_=_=System" "589934592" 35 | Then a valid ControllerExpandVolumeResponse is returned 36 | 37 | Scenario Outline: Controller Expand volume with negative arguments and Quota enabled 38 | Given a Isilon service 39 | And I enable quota 40 | When I call ControllerExpandVolume 41 | Then a valid ControllerExpandVolumeResponse is returned 42 | 43 | Examples: 44 | | volumeID | requiredBytes | 45 | | "volume1=_=_=557=_=_=System" | "-108589934592" | 46 | 47 | Scenario Outline: Controller Expand volume with induced errors and Quota enabled 48 | Given a Isilon service 49 | And I enable quota 50 | When I induce error 51 | And I call ControllerExpandVolume "volume1=_=_=557=_=_=System" "108589934592" 52 | Then the error contains 53 | 54 | Examples: 55 | | induced | errormsg | 56 | | "UpdateQuotaError" | "failed to update quota" | 57 | 58 | Scenario: Calling functions with autoProbe failed 59 | Given a Isilon service 60 | And I induce error "autoProbeFailed" 61 | When I call ControllerExpandVolume "volume1=_=_=557=_=_=System" "108589934592" 62 | Then the error contains "auto probe is not enabled" 63 | 64 | Scenario: Calling functions with invalid volume id 65 | Given a Isilon service 66 | When I call ControllerExpandVolume "volume1=_=_=557" "108589934592" 67 | Then the error contains "volume ID @@ cannot be split into tokens" 68 | -------------------------------------------------------------------------------- /service/features/csi_extension.feature: -------------------------------------------------------------------------------- 1 | Feature: Isilon CSI interface 2 | As a consumer of the CSI interface 3 | I want to test service methods 4 | So that they are known to work 5 | 6 | @podmon 7 | @v1.0.0 8 | Scenario: Call ValidateConnectivity 9 | Given a Isilon service 10 | When I call Probe 11 | And I call CreateVolume "volume1" 12 | And a valid CreateVolumeResponse is returned 13 | And I call ValidateConnectivity 14 | Then the error contains "none" 15 | 16 | Scenario: Call ValidateConnectivity with invalid volID 17 | Given a Isilon service 18 | When I call Probe 19 | And I call CreateVolume "volume1" 20 | And I induce error "invalid-volumeId" 21 | And I call ValidateConnectivity 22 | Then the error contains "none" 23 | 24 | Scenario: Call ValidateConnectivity with invalid NodeID 25 | Given a Isilon service 26 | When I call Probe 27 | And I call CreateVolume "volume1" 28 | And I induce error "invalid-nodeId" 29 | And I call ValidateConnectivity 30 | Then the error contains "failed to parse node ID" 31 | 32 | Scenario: Call ValidateConnectivity with no Node 33 | Given a Isilon service 34 | When I call CreateVolume "volume1" 35 | And I induce error "no-nodeId" 36 | And I call ValidateConnectivity 37 | Then the error contains "the NodeID is a required field" 38 | 39 | Scenario: Call ValidateConnectivity with no Volume no Node 40 | Given a Isilon service 41 | And I induce error "no-volume-no-nodeId" 42 | And I call ValidateConnectivity 43 | Then the error contains "ValidateVolumeHostConnectivity is implemented" 44 | 45 | Scenario: Call Validate Url Status 46 | Given a Isilon service 47 | And I call QueryArrayStatus "36443" 48 | Then the error contains "none" 49 | 50 | Scenario: Call Modify LastAttempt with delay 51 | Given a Isilon service 52 | And I induce error "ModifyLastAttempt" 53 | And I call QueryArrayStatus "36443" 54 | Then the error contains "none" -------------------------------------------------------------------------------- /service/features/isiService.feature: -------------------------------------------------------------------------------- 1 | Feature: Isilon CSI interface 2 | As a consumer of the CSI interface 3 | I want to test service methods 4 | So that they are known to work 5 | 6 | Scenario: Calling create quota in isiService with negative sizeInBytes 7 | Given a Isilon service 8 | When I call CreateQuota in isiService with 9 | Then the error contains "none" 10 | Examples: 11 | | softLimit | advisoryLimit | softgraceprd | sizeInBytes 12 | | "0" | "30" | "0" | -1 13 | | "40" | "0" | "85600" | 53687091 14 | | "60" | "80" | "85600" | 53687091 15 | | "110" | "80" | "85600" | 53687091 16 | | "-1" | "-1" | "85600" | 53687091 17 | | "ab" | "-1" | "85600" | 53687091 18 | 19 | Scenario: Calling get export with no result 20 | Given a Isilon service 21 | When I induce error "GetExportInternalError" 22 | And I call get export related functions in isiService 23 | Then the error contains "EOF" 24 | 25 | Scenario Outline: GetSnapshotNameFromIsiPath with params 26 | Given a Isilon service 27 | And I call GetSnapshotNameFromIsiPath with 28 | Then the error contains 29 | Examples: 30 | | isipath | errormsg | 31 | | "" | "invalid snapshot isilon path" | 32 | | "/ifs/.snapshot" | "invalid snapshot isilon path" | 33 | | "/ifs/.snapshot/data/csiislon" | "none" | 34 | 35 | Scenario: GetSnapshotIsiPathComponents 36 | Given a Isilon service 37 | And I call GetSnapshotIsiPathComponents 38 | Then the error contains "none" 39 | 40 | Scenario: GetSubDirectoryCount 41 | Given a Isilon service 42 | And I call GetSubDirectoryCount 43 | Then the error contains "none" 44 | 45 | Scenario: DeleteSnapshot case 46 | Given a Isilon service 47 | And I call DeleteSnapshotIsiService 48 | Then the error contains "none" 49 | -------------------------------------------------------------------------------- /service/mock/cluster/get_cluster_config.txt: -------------------------------------------------------------------------------- 1 | { 2 | "description": "", 3 | "devices": [ 4 | { 5 | "devid": 1, 6 | "guid": "000e1ea5825065e0e65c231d37b8ab381ab7", 7 | "is_up": true, 8 | "lnn": 1 9 | }, 10 | { 11 | "devid": 2, 12 | "guid": "000e1ea577400ee7e65c401ce161d195da97", 13 | "is_up": true, 14 | "lnn": 2 15 | }, 16 | { 17 | "devid": 3, 18 | "guid": "000e1ea577302ce6e65c4a1fe30e4d5cc72a", 19 | "is_up": true, 20 | "lnn": 3 21 | } 22 | ], 23 | "encoding": "utf-8", 24 | "guid": "000e1ea582501ce1e65c8e123920ccb186fe", 25 | "has_quorum": true, 26 | "is_compliance": false, 27 | "is_virtual": false, 28 | "is_vonefs": false, 29 | "join_mode": "Manual", 30 | "local_devid": 1, 31 | "local_lnn": 1, 32 | "local_serial": "SX410-301543-0031", 33 | "name": "PIE-IsilonX", 34 | "onefs_version": { 35 | "build": "B_8_2_0_0_009(RELEASE)", 36 | "copyright": "Copyright (c) 2001-2016 EMC Corporation. All Rights Reserved.", 37 | "reldate": 1200019, 38 | "release": "v8.2.0.0", 39 | "revision": "577024045854228489", 40 | "type": "Isilon OneFS", 41 | "version": "Isilon OneFS v8.2.0.0 B_8_2_0_0_009(RELEASE): 0x802005000000009:Mon May 6 17:10:51 PDT 2019 root@sea-build11-01:/b/mnt/obj/b/mnt/src/amd64.amd64/sys/IQ.amd64.release FreeBSD clang version 3.9.1 (tags/RELEASE_391/final 289601) (based on LLVM 3.9.1)" 42 | }, 43 | "timezone": { 44 | "abbreviation": "EDT", 45 | "custom": "", 46 | "name": "Eastern Time Zone", 47 | "path": "America/New_York" 48 | }, 49 | "upgrade_type": null 50 | } -------------------------------------------------------------------------------- /service/mock/export/create_export_557.txt: -------------------------------------------------------------------------------- 1 | { 2 | "id": 557 3 | } -------------------------------------------------------------------------------- /service/mock/export/export_not_found_by_id.txt: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "code": "AEC_NOT_FOUND", 5 | "field": "id", 6 | "message": "Export id 9999999 does not exist" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /service/mock/export/get_all_exports_including_volume2.txt: -------------------------------------------------------------------------------- 1 | { 2 | "digest": "ea3e2ee33987c086b729920af28a68d9", 3 | "exports": [ 4 | { 5 | "all_dirs": false, 6 | "block_size": 8192, 7 | "can_set_time": true, 8 | "case_insensitive": false, 9 | "case_preserving": true, 10 | "chown_restricted": false, 11 | "clients": [], 12 | "commit_asynchronous": false, 13 | "conflicting_paths": [], 14 | "description": "CSI_QUOTA_ID:AABpAQEAAAAAAAAAAAAAQA0AAAAAAAAA", 15 | "directory_transfer_size": 131072, 16 | "encoding": "DEFAULT", 17 | "id": 43, 18 | "link_max": 32767, 19 | "map_failure": { 20 | "enabled": false, 21 | "primary_group": {}, 22 | "secondary_groups": [], 23 | "user": { 24 | "id": "USER:nobody" 25 | } 26 | }, 27 | "map_full": true, 28 | "map_lookup_uid": false, 29 | "map_non_root": { 30 | "enabled": false, 31 | "primary_group": {}, 32 | "secondary_groups": [], 33 | "user": { 34 | "id": "USER:nobody" 35 | } 36 | }, 37 | "map_retry": true, 38 | "map_root": { 39 | "enabled": true, 40 | "primary_group": {}, 41 | "secondary_groups": [], 42 | "user": { 43 | "id": "USER:nobody" 44 | } 45 | }, 46 | "max_file_size": 9223372036854775807, 47 | "name_max_size": 255, 48 | "no_truncate": false, 49 | "paths": [ 50 | "/ifs/data/csi-isilon/volume2" 51 | ], 52 | "read_only": false, 53 | "read_only_clients": [], 54 | "read_transfer_max_size": 1048576, 55 | "read_transfer_multiple": 512, 56 | "read_transfer_size": 131072, 57 | "read_write_clients": [], 58 | "readdirplus": true, 59 | "readdirplus_prefetch": 10, 60 | "return_32bit_file_ids": false, 61 | "root_clients": [], 62 | "security_flavors": [ 63 | "unix" 64 | ], 65 | "setattr_asynchronous": false, 66 | "snapshot": "-", 67 | "symlinks": true, 68 | "time_delta": 1.000000000000000e-09, 69 | "unresolved_clients": [], 70 | "write_datasync_action": "DATASYNC", 71 | "write_datasync_reply": "DATASYNC", 72 | "write_filesync_action": "FILESYNC", 73 | "write_filesync_reply": "FILESYNC", 74 | "write_transfer_max_size": 1048576, 75 | "write_transfer_multiple": 512, 76 | "write_transfer_size": 524288, 77 | "write_unstable_action": "UNSTABLE", 78 | "write_unstable_reply": "UNSTABLE", 79 | "zone": "System" 80 | }, 81 | { 82 | "all_dirs": false, 83 | "block_size": 8192, 84 | "can_set_time": true, 85 | "case_insensitive": false, 86 | "case_preserving": true, 87 | "chown_restricted": false, 88 | "clients": [], 89 | "commit_asynchronous": false, 90 | "conflicting_paths": [], 91 | "description": "", 92 | "directory_transfer_size": 131072, 93 | "encoding": "DEFAULT", 94 | "id": 49, 95 | "link_max": 32767, 96 | "map_failure": { 97 | "enabled": false, 98 | "primary_group": {}, 99 | "secondary_groups": [], 100 | "user": { 101 | "id": "USER:nobody" 102 | } 103 | }, 104 | "map_full": true, 105 | "map_lookup_uid": false, 106 | "map_non_root": { 107 | "enabled": false, 108 | "primary_group": {}, 109 | "secondary_groups": [], 110 | "user": { 111 | "id": "USER:nobody" 112 | } 113 | }, 114 | "map_retry": true, 115 | "map_root": { 116 | "enabled": true, 117 | "primary_group": {}, 118 | "secondary_groups": [], 119 | "user": { 120 | "id": "USER:nobody" 121 | } 122 | }, 123 | "max_file_size": 9223372036854775807, 124 | "name_max_size": 255, 125 | "no_truncate": false, 126 | "paths": [ 127 | "/ifs/data/csi_share_1/k8s-51b4602dba" 128 | ], 129 | "read_only": false, 130 | "read_only_clients": [], 131 | "read_transfer_max_size": 1048576, 132 | "read_transfer_multiple": 512, 133 | "read_transfer_size": 131072, 134 | "read_write_clients": [], 135 | "readdirplus": true, 136 | "readdirplus_prefetch": 10, 137 | "return_32bit_file_ids": false, 138 | "root_clients": [], 139 | "security_flavors": [ 140 | "unix" 141 | ], 142 | "setattr_asynchronous": false, 143 | "snapshot": "-", 144 | "symlinks": true, 145 | "time_delta": 1.000000000000000e-09, 146 | "unresolved_clients": [], 147 | "write_datasync_action": "DATASYNC", 148 | "write_datasync_reply": "DATASYNC", 149 | "write_filesync_action": "FILESYNC", 150 | "write_filesync_reply": "FILESYNC", 151 | "write_transfer_max_size": 1048576, 152 | "write_transfer_multiple": 512, 153 | "write_transfer_size": 524288, 154 | "write_unstable_action": "UNSTABLE", 155 | "write_unstable_reply": "UNSTABLE", 156 | "zone": "System" 157 | } 158 | ], 159 | "resume": null, 160 | "total": 2 161 | } -------------------------------------------------------------------------------- /service/mock/export/get_export_557.txt: -------------------------------------------------------------------------------- 1 | { 2 | "exports": [ 3 | { 4 | "all_dirs": false, 5 | "block_size": 8192, 6 | "can_set_time": true, 7 | "case_insensitive": false, 8 | "case_preserving": true, 9 | "chown_restricted": false, 10 | "clients": [], 11 | "commit_asynchronous": false, 12 | "conflicting_paths": [], 13 | "description": "CSI_QUOTA_ID:AABpAQEAAAAAAAAAAAAAQA0AAAAAAAAA", 14 | "directory_transfer_size": 131072, 15 | "encoding": "DEFAULT", 16 | "id": 557, 17 | "link_max": 32767, 18 | "map_failure": { 19 | "enabled": false, 20 | "primary_group": {}, 21 | "secondary_groups": [], 22 | "user": { 23 | "id": "USER:nobody" 24 | } 25 | }, 26 | "map_full": true, 27 | "map_lookup_uid": false, 28 | "map_non_root": { 29 | "enabled": false, 30 | "primary_group": {}, 31 | "secondary_groups": [], 32 | "user": { 33 | "id": "USER:nobody" 34 | } 35 | }, 36 | "map_retry": true, 37 | "map_root": { 38 | "enabled": true, 39 | "primary_group": {}, 40 | "secondary_groups": [], 41 | "user": { 42 | "id": "USER:nobody" 43 | } 44 | }, 45 | "max_file_size": 9223372036854775807, 46 | "name_max_size": 255, 47 | "no_truncate": false, 48 | "paths": [ 49 | "/ifs/data/csi-isilon/volume1" 50 | ], 51 | "read_only": false, 52 | "read_only_clients": [], 53 | "read_transfer_max_size": 1048576, 54 | "read_transfer_multiple": 512, 55 | "read_transfer_size": 131072, 56 | "read_write_clients": [], 57 | "readdirplus": true, 58 | "readdirplus_prefetch": 10, 59 | "return_32bit_file_ids": false, 60 | "root_clients": [], 61 | "security_flavors": [ 62 | "unix" 63 | ], 64 | "setattr_asynchronous": false, 65 | "snapshot": "-", 66 | "symlinks": true, 67 | "time_delta": 1.000000000000000e-09, 68 | "unresolved_clients": [], 69 | "write_datasync_action": "DATASYNC", 70 | "write_datasync_reply": "DATASYNC", 71 | "write_filesync_action": "FILESYNC", 72 | "write_filesync_reply": "FILESYNC", 73 | "write_transfer_max_size": 1048576, 74 | "write_transfer_multiple": 512, 75 | "write_transfer_size": 524288, 76 | "write_unstable_action": "UNSTABLE", 77 | "write_unstable_reply": "UNSTABLE", 78 | "zone": "System" 79 | } 80 | ] 81 | } -------------------------------------------------------------------------------- /service/mock/export/get_export_not_found.txt: -------------------------------------------------------------------------------- 1 | { 2 | "digest": "a88ac47374d79dcbf43681a73c90bd29", 3 | "exports": [], 4 | "resume": null, 5 | "total": 0 6 | } -------------------------------------------------------------------------------- /service/mock/export/get_export_snapVol3.txt: -------------------------------------------------------------------------------- 1 | { 2 | "exports": [ 3 | { 4 | "all_dirs": false, 5 | "block_size": 8192, 6 | "can_set_time": true, 7 | "case_insensitive": false, 8 | "case_preserving": true, 9 | "chown_restricted": false, 10 | "clients": [], 11 | "commit_asynchronous": false, 12 | "conflicting_paths": [], 13 | "description": "CSI_QUOTA_ID:AABpAQEAAAAAAAAAAAAAQA0AAAAAAAAA", 14 | "directory_transfer_size": 131072, 15 | "encoding": "DEFAULT", 16 | "id": 557, 17 | "link_max": 32767, 18 | "map_failure": { 19 | "enabled": false, 20 | "primary_group": {}, 21 | "secondary_groups": [], 22 | "user": { 23 | "id": "USER:nobody" 24 | } 25 | }, 26 | "map_full": true, 27 | "map_lookup_uid": false, 28 | "map_non_root": { 29 | "enabled": false, 30 | "primary_group": {}, 31 | "secondary_groups": [], 32 | "user": { 33 | "id": "USER:nobody" 34 | } 35 | }, 36 | "map_retry": true, 37 | "map_root": { 38 | "enabled": true, 39 | "primary_group": {}, 40 | "secondary_groups": [], 41 | "user": { 42 | "id": "USER:nobody" 43 | } 44 | }, 45 | "max_file_size": 9223372036854775807, 46 | "name_max_size": 255, 47 | "no_truncate": false, 48 | "paths": [ 49 | "/ifs/.snapshot/k8s-12345678/volSnap2" 50 | ], 51 | "read_only": false, 52 | "read_only_clients": [], 53 | "read_transfer_max_size": 1048576, 54 | "read_transfer_multiple": 512, 55 | "read_transfer_size": 131072, 56 | "read_write_clients": [], 57 | "readdirplus": true, 58 | "readdirplus_prefetch": 10, 59 | "return_32bit_file_ids": false, 60 | "root_clients": [], 61 | "security_flavors": [ 62 | "unix" 63 | ], 64 | "setattr_asynchronous": false, 65 | "snapshot": "-", 66 | "symlinks": true, 67 | "time_delta": 1.000000000000000e-09, 68 | "unresolved_clients": [], 69 | "write_datasync_action": "DATASYNC", 70 | "write_datasync_reply": "DATASYNC", 71 | "write_filesync_action": "FILESYNC", 72 | "write_filesync_reply": "FILESYNC", 73 | "write_transfer_max_size": 1048576, 74 | "write_transfer_multiple": 512, 75 | "write_transfer_size": 524288, 76 | "write_unstable_action": "UNSTABLE", 77 | "write_unstable_reply": "UNSTABLE", 78 | "zone": "System" 79 | } 80 | ] 81 | } -------------------------------------------------------------------------------- /service/mock/export/get_exports_snapVol2.txt: -------------------------------------------------------------------------------- 1 | { 2 | "exports": [ 3 | { 4 | "all_dirs": false, 5 | "block_size": 8192, 6 | "can_set_time": true, 7 | "case_insensitive": false, 8 | "case_preserving": true, 9 | "chown_restricted": false, 10 | "clients": [], 11 | "commit_asynchronous": false, 12 | "conflicting_paths": [], 13 | "description": "CSI_QUOTA_ID:AABpAQEAAAAAAAAAAAAAQA0AAAAAAARR", 14 | "directory_transfer_size": 131072, 15 | "encoding": "DEFAULT", 16 | "id": 0, 17 | "link_max": 32767, 18 | "map_failure": { 19 | "enabled": false, 20 | "primary_group": {}, 21 | "secondary_groups": [], 22 | "user": { 23 | "id": "USER:nobody" 24 | } 25 | }, 26 | "map_full": true, 27 | "map_lookup_uid": false, 28 | "map_non_root": { 29 | "enabled": false, 30 | "primary_group": {}, 31 | "secondary_groups": [], 32 | "user": { 33 | "id": "USER:nobody" 34 | } 35 | }, 36 | "map_retry": true, 37 | "map_root": { 38 | "enabled": true, 39 | "primary_group": {}, 40 | "secondary_groups": [], 41 | "user": { 42 | "id": "USER:nobody" 43 | } 44 | }, 45 | "max_file_size": 9223372036854775807, 46 | "name_max_size": 255, 47 | "no_truncate": false, 48 | "paths": [ 49 | "/ifs/.snapshot/volSnap2" 50 | ], 51 | "read_only": false, 52 | "read_only_clients": [], 53 | "read_transfer_max_size": 1048576, 54 | "read_transfer_multiple": 512, 55 | "read_transfer_size": 131072, 56 | "read_write_clients": [], 57 | "readdirplus": true, 58 | "readdirplus_prefetch": 10, 59 | "return_32bit_file_ids": false, 60 | "root_clients": [], 61 | "security_flavors": [ 62 | "unix" 63 | ], 64 | "setattr_asynchronous": false, 65 | "snapshot": "-", 66 | "symlinks": true, 67 | "time_delta": 1.000000000000000e-09, 68 | "unresolved_clients": [], 69 | "write_datasync_action": "DATASYNC", 70 | "write_datasync_reply": "DATASYNC", 71 | "write_filesync_action": "FILESYNC", 72 | "write_filesync_reply": "FILESYNC", 73 | "write_transfer_max_size": 1048576, 74 | "write_transfer_multiple": 512, 75 | "write_transfer_size": 524288, 76 | "write_unstable_action": "UNSTABLE", 77 | "write_unstable_reply": "UNSTABLE", 78 | "zone": "System" 79 | } 80 | ] 81 | } 82 | -------------------------------------------------------------------------------- /service/mock/export/get_exports_with_invalid_resume.txt: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "code": "AEC_BAD_REQUEST", 5 | "message": "Invalid resume token" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /service/mock/export/get_exports_with_limit.txt: -------------------------------------------------------------------------------- 1 | { 2 | "digest": "7a06ee50128d105fd6d8a37f0f7e1fa3", 3 | "exports": [ 4 | { 5 | "all_dirs": true, 6 | "block_size": 8192, 7 | "can_set_time": true, 8 | "case_insensitive": false, 9 | "case_preserving": true, 10 | "chown_restricted": false, 11 | "clients": [ 12 | "127.0.0.1" 13 | ], 14 | "commit_asynchronous": false, 15 | "conflicting_paths": [], 16 | "description": "Default export", 17 | "directory_transfer_size": 131072, 18 | "encoding": "DEFAULT", 19 | "id": 1, 20 | "link_max": 32767, 21 | "map_failure": { 22 | "enabled": false, 23 | "primary_group": {}, 24 | "secondary_groups": [], 25 | "user": { 26 | "id": "USER:nobody" 27 | } 28 | }, 29 | "map_full": true, 30 | "map_lookup_uid": false, 31 | "map_non_root": { 32 | "enabled": false, 33 | "primary_group": {}, 34 | "secondary_groups": [], 35 | "user": { 36 | "id": "USER:nobody" 37 | } 38 | }, 39 | "map_retry": true, 40 | "map_root": { 41 | "enabled": true, 42 | "primary_group": {}, 43 | "secondary_groups": [], 44 | "user": { 45 | "id": "USER:nobody" 46 | } 47 | }, 48 | "max_file_size": 9223372036854775807, 49 | "name_max_size": 255, 50 | "no_truncate": false, 51 | "paths": [ 52 | "/ifs" 53 | ], 54 | "read_only": false, 55 | "read_only_clients": [], 56 | "read_transfer_max_size": 1048576, 57 | "read_transfer_multiple": 512, 58 | "read_transfer_size": 131072, 59 | "read_write_clients": [], 60 | "readdirplus": true, 61 | "readdirplus_prefetch": 10, 62 | "return_32bit_file_ids": false, 63 | "root_clients": [], 64 | "security_flavors": [ 65 | "unix" 66 | ], 67 | "setattr_asynchronous": false, 68 | "snapshot": "-", 69 | "symlinks": true, 70 | "time_delta": 1.000000000000000e-09, 71 | "unresolved_clients": [], 72 | "write_datasync_action": "DATASYNC", 73 | "write_datasync_reply": "DATASYNC", 74 | "write_filesync_action": "FILESYNC", 75 | "write_filesync_reply": "FILESYNC", 76 | "write_transfer_max_size": 1048576, 77 | "write_transfer_multiple": 512, 78 | "write_transfer_size": 524288, 79 | "write_unstable_action": "UNSTABLE", 80 | "write_unstable_reply": "UNSTABLE", 81 | "zone": "System" 82 | }, 83 | { 84 | "all_dirs": false, 85 | "block_size": 8192, 86 | "can_set_time": true, 87 | "case_insensitive": false, 88 | "case_preserving": true, 89 | "chown_restricted": false, 90 | "clients": [], 91 | "commit_asynchronous": false, 92 | "conflicting_paths": [], 93 | "description": "", 94 | "directory_transfer_size": 131072, 95 | "encoding": "DEFAULT", 96 | "id": 2, 97 | "link_max": 32767, 98 | "map_failure": { 99 | "enabled": false, 100 | "primary_group": {}, 101 | "secondary_groups": [], 102 | "user": { 103 | "id": "USER:nobody" 104 | } 105 | }, 106 | "map_full": true, 107 | "map_lookup_uid": false, 108 | "map_non_root": { 109 | "enabled": false, 110 | "primary_group": {}, 111 | "secondary_groups": [], 112 | "user": { 113 | "id": "USER:nobody" 114 | } 115 | }, 116 | "map_retry": true, 117 | "map_root": { 118 | "enabled": true, 119 | "primary_group": {}, 120 | "secondary_groups": [], 121 | "user": { 122 | "id": "USER:nobody" 123 | } 124 | }, 125 | "max_file_size": 9223372036854775807, 126 | "name_max_size": 255, 127 | "no_truncate": false, 128 | "paths": [ 129 | "/ifs/data/csi" 130 | ], 131 | "read_only": false, 132 | "read_only_clients": [], 133 | "read_transfer_max_size": 1048576, 134 | "read_transfer_multiple": 512, 135 | "read_transfer_size": 131072, 136 | "read_write_clients": [], 137 | "readdirplus": true, 138 | "readdirplus_prefetch": 10, 139 | "return_32bit_file_ids": false, 140 | "root_clients": [], 141 | "security_flavors": [ 142 | "unix" 143 | ], 144 | "setattr_asynchronous": false, 145 | "snapshot": "-", 146 | "symlinks": true, 147 | "time_delta": 1.000000000000000e-09, 148 | "unresolved_clients": [], 149 | "write_datasync_action": "DATASYNC", 150 | "write_datasync_reply": "DATASYNC", 151 | "write_filesync_action": "FILESYNC", 152 | "write_filesync_reply": "FILESYNC", 153 | "write_transfer_max_size": 1048576, 154 | "write_transfer_multiple": 512, 155 | "write_transfer_size": 524288, 156 | "write_unstable_action": "UNSTABLE", 157 | "write_unstable_reply": "UNSTABLE", 158 | "zone": "System" 159 | } 160 | ], 161 | "resume": "1-1-MAAA1-MAAA1-NwAA1-MgAA1-MgAA0-1-MgAA2-aWQA1-NwAA32-N2EwNmVlNTAxMjhkMTA1ZmQ2ZDhhMzdmMGY3ZTFmYTMA1-MQAA", 162 | "total": 35 163 | } 164 | -------------------------------------------------------------------------------- /service/mock/jobs/created.json: -------------------------------------------------------------------------------- 1 | { 2 | "id" : "20" 3 | } -------------------------------------------------------------------------------- /service/mock/jobs/empty.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs" : [], 3 | "resume" : null, 4 | "total" : 0 5 | } 6 | -------------------------------------------------------------------------------- /service/mock/jobs/running.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs": [ 3 | { 4 | "action": "run", 5 | "ads_streams_replicated": 0, 6 | "block_specs_replicated": 0, 7 | "bytes_recoverable": 0, 8 | "bytes_transferred": 0, 9 | "char_specs_replicated": 0, 10 | "committed_files": 0, 11 | "corrected_lins": 0, 12 | "dead_node": false, 13 | "directories_replicated": 0, 14 | "dirs_changed": 0, 15 | "dirs_deleted": 0, 16 | "dirs_moved": 0, 17 | "dirs_new": 0, 18 | "duration": 1, 19 | "encrypted": false, 20 | "end_time": 1672870562, 21 | "error": "", 22 | "error_checksum_files_skipped": 0, 23 | "error_io_files_skipped": 0, 24 | "error_net_files_skipped": 0, 25 | "errors": [], 26 | "failed_chunks": 0, 27 | "fifos_replicated": 0, 28 | "file_data_bytes": 0, 29 | "files_changed": 0, 30 | "files_linked": 0, 31 | "files_new": 0, 32 | "files_selected": 0, 33 | "files_transferred": 0, 34 | "files_unlinked": 0, 35 | "files_with_ads_replicated": 0, 36 | "flipped_lins": 0, 37 | "hard_links_replicated": 0, 38 | "hash_exceptions_fixed": 0, 39 | "hash_exceptions_found": 0, 40 | "id": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 41 | "job_id": 3, 42 | "lins_total": 0, 43 | "network_bytes_to_source": 0, 44 | "network_bytes_to_target": 0, 45 | "new_files_replicated": 0, 46 | "num_retransmitted_files": 0, 47 | "phases": [], 48 | "policy": { 49 | "action": "sync", 50 | "file_matching_pattern": {}, 51 | "name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 52 | "source_exclude_directories": [], 53 | "source_include_directories": [], 54 | "source_root_path": "/ifs/data/new/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 55 | "target_host": "10.247.100.10", 56 | "target_path": "/ifs/data/new/csi-prov-test-19743d82-192.168.111.25-Five_Minutes" 57 | }, 58 | "policy_action": "sync", 59 | "policy_id": "41c2c9a22de815e045decc0c7605e9f9", 60 | "policy_name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 61 | "quotas_deleted": 0, 62 | "regular_files_replicated": 0, 63 | "resynced_lins": 0, 64 | "retransmitted_files": [], 65 | "retry": 1, 66 | "running_chunks": 0, 67 | "sockets_replicated": 0, 68 | "source_bytes_recovered": 0, 69 | "source_directories_created": 0, 70 | "source_directories_deleted": 0, 71 | "source_directories_linked": 0, 72 | "source_directories_unlinked": 0, 73 | "source_directories_visited": 0, 74 | "source_files_deleted": 0, 75 | "source_files_linked": 0, 76 | "source_files_unlinked": 0, 77 | "sparse_data_bytes": 0, 78 | "start_time": 1672870561, 79 | "state": "running", 80 | "succeeded_chunks": 0, 81 | "symlinks_replicated": 0, 82 | "sync_type": "invalid", 83 | "target_bytes_recovered": 0, 84 | "target_directories_created": 0, 85 | "target_directories_deleted": 0, 86 | "target_directories_linked": 0, 87 | "target_directories_unlinked": 0, 88 | "target_files_deleted": 0, 89 | "target_files_linked": 0, 90 | "target_files_unlinked": 0, 91 | "target_snapshots": [], 92 | "throughput": "0 b/s", 93 | "total_chunks": 0, 94 | "total_data_bytes": 0, 95 | "total_files": 0, 96 | "total_network_bytes": 0, 97 | "total_phases": 0, 98 | "unchanged_data_bytes": 0, 99 | "up_to_date_files_skipped": 0, 100 | "updated_files_replicated": 0, 101 | "user_conflict_files_skipped": 0, 102 | "warnings": [], 103 | "workers": [], 104 | "worm_committed_file_conflicts": 0 105 | } 106 | ], 107 | "resume": null, 108 | "total": 1 109 | } -------------------------------------------------------------------------------- /service/mock/k8s/fakeNodeCreator.go: -------------------------------------------------------------------------------- 1 | package k8s 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | 10 | log "github.com/sirupsen/logrus" 11 | 12 | v1 "k8s.io/api/core/v1" 13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | "k8s.io/client-go/kubernetes/fake" 15 | ) 16 | 17 | // K8sValueFile values file that stories k8s node labels applied 18 | const K8sValueFile = "k8sValues.csv" 19 | 20 | // K8sLabel defines the field label to be used 21 | const K8sLabel = "label" 22 | 23 | // WriteK8sValueToFile writes the values to a file to used in fakeNode 24 | func WriteK8sValueToFile(inputType, value string) { 25 | DeleteK8sValuesFile() 26 | log.Printf("writing k8s values input=%s, value=%s", inputType, value) 27 | pwd, _ := os.Getwd() 28 | log.Printf("cwd is path is %s", pwd) 29 | file, err := os.Create(K8sValueFile) 30 | if err != nil { 31 | log.Printf("Unable to create file to write kubernetes values - %s", err) 32 | } 33 | defer func() { 34 | if err := file.Close(); err != nil { 35 | log.Printf("Error closing file: %s\n", err) 36 | } 37 | }() 38 | valuesCsvStr := fmt.Sprintf("%s,%s", inputType, value) 39 | log.Printf("values str is %s", valuesCsvStr) 40 | _, err = file.WriteString(valuesCsvStr) 41 | if err != nil { 42 | log.Printf("Unable to create file to write kubernetes values - %s", err) 43 | } 44 | absPath, err := filepath.Abs(file.Name()) 45 | if err != nil { 46 | log.Printf("Unable to create abspath of file - %s", err) 47 | } 48 | fmt.Printf("wrote the values to file - %s \n", absPath) 49 | } 50 | 51 | // DeleteK8sValuesFile deletes the values in the file used in fakeNode 52 | func DeleteK8sValuesFile() bool { 53 | abspath, err := filepath.Abs(K8sValueFile) 54 | if err != nil { 55 | log.Errorf("unable get abs path of file for deletion - %s", err) 56 | } 57 | log.Infof("abs path for deletion is %s", abspath) 58 | pwd, _ := os.Getwd() 59 | log.Infof("cwd for deletion is %s", pwd) 60 | err = os.Remove(K8sValueFile) 61 | if err != nil { 62 | log.Errorf("unable to remove file %s - %s", K8sValueFile, err) 63 | return false 64 | } 65 | log.Infof("deleted file %s", abspath) 66 | return true 67 | } 68 | 69 | func readAppliedLabels() (string, string) { 70 | var label string 71 | var value string 72 | abspath, err := filepath.Abs(K8sValueFile) 73 | if err != nil { 74 | log.Errorf("unable to get abs path of filei to read due to - %s", err) 75 | } 76 | log.Infof("abs path to read is is %s", abspath) 77 | pwd, _ := os.Getwd() 78 | log.Infof("cwd while reading is path is %s", pwd) 79 | content, err := os.ReadFile(K8sValueFile) 80 | if err != nil { 81 | log.Errorf("unable to read file - %s", err) 82 | return label, value 83 | } 84 | valueStr := string(content) 85 | log.Infof("content read is %s", valueStr) 86 | values := strings.Split(valueStr, ",") 87 | if len(values) > 0 { 88 | labelnValues := strings.Split(values[1], "=") 89 | if len(labelnValues) > 1 { 90 | label = labelnValues[0] 91 | value = labelnValues[1] 92 | } 93 | } 94 | log.Printf("sent label values %s - %s ", label, value) 95 | return label, value 96 | } 97 | 98 | // GetFakeNode returns a fake node with labels including current hostname 99 | func GetFakeNode() *v1.Node { 100 | client := fake.NewSimpleClientset() 101 | hostname, err := os.Hostname() 102 | if err != nil { 103 | hostname = "fake-host" 104 | log.Errorf("setting hostname as %s as call to get hostname failed", hostname) 105 | } 106 | log.Print(hostname) 107 | labelMap := make(map[string]string) 108 | labelMap["beta.kubernetes.io/arch"] = "amd64" 109 | labelMap["beta.kubernetes.io/os"] = "linux" 110 | labelMap["kubernetes.io/arch"] = "amd64" 111 | labelMap["kubernetes.io/hostname"] = hostname 112 | labelMap["kubernetes.io/os"] = "linux" 113 | label, value := readAppliedLabels() 114 | if label != "" { 115 | fmt.Printf("wrote %s=%s\n", label, value) 116 | labelStr := label 117 | val := "" + value + "" 118 | labelMap[labelStr] = val 119 | } 120 | labelMap["csi-isilon.dellemc.com/127.0.0.1"] = "csi-isilon.dellemc.com" 121 | 122 | node := &v1.Node{ 123 | TypeMeta: metav1.TypeMeta{ 124 | Kind: "Node", 125 | APIVersion: "v1", 126 | }, 127 | ObjectMeta: metav1.ObjectMeta{ 128 | Name: "test-node", 129 | UID: "apple123-6a3b-4e6c-9fc3-a8b9f3ecf8ec", 130 | ResourceVersion: "12628879", 131 | Generation: 0, 132 | CreationTimestamp: metav1.Time{}, 133 | DeletionTimestamp: nil, 134 | DeletionGracePeriodSeconds: nil, 135 | Labels: labelMap, 136 | Annotations: nil, 137 | OwnerReferences: nil, 138 | Finalizers: nil, 139 | // ClusterName: "", 140 | ManagedFields: nil, 141 | }, 142 | Spec: v1.NodeSpec{}, 143 | Status: v1.NodeStatus{}, 144 | } 145 | 146 | fakeNode, err := client.CoreV1().Nodes().Create(context.TODO(), node, metav1.CreateOptions{}) 147 | if err != nil { 148 | log.Errorf("Error occured while creating pod %s: %s", node.Name, err.Error()) 149 | } 150 | return fakeNode 151 | } 152 | -------------------------------------------------------------------------------- /service/mock/loglevel/logBackup.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dell/csi-powerscale/4e69a02c5cf9eb12268b1baa154e1444739bee9d/service/mock/loglevel/logBackup.yaml -------------------------------------------------------------------------------- /service/mock/loglevel/logConfig.yaml: -------------------------------------------------------------------------------- 1 | CSI_LOG_LEVEL: "Debug" 2 | -------------------------------------------------------------------------------- /service/mock/loglevel/logConfigError.yaml: -------------------------------------------------------------------------------- 1 | CSI_LOG_LEVEL: "xyz" 2 | -------------------------------------------------------------------------------- /service/mock/loglevel/logLevelInfo.yaml: -------------------------------------------------------------------------------- 1 | CSI_LOG_LEVEL: "INFO" 2 | -------------------------------------------------------------------------------- /service/mock/policy/empty.txt: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "policies" : 4 | [ 5 | 6 | { 7 | "failover_failback_state" : "writes_disabled", 8 | "id" : "9c9b581c60b4314b21e339796ea66ac7", 9 | "last_job_state" : "finished", 10 | "last_source_coordinator_ip" : "192.168.111.20", 11 | "last_update_from_source" : 1644930873, 12 | "legacy_policy" : false, 13 | "name" : "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 14 | "source_cluster_guid" : "0050568876308e650b62651a8b25f5982d90", 15 | "source_host" : "max", 16 | "target_path" : "/ifs/data/csi/csi-prov-test-19743d82-192-168-111-25-Five_Minutes" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /service/mock/policy/get_policies.txt: -------------------------------------------------------------------------------- 1 | { 2 | "policies": [ 3 | { 4 | "accelerated_failback": false, 5 | "action": "sync", 6 | "bandwidth_reservation": null, 7 | "changelist": false, 8 | "check_integrity": true, 9 | "cloud_deep_copy": "deny", 10 | "conflicted": false, 11 | "database_mirrored": false, 12 | "delete_quotas": true, 13 | "description": "", 14 | "disable_file_split": false, 15 | "disable_fofb": false, 16 | "disable_quota_tmp_dir": false, 17 | "disable_stf": false, 18 | "enable_hash_tmpdir": false, 19 | "enabled": true, 20 | "encrypted": false, 21 | "encryption_cipher_list": "", 22 | "expected_dataloss": false, 23 | "file_matching_pattern": {}, 24 | "force_interface": false, 25 | "has_sync_state": false, 26 | "id": "6e3e43821248d345853c52a04199a163", 27 | "job_delay": 300, 28 | "last_job_state": "failed", 29 | "last_started": 1645532377, 30 | "last_success": null, 31 | "linked_service_policies": [], 32 | "log_level": "notice", 33 | "log_removed_files": false, 34 | "name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 35 | "next_run": 1645533635, 36 | "ocsp_address": "", 37 | "ocsp_issuer_certificate_id": "", 38 | "password_set": false, 39 | "priority": 0, 40 | "report_max_age": 31536000, 41 | "report_max_count": 2000, 42 | "restrict_target_network": false, 43 | "rpo_alert": null, 44 | "schedule": "when-source-modified", 45 | "service_policy": false, 46 | "skip_when_source_unmodified": false, 47 | "snapshot_sync_existing": false, 48 | "snapshot_sync_pattern": "*", 49 | "source_certificate_id": "", 50 | "source_domain_marked": false, 51 | "source_exclude_directories": [], 52 | "source_include_directories": [], 53 | "source_network": null, 54 | "source_root_path": "/ifs/data/new/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 55 | "source_snapshot_archive": false, 56 | "source_snapshot_expiration": 0, 57 | "source_snapshot_pattern": "", 58 | "target_certificate_id": "", 59 | "target_compare_initial_sync": false, 60 | "target_detect_modifications": true, 61 | "target_host": "192.168.111.20", 62 | "target_path": "/ifs/data/new/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 63 | "target_snapshot_alias": "SIQ-%{SrcCluster}-%{PolicyName}-latest", 64 | "target_snapshot_archive": false, 65 | "target_snapshot_expiration": 0, 66 | "target_snapshot_pattern": "SIQ-%{SrcCluster}-%{PolicyName}-%Y-%m-%d_%H-%M-%S", 67 | "workers_per_node": 3 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /service/mock/policy/get_policies2.txt: -------------------------------------------------------------------------------- 1 | { 2 | "policies": [ 3 | { 4 | "accelerated_failback": false, 5 | "action": "sync", 6 | "bandwidth_reservation": null, 7 | "changelist": false, 8 | "check_integrity": true, 9 | "cloud_deep_copy": "deny", 10 | "conflicted": false, 11 | "database_mirrored": false, 12 | "delete_quotas": true, 13 | "description": "", 14 | "disable_file_split": false, 15 | "disable_fofb": false, 16 | "disable_quota_tmp_dir": false, 17 | "disable_stf": false, 18 | "enable_hash_tmpdir": false, 19 | "enabled": false, 20 | "encrypted": false, 21 | "encryption_cipher_list": "", 22 | "expected_dataloss": false, 23 | "file_matching_pattern": {}, 24 | "force_interface": false, 25 | "has_sync_state": false, 26 | "id": "6e3e43821248d345853c52a04199a163", 27 | "job_delay": 300, 28 | "last_job_state": "failed", 29 | "last_started": 1645532377, 30 | "last_success": null, 31 | "linked_service_policies": [], 32 | "log_level": "notice", 33 | "log_removed_files": false, 34 | "name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 35 | "next_run": 1645533635, 36 | "ocsp_address": "", 37 | "ocsp_issuer_certificate_id": "", 38 | "password_set": false, 39 | "priority": 0, 40 | "report_max_age": 31536000, 41 | "report_max_count": 2000, 42 | "restrict_target_network": false, 43 | "rpo_alert": null, 44 | "schedule": "when-source-modified", 45 | "service_policy": false, 46 | "skip_when_source_unmodified": false, 47 | "snapshot_sync_existing": false, 48 | "snapshot_sync_pattern": "*", 49 | "source_certificate_id": "", 50 | "source_domain_marked": false, 51 | "source_exclude_directories": [], 52 | "source_include_directories": [], 53 | "source_network": null, 54 | "source_root_path": "/ifs/data/new/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 55 | "source_snapshot_archive": false, 56 | "source_snapshot_expiration": 0, 57 | "source_snapshot_pattern": "", 58 | "target_certificate_id": "", 59 | "target_compare_initial_sync": false, 60 | "target_detect_modifications": true, 61 | "target_host": "192.168.111.20", 62 | "target_path": "/ifs/data/new/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 63 | "target_snapshot_alias": "SIQ-%{SrcCluster}-%{PolicyName}-latest", 64 | "target_snapshot_archive": false, 65 | "target_snapshot_expiration": 0, 66 | "target_snapshot_pattern": "SIQ-%{SrcCluster}-%{PolicyName}-%Y-%m-%d_%H-%M-%S", 67 | "workers_per_node": 3 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /service/mock/policy/get_policies_sync.txt: -------------------------------------------------------------------------------- 1 | { 2 | "policies": [ 3 | { 4 | "enabled": true, 5 | "name": "vgname", 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /service/mock/policy/get_target_policies.txt: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "policies" : 4 | [ 5 | 6 | { 7 | "failover_failback_state" : "writes_disabled", 8 | "id" : "9c9b581c60b4314b21e339796ea66ac7", 9 | "last_job_state" : "finished", 10 | "last_source_coordinator_ip" : "192.168.111.20", 11 | "last_update_from_source" : 1644930873, 12 | "legacy_policy" : false, 13 | "name" : "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 14 | "source_cluster_guid" : "0050568876308e650b62651a8b25f5982d90", 15 | "source_host" : "max", 16 | "target_path" : "/ifs/data/csi/csi-prov-test-19743d82-192-168-111-25-Five_Minutes" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /service/mock/policy/get_target_policies2.txt: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "policies" : 4 | [ 5 | 6 | { 7 | "failover_failback_state" : "writes_enabled", 8 | "id" : "9c9b581c60b4314b21e339796ea66ac7", 9 | "last_job_state" : "finished", 10 | "last_source_coordinator_ip" : "192.168.111.20", 11 | "last_update_from_source" : 1644930873, 12 | "legacy_policy" : false, 13 | "name" : "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 14 | "source_cluster_guid" : "0050568876308e650b62651a8b25f5982d90", 15 | "source_host" : "max", 16 | "target_path" : "/ifs/data/csi/csi-prov-test-19743d82-192-168-111-25-Five_Minutes" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /service/mock/policy/tp_failed.txt: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "policies" : 4 | [ 5 | 6 | { 7 | "failover_failback_state" : "writes_disabled", 8 | "id" : "9c9b581c60b4314b21e339796ea66ac7", 9 | "last_job_state" : "failed", 10 | "last_source_coordinator_ip" : "192.168.111.20", 11 | "last_update_from_source" : 1644930873, 12 | "legacy_policy" : false, 13 | "name" : "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 14 | "source_cluster_guid" : "0050568876308e650b62651a8b25f5982d90", 15 | "source_host" : "max", 16 | "target_path" : "/ifs/data/csi/csi-prov-test-19743d82-192-168-111-25-Five_Minutes" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /service/mock/quota/create_quota.txt: -------------------------------------------------------------------------------- 1 | { 2 | "id": "AABpAQEAAAAAAAAAAAAAQA0AAAAAAAAA" 3 | } -------------------------------------------------------------------------------- /service/mock/quota/get_quota_by_id.txt: -------------------------------------------------------------------------------- 1 | { 2 | "quotas": [ 3 | { 4 | "container": true, 5 | "enforced": true, 6 | "id": "WACnAAEAAAAAAAAAAAAAQBUPAAAAAAAA", 7 | "include_snapshots": false, 8 | "linked": false, 9 | "notifications": "default", 10 | "path": "/ifs/data/csi/Hui/k8s-37fae6e3fa", 11 | "persona": null, 12 | "ready": true, 13 | "thresholds": { 14 | "advisory": null, 15 | "advisory_exceeded": false, 16 | "advisory_last_exceeded": null, 17 | "hard": 8589934592, 18 | "hard_exceeded": false, 19 | "hard_last_exceeded": null, 20 | "percent_advisory": null, 21 | "percent_soft": null, 22 | "soft": null, 23 | "soft_exceeded": false, 24 | "soft_grace": null, 25 | "soft_last_exceeded": null 26 | }, 27 | "thresholds_include_overhead": false, 28 | "type": "directory", 29 | "usage": { 30 | "inodes": 1, 31 | "logical": 0, 32 | "physical": 2048 33 | } 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /service/mock/quota/get_quota_license.txt: -------------------------------------------------------------------------------- 1 | { 2 | "days_to_expiry": 71, 3 | "expiration": "2019-10-14", 4 | "expired_alert": false, 5 | "expiring_alert": false, 6 | "id": "SMARTQUOTAS", 7 | "name": "SMARTQUOTAS", 8 | "status": "Evaluation", 9 | "tiers": [ 10 | { 11 | "licensed_node_count": 3, 12 | "tier": "NONINF", 13 | "used_node_count": 3 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /service/mock/quota/invalid_quota.txt: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "code": "AEC_NOT_FOUND", 5 | "message": "quota not found:" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /service/mock/quota/quota_not_found.txt: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "code": "AEC_NOT_FOUND", 5 | "message": "Failed to fetch quota domain record: No such file or directory" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /service/mock/report/get_report_by_policy.txt: -------------------------------------------------------------------------------- 1 | { 2 | "reports": [ 3 | { 4 | "action": "run", 5 | "ads_streams_replicated": 0, 6 | "block_specs_replicated": 0, 7 | "bytes_recoverable": 0, 8 | "bytes_transferred": 2443, 9 | "char_specs_replicated": 0, 10 | "committed_files": 0, 11 | "corrected_lins": 0, 12 | "dead_node": false, 13 | "directories_replicated": 2, 14 | "dirs_changed": 1, 15 | "dirs_deleted": 0, 16 | "dirs_moved": 0, 17 | "dirs_new": 1, 18 | "duration": 16, 19 | "encrypted": false, 20 | "end_time": 1680896443, 21 | "error": "", 22 | "error_checksum_files_skipped": 0, 23 | "error_io_files_skipped": 0, 24 | "error_net_files_skipped": 0, 25 | "errors": ["A new quota domain that has not finished QuotaScan has been found"], 26 | "failed_chunks": 0, 27 | "fifos_replicated": 0, 28 | "file_data_bytes": 20, 29 | "files_changed": 0, 30 | "files_linked": 0, 31 | "files_new": 0, 32 | "files_selected": 0, 33 | "files_transferred": 0, 34 | "files_unlinked": 0, 35 | "files_with_ads_replicated": 0, 36 | "flipped_lins": 2, 37 | "hard_links_replicated": 0, 38 | "hash_exceptions_fixed": 0, 39 | "hash_exceptions_found": 0, 40 | "id": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 41 | "job_id": 2, 42 | "lins_total": 2, 43 | "network_bytes_to_source": 716, 44 | "network_bytes_to_target": 1727, 45 | "new_files_replicated": 0, 46 | "num_retransmitted_files": 0, 47 | "phases": [ 48 | { 49 | "end_time": 1680896431, 50 | "phase": "STF_PHASE_SUMM_TREE", 51 | "start_time": 1680896430 52 | }, 53 | { 54 | "end_time": 1680896440, 55 | "phase": "STF_PHASE_IDMAP_SEND", 56 | "start_time": 1680896440 57 | } 58 | ], 59 | "policy": { 60 | "action": "sync", 61 | "file_matching_pattern": {}, 62 | "name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 63 | "source_exclude_directories": [], 64 | "source_include_directories": [], 65 | "source_root_path": "/ifs/data/csi/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 66 | "target_host": "192.168.111.25", 67 | "target_path": "/ifs/data/csi/csi-prov-test-19743d82-192.168.111.25-Five_Minutes" 68 | }, 69 | "policy_action": "sync", 70 | "policy_id": "68bd08fb942c174179a3b76bd0e11a32", 71 | "policy_name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 72 | "quotas_deleted": 0, 73 | "regular_files_replicated": 0, 74 | "resynced_lins": 0, 75 | "retransmitted_files": [], 76 | "retry": 0, 77 | "running_chunks": 0, 78 | "sockets_replicated": 0, 79 | "source_bytes_recovered": 0, 80 | "source_directories_created": 1, 81 | "source_directories_deleted": 0, 82 | "source_directories_linked": 1, 83 | "source_directories_unlinked": 0, 84 | "source_directories_visited": 0, 85 | "source_files_deleted": 0, 86 | "source_files_linked": 0, 87 | "source_files_unlinked": 0, 88 | "sparse_data_bytes": 0, 89 | "start_time": 1680896427, 90 | "state": "finished", 91 | "subreport_count": 1, 92 | "succeeded_chunks": 0, 93 | "symlinks_replicated": 0, 94 | "sync_type": "incremental", 95 | "target_bytes_recovered": 0, 96 | "target_directories_created": 1, 97 | "target_directories_deleted": 0, 98 | "target_directories_linked": 0, 99 | "target_directories_unlinked": 0, 100 | "target_files_deleted": 0, 101 | "target_files_linked": 0, 102 | "target_files_unlinked": 0, 103 | "target_snapshots": [ 104 | "SIQ-Failover-csi-prov-test-19743d82-192-168-111-25-Five_Minutes-2023-04-07_20-18-32" 105 | ], 106 | "total_chunks": 0, 107 | "total_data_bytes": 20, 108 | "total_files": 0, 109 | "total_network_bytes": 2443, 110 | "total_phases": 9, 111 | "unchanged_data_bytes": 0, 112 | "up_to_date_files_skipped": 0, 113 | "updated_files_replicated": 0, 114 | "user_conflict_files_skipped": 0, 115 | "warnings": [], 116 | "worm_committed_file_conflicts": 0 117 | } 118 | ], 119 | "resume": null, 120 | "total": 1 121 | } -------------------------------------------------------------------------------- /service/mock/report/get_report_no_error.txt: -------------------------------------------------------------------------------- 1 | { 2 | "reports": [ 3 | { 4 | "action": "run", 5 | "ads_streams_replicated": 0, 6 | "block_specs_replicated": 0, 7 | "bytes_recoverable": 0, 8 | "bytes_transferred": 2443, 9 | "char_specs_replicated": 0, 10 | "committed_files": 0, 11 | "corrected_lins": 0, 12 | "dead_node": false, 13 | "directories_replicated": 2, 14 | "dirs_changed": 1, 15 | "dirs_deleted": 0, 16 | "dirs_moved": 0, 17 | "dirs_new": 1, 18 | "duration": 16, 19 | "encrypted": false, 20 | "end_time": 1680896443, 21 | "error": "", 22 | "error_checksum_files_skipped": 0, 23 | "error_io_files_skipped": 0, 24 | "error_net_files_skipped": 0, 25 | "errors": [], 26 | "failed_chunks": 0, 27 | "fifos_replicated": 0, 28 | "file_data_bytes": 20, 29 | "files_changed": 0, 30 | "files_linked": 0, 31 | "files_new": 0, 32 | "files_selected": 0, 33 | "files_transferred": 0, 34 | "files_unlinked": 0, 35 | "files_with_ads_replicated": 0, 36 | "flipped_lins": 2, 37 | "hard_links_replicated": 0, 38 | "hash_exceptions_fixed": 0, 39 | "hash_exceptions_found": 0, 40 | "id": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 41 | "job_id": 2, 42 | "lins_total": 2, 43 | "network_bytes_to_source": 716, 44 | "network_bytes_to_target": 1727, 45 | "new_files_replicated": 0, 46 | "num_retransmitted_files": 0, 47 | "phases": [ 48 | { 49 | "end_time": 1680896431, 50 | "phase": "STF_PHASE_SUMM_TREE", 51 | "start_time": 1680896430 52 | }, 53 | { 54 | "end_time": 1680896440, 55 | "phase": "STF_PHASE_IDMAP_SEND", 56 | "start_time": 1680896440 57 | } 58 | ], 59 | "policy": { 60 | "action": "sync", 61 | "file_matching_pattern": {}, 62 | "name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 63 | "source_exclude_directories": [], 64 | "source_include_directories": [], 65 | "source_root_path": "/ifs/data/csi/csi-prov-test-19743d82-192.168.111.25-Five_Minutes", 66 | "target_host": "192.168.111.25", 67 | "target_path": "/ifs/data/csi/csi-prov-test-19743d82-192.168.111.25-Five_Minutes" 68 | }, 69 | "policy_action": "sync", 70 | "policy_id": "68bd08fb942c174179a3b76bd0e11a32", 71 | "policy_name": "csi-prov-test-19743d82-192-168-111-25-Five_Minutes", 72 | "quotas_deleted": 0, 73 | "regular_files_replicated": 0, 74 | "resynced_lins": 0, 75 | "retransmitted_files": [], 76 | "retry": 0, 77 | "running_chunks": 0, 78 | "sockets_replicated": 0, 79 | "source_bytes_recovered": 0, 80 | "source_directories_created": 1, 81 | "source_directories_deleted": 0, 82 | "source_directories_linked": 1, 83 | "source_directories_unlinked": 0, 84 | "source_directories_visited": 0, 85 | "source_files_deleted": 0, 86 | "source_files_linked": 0, 87 | "source_files_unlinked": 0, 88 | "sparse_data_bytes": 0, 89 | "start_time": 1680896427, 90 | "state": "finished", 91 | "subreport_count": 1, 92 | "succeeded_chunks": 0, 93 | "symlinks_replicated": 0, 94 | "sync_type": "incremental", 95 | "target_bytes_recovered": 0, 96 | "target_directories_created": 1, 97 | "target_directories_deleted": 0, 98 | "target_directories_linked": 0, 99 | "target_directories_unlinked": 0, 100 | "target_files_deleted": 0, 101 | "target_files_linked": 0, 102 | "target_files_unlinked": 0, 103 | "target_snapshots": [ 104 | "SIQ-Failover-csi-prov-test-19743d82-192-168-111-25-Five_Minutes-2023-04-07_20-18-32" 105 | ], 106 | "total_chunks": 0, 107 | "total_data_bytes": 20, 108 | "total_files": 0, 109 | "total_network_bytes": 2443, 110 | "total_phases": 9, 111 | "unchanged_data_bytes": 0, 112 | "up_to_date_files_skipped": 0, 113 | "updated_files_replicated": 0, 114 | "user_conflict_files_skipped": 0, 115 | "warnings": [], 116 | "worm_committed_file_conflicts": 0 117 | } 118 | ], 119 | "resume": null, 120 | "total": 1 121 | } -------------------------------------------------------------------------------- /service/mock/secret/secret.yaml: -------------------------------------------------------------------------------- 1 | isilonClusters: 2 | - clusterName: "cluster1" 3 | username: "blah" 4 | password: "blah" 5 | endpoint: "127.0.0.1" 6 | isDefault: true 7 | -------------------------------------------------------------------------------- /service/mock/snapshot/create_snapshot.txt: -------------------------------------------------------------------------------- 1 | { 2 | "created" : 1567491928, 3 | "id" : 34, 4 | "name" : "create_Snapshot_name", 5 | "path" : "/ifs/data/csi-isilon/volume2", 6 | "size" : 4096, 7 | "state" : "active" 8 | } 9 | -------------------------------------------------------------------------------- /service/mock/snapshot/get_existent_compatible_snapshot.txt: -------------------------------------------------------------------------------- 1 | { 2 | "snapshots" : 3 | [ 4 | 5 | { 6 | "created" : 1567061367, 7 | "expires" : null, 8 | "has_locks" : false, 9 | "id" : 3, 10 | "name" : "existent_comp_snapshot_name", 11 | "path" : "/ifs/data/csi-isilon/volume2", 12 | "pct_filesystem" : 8.106093574156148e-09, 13 | "pct_reserve" : 0.0, 14 | "schedule" : null, 15 | "shadow_bytes" : 0, 16 | "size" : 8192, 17 | "state" : "active", 18 | "target_id" : null, 19 | "target_name" : null 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /service/mock/snapshot/get_existent_snapshot_2.txt: -------------------------------------------------------------------------------- 1 | { 2 | "snapshots" : 3 | [ 4 | 5 | { 6 | "created" : 1567061367, 7 | "expires" : null, 8 | "has_locks" : false, 9 | "id" : 2, 10 | "name" : "existent_snapshot_name", 11 | "path" : "/ifs/data/yian/nfs_1", 12 | "pct_filesystem" : 8.106093574156148e-09, 13 | "pct_reserve" : 0.0, 14 | "schedule" : null, 15 | "shadow_bytes" : 0, 16 | "size" : 8192, 17 | "state" : "active", 18 | "target_id" : null, 19 | "target_name" : null 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /service/mock/snapshot/get_existent_snapshot_4.txt: -------------------------------------------------------------------------------- 1 | { 2 | "snapshots" : 3 | [ 4 | { 5 | "created" : 1567061367, 6 | "expires" : null, 7 | "has_locks" : false, 8 | "id" : 4, 9 | "name" : "existent_snapshot_name_4", 10 | "path" : "ifs/data/csi-isilon/childZone/nfs_4", 11 | "pct_filesystem" : 8.106093574156148e-09, 12 | "pct_reserve" : 0.0, 13 | "schedule" : null, 14 | "shadow_bytes" : 0, 15 | "size" : 8192, 16 | "state" : "active", 17 | "target_id" : null, 18 | "target_name" : null 19 | } 20 | 21 | ] 22 | } -------------------------------------------------------------------------------- /service/mock/snapshot/get_non_existent_snapshot.txt: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "code": "AEC_NOT_FOUND", 5 | "message": "new_snapshot_name snapshot not found" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /service/mock/snapshot/get_snapshot_size.txt: -------------------------------------------------------------------------------- 1 | {"children":[{ 2 | "name" : "DELLEMC_UnityFileSra_v6.0.1.85.tar", 3 | "size" : 665332736 4 | } 5 | ,{ 6 | "name" : "t1.txt", 7 | "size" : 138 8 | } 9 | ,{ 10 | "name" : "dir1", 11 | "size" : 24 12 | } 13 | ,{ 14 | "name" : "t2.txt", 15 | "size" : 161 16 | } 17 | ]} 18 | -------------------------------------------------------------------------------- /service/mock/snapshot/get_zone_by_name.txt: -------------------------------------------------------------------------------- 1 | { 2 | "zones" : 3 | [ 4 | { 5 | "alternate_system_provider" : "lsa-file-provider:MinimumRequired", 6 | "auth_providers" : [ "lsa-local-provider:zone2" ], 7 | "cache_entry_expiry" : 14400, 8 | "groupnet" : "groupnet0", 9 | "home_directory_umask" : 63, 10 | "id" : "zone2", 11 | "ifs_restricted" : [], 12 | "map_untrusted" : "", 13 | "name" : "System", 14 | "negative_cache_entry_expiry" : 60, 15 | "netbios_name" : "", 16 | "path" : "/ifs", 17 | "skeleton_directory" : "/usr/share/skel", 18 | "system" : false, 19 | "system_provider" : "lsa-file-provider:System", 20 | "user_mapping_rules" : [], 21 | "zone_id" : 2 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /service/mock/statistics/IO_not_inprogress.txt: -------------------------------------------------------------------------------- 1 | { 2 | "client": [ 3 | { 4 | "class": "other", 5 | "in": 7.800000190734863, 6 | "in_avg": 39.0, 7 | "in_max": 39, 8 | "in_min": 39, 9 | "local_addr": "*", 10 | "local_name": "UNKNOWN", 11 | "node": 1, 12 | "num_operations": 1, 13 | "operation_rate": 0.2000000029802322, 14 | "out": 0.0, 15 | "out_avg": 0.0, 16 | "out_max": 0, 17 | "out_min": 0, 18 | "protocol": "nfs3", 19 | "remote_addr": "127.0.0.1", 20 | "remote_name": "UNKNOWN", 21 | "time": 1651131929, 22 | "time_avg": 7.0, 23 | "time_max": 7, 24 | "time_min": 7, 25 | "user": {} 26 | }, 27 | { 28 | "class": "other", 29 | "in": 0.0, 30 | "in_avg": 0.0, 31 | "in_max": 0, 32 | "in_min": 0, 33 | "local_addr": "*", 34 | "local_name": "UNKNOWN", 35 | "node": 2, 36 | "num_operations": 1, 37 | "operation_rate": 0.2000000029802322, 38 | "out": 7.800000190734863, 39 | "out_avg": 39.0, 40 | "out_max": 39, 41 | "out_min": 39, 42 | "protocol": "siq", 43 | "remote_addr": "*", 44 | "remote_name": "UNKNOWN", 45 | "time": 1651131929, 46 | "time_avg": 68.0, 47 | "time_max": 68, 48 | "time_min": 68, 49 | "user": {} 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /service/mock/volume/get_non_existent_volume.txt: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "code": "AEC_NOT_FOUND", 5 | "message": "Unable to open object 'data/csi-isilon/volume1' in store 'ifs' -- not found." 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /service/mock/volume/get_volume2_without_metadata.txt: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "name": "hello_world.txt" 5 | }, 6 | { 7 | "name": "sub" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /service/mock/volume/get_volume_size.txt: -------------------------------------------------------------------------------- 1 | {"children":[{ 2 | "name" : "d1", 3 | "size" : 40 4 | } 5 | ,{ 6 | "name" : "d2", 7 | "size" : 20 8 | } 9 | ,{ 10 | "name" : "f3", 11 | "size" : 457 12 | } 13 | ,{ 14 | "name" : "f2", 15 | "size" : 457 16 | } 17 | ,{ 18 | "name" : "f1", 19 | "size" : 457 20 | } 21 | ]} 22 | -------------------------------------------------------------------------------- /service/mount_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2025 Dell Inc, or its subsidiaries. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package service 18 | 19 | import ( 20 | "context" 21 | "os" 22 | "testing" 23 | 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | // Split TestMkdir into separate tests to test each case 28 | func TestMkdirCreateDir(t *testing.T) { 29 | ctx := context.Background() 30 | 31 | // Make temp directory to use for testing 32 | basepath, err := os.MkdirTemp("/tmp", "*") 33 | assert.NoError(t, err) 34 | defer os.RemoveAll(basepath) 35 | path := basepath + "/test" 36 | 37 | // Test creating a directory 38 | created, err := mkdir(ctx, path) 39 | assert.NoError(t, err) 40 | assert.True(t, created) 41 | } 42 | 43 | func TestMkdirExistingDir(t *testing.T) { 44 | ctx := context.Background() 45 | 46 | // Make temp directory to use for testing 47 | basepath, err := os.MkdirTemp("/tmp", "*") 48 | assert.NoError(t, err) 49 | defer os.RemoveAll(basepath) 50 | 51 | path := basepath + "/test" 52 | 53 | // Pre-create the directory 54 | err = os.Mkdir(path, 0o755) 55 | assert.NoError(t, err) 56 | 57 | // Test creating an existing directory 58 | created, err := mkdir(ctx, path) 59 | assert.NoError(t, err) 60 | assert.False(t, created) 61 | } 62 | 63 | func TestMkdirExistingFile(t *testing.T) { 64 | ctx := context.Background() 65 | 66 | // Make temp directory to use for testing 67 | basepath, err := os.MkdirTemp("/tmp", "*") 68 | assert.NoError(t, err) 69 | defer os.RemoveAll(basepath) 70 | 71 | path := basepath + "/file" 72 | file, err := os.Create(path) 73 | assert.NoError(t, err) 74 | file.Close() 75 | 76 | // Test creating a directory with an existing file path 77 | created, err := mkdir(ctx, path) 78 | assert.Error(t, err) 79 | assert.False(t, created) 80 | } 81 | 82 | func TestMkdirNotExistingFile(t *testing.T) { 83 | ctx := context.Background() 84 | 85 | // Make temp directory to use for testing 86 | basepath, err := os.MkdirTemp("/tmp", "*") 87 | assert.NoError(t, err) 88 | defer os.RemoveAll(basepath) 89 | 90 | path := "" 91 | file, err := os.Create(path) 92 | assert.Error(t, err) 93 | file.Close() 94 | 95 | // Test creating a directory with an existing file path 96 | created, err := mkdir(ctx, path) 97 | assert.Error(t, err) 98 | assert.False(t, created) 99 | } 100 | -------------------------------------------------------------------------------- /service/test/tmp/datafile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dell/csi-powerscale/4e69a02c5cf9eb12268b1baa154e1444739bee9d/service/test/tmp/datafile -------------------------------------------------------------------------------- /service/test/tmp/datafile2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dell/csi-powerscale/4e69a02c5cf9eb12268b1baa154e1444739bee9d/service/test/tmp/datafile2 -------------------------------------------------------------------------------- /test/helm/.gitignore: -------------------------------------------------------------------------------- 1 | __*__.yaml 2 | 3 | -------------------------------------------------------------------------------- /test/helm/10vols/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: 10vols 2 | version: 1.0.0 3 | appVersion: 1.0.0 4 | description: | 5 | Tests isilon CSI deployments. 6 | keywords: 7 | - csi-isilon 8 | - storage 9 | engine: gotpl 10 | -------------------------------------------------------------------------------- /test/helm/10vols/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol0 5 | namespace: {{ .Values.namespace }} 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | --- 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: pvol1 19 | namespace: {{ .Values.namespace }} 20 | spec: 21 | accessModes: 22 | - ReadWriteOnce 23 | volumeMode: Filesystem 24 | resources: 25 | requests: 26 | storage: 8Gi 27 | storageClassName: isilon 28 | --- 29 | kind: PersistentVolumeClaim 30 | apiVersion: v1 31 | metadata: 32 | name: pvol2 33 | namespace: {{ .Values.namespace }} 34 | spec: 35 | accessModes: 36 | - ReadWriteOnce 37 | volumeMode: Filesystem 38 | resources: 39 | requests: 40 | storage: 8Gi 41 | storageClassName: isilon 42 | --- 43 | kind: PersistentVolumeClaim 44 | apiVersion: v1 45 | metadata: 46 | name: pvol3 47 | namespace: {{ .Values.namespace }} 48 | spec: 49 | accessModes: 50 | - ReadWriteOnce 51 | volumeMode: Filesystem 52 | resources: 53 | requests: 54 | storage: 8Gi 55 | storageClassName: isilon 56 | --- 57 | kind: PersistentVolumeClaim 58 | apiVersion: v1 59 | metadata: 60 | name: pvol4 61 | namespace: {{ .Values.namespace }} 62 | spec: 63 | accessModes: 64 | - ReadWriteOnce 65 | volumeMode: Filesystem 66 | resources: 67 | requests: 68 | storage: 8Gi 69 | storageClassName: isilon 70 | --- 71 | kind: PersistentVolumeClaim 72 | apiVersion: v1 73 | metadata: 74 | name: pvol5 75 | namespace: {{ .Values.namespace }} 76 | spec: 77 | accessModes: 78 | - ReadWriteOnce 79 | volumeMode: Filesystem 80 | resources: 81 | requests: 82 | storage: 8Gi 83 | storageClassName: isilon 84 | --- 85 | kind: PersistentVolumeClaim 86 | apiVersion: v1 87 | metadata: 88 | name: pvol6 89 | namespace: {{ .Values.namespace }} 90 | spec: 91 | accessModes: 92 | - ReadWriteOnce 93 | volumeMode: Filesystem 94 | resources: 95 | requests: 96 | storage: 8Gi 97 | storageClassName: isilon 98 | --- 99 | kind: PersistentVolumeClaim 100 | apiVersion: v1 101 | metadata: 102 | name: pvol7 103 | namespace: {{ .Values.namespace }} 104 | spec: 105 | accessModes: 106 | - ReadWriteOnce 107 | volumeMode: Filesystem 108 | resources: 109 | requests: 110 | storage: 8Gi 111 | storageClassName: isilon 112 | --- 113 | kind: PersistentVolumeClaim 114 | apiVersion: v1 115 | metadata: 116 | name: pvol8 117 | namespace: {{ .Values.namespace }} 118 | spec: 119 | accessModes: 120 | - ReadWriteOnce 121 | volumeMode: Filesystem 122 | resources: 123 | requests: 124 | storage: 8Gi 125 | storageClassName: isilon 126 | --- 127 | kind: PersistentVolumeClaim 128 | apiVersion: v1 129 | metadata: 130 | name: pvol9 131 | namespace: {{ .Values.namespace }} 132 | spec: 133 | accessModes: 134 | - ReadWriteOnce 135 | volumeMode: Filesystem 136 | resources: 137 | requests: 138 | storage: 8Gi 139 | storageClassName: isilon 140 | --- 141 | -------------------------------------------------------------------------------- /test/helm/10vols/templates/test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: isilontest 5 | namespace: {{ .Values.namespace }} 6 | --- 7 | kind: StatefulSet 8 | apiVersion: apps/v1 9 | metadata: 10 | name: isilontest 11 | namespace: {{ .Values.namespace }} 12 | spec: 13 | serviceName: "isilontest" 14 | selector: 15 | matchLabels: 16 | app: isilontest 17 | template: 18 | metadata: 19 | labels: 20 | app: isilontest 21 | spec: 22 | serviceAccount: isilontest 23 | hostNetwork: true 24 | containers: 25 | - name: test 26 | image: quay.io/centos/centos:latest 27 | command: [ "/bin/sleep", "3600" ] 28 | volumeMounts: 29 | - mountPath: "/data0" 30 | name: pvol0 31 | - mountPath: "/data1" 32 | name: pvol1 33 | - mountPath: "/data2" 34 | name: pvol2 35 | - mountPath: "/data3" 36 | name: pvol3 37 | - mountPath: "/data4" 38 | name: pvol4 39 | - mountPath: "/data5" 40 | name: pvol5 41 | - mountPath: "/data6" 42 | name: pvol6 43 | - mountPath: "/data7" 44 | name: pvol7 45 | - mountPath: "/data8" 46 | name: pvol8 47 | - mountPath: "/data9" 48 | name: pvol9 49 | volumes: 50 | - name: pvol0 51 | persistentVolumeClaim: 52 | claimName: pvol0 53 | - name: pvol1 54 | persistentVolumeClaim: 55 | claimName: pvol1 56 | - name: pvol2 57 | persistentVolumeClaim: 58 | claimName: pvol2 59 | - name: pvol3 60 | persistentVolumeClaim: 61 | claimName: pvol3 62 | - name: pvol4 63 | persistentVolumeClaim: 64 | claimName: pvol4 65 | - name: pvol5 66 | persistentVolumeClaim: 67 | claimName: pvol5 68 | - name: pvol6 69 | persistentVolumeClaim: 70 | claimName: pvol6 71 | - name: pvol7 72 | persistentVolumeClaim: 73 | claimName: pvol7 74 | - name: pvol8 75 | persistentVolumeClaim: 76 | claimName: pvol8 77 | - name: pvol9 78 | persistentVolumeClaim: 79 | claimName: pvol9 80 | -------------------------------------------------------------------------------- /test/helm/1vol/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: 1vol 2 | version: 1.0.0 3 | appVersion: 1.0.0 4 | description: | 5 | Test CSI Isilon deployment. 6 | keywords: 7 | - csi-isilon 8 | - storage 9 | engine: gotpl 10 | -------------------------------------------------------------------------------- /test/helm/1vol/templates/createSnapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: pvol0-snap1 5 | namespace: test 6 | spec: 7 | volumeSnapshotClassName: isilon-snapclass 8 | source: 9 | persistentVolumeClaimName: pvol0 10 | -------------------------------------------------------------------------------- /test/helm/1vol/templates/createVolumeFromSnapshot.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-2 5 | namespace: test 6 | spec: 7 | accessModes: 8 | - ReadOnlyMany 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | dataSource: 15 | kind: VolumeSnapshot 16 | name: snap-1 17 | apiGroup: snapshot.storage.k8s.io 18 | -------------------------------------------------------------------------------- /test/helm/1vol/templates/createVolumeFromVolume.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-2 5 | namespace: test 6 | spec: 7 | accessModes: 8 | - ReadOnlyMany 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | dataSource: 15 | kind: PersistentVolumeClaim 16 | name: pvc-1 17 | apiGroup: "" 18 | -------------------------------------------------------------------------------- /test/helm/1vol/templates/pvc0.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol0 5 | namespace: test 6 | spec: 7 | accessModes: 8 | - ReadOnlyMany 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | -------------------------------------------------------------------------------- /test/helm/1vol/templates/test_pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: isilontestpod1 5 | namespace: test 6 | spec: 7 | containers: 8 | - name: test 9 | image: quay.io/centos/centos:latest 10 | command: [ "/bin/sleep", "3600" ] 11 | volumeMounts: 12 | - mountPath: "/data0" 13 | name: pvol0 14 | volumes: 15 | - name: pvol0 16 | persistentVolumeClaim: 17 | claimName: pvol0 18 | -------------------------------------------------------------------------------- /test/helm/1vol/templates/test_statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: isilontest 5 | namespace: test 6 | --- 7 | kind: StatefulSet 8 | apiVersion: apps/v1 9 | metadata: 10 | name: isilontest 11 | namespace: test 12 | spec: 13 | serviceName: "isilontest" 14 | selector: 15 | matchLabels: 16 | app: isilontest 17 | template: 18 | metadata: 19 | labels: 20 | app: isilontest 21 | spec: 22 | serviceAccount: isilontest 23 | hostNetwork: true 24 | containers: 25 | - name: test 26 | image: quay.io/centos/centos:latest 27 | command: [ "/bin/sleep", "3600" ] 28 | volumeMounts: 29 | - mountPath: "/data0" 30 | name: pvol0 31 | volumes: 32 | - name: pvol0 33 | persistentVolumeClaim: 34 | claimName: pvol0 35 | -------------------------------------------------------------------------------- /test/helm/2vols+restore/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: 2vols+restore 2 | version: 1.0.0 3 | appVersion: 1.0.0 4 | description: | 5 | Tests Isilon CSI deployments. 6 | keywords: 7 | - isilon-csi 8 | - storage 9 | engine: gotpl 10 | -------------------------------------------------------------------------------- /test/helm/2vols+restore/templates/createFromSnap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: restorepvc 5 | namespace: test 6 | spec: 7 | storageClassName: isilon 8 | volumeMode: Filesystem 9 | dataSource: 10 | name: pvol0-snap1 11 | kind: VolumeSnapshot 12 | apiGroup: snapshot.storage.k8s.io 13 | accessModes: 14 | - ReadWriteOnce 15 | resources: 16 | requests: 17 | storage: 8Gi 18 | -------------------------------------------------------------------------------- /test/helm/2vols+restore/templates/pvc0.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol0 5 | namespace: test 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | -------------------------------------------------------------------------------- /test/helm/2vols+restore/templates/pvc1.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol1 5 | namespace: test 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 12Gi 13 | storageClassName: isilon 14 | -------------------------------------------------------------------------------- /test/helm/2vols+restore/templates/test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: isilontest 5 | namespace: test 6 | --- 7 | kind: StatefulSet 8 | apiVersion: apps/v1 9 | metadata: 10 | name: isilontest 11 | namespace: test 12 | spec: 13 | serviceName: "isilontest" 14 | selector: 15 | matchLabels: 16 | app: isilontest 17 | template: 18 | metadata: 19 | labels: 20 | app: isilontest 21 | spec: 22 | serviceAccount: isilontest 23 | hostNetwork: true 24 | containers: 25 | - name: test 26 | image: quay.io/centos/centos:latest 27 | command: [ "/bin/sleep", "3600" ] 28 | volumeMounts: 29 | - mountPath: "/data0" 30 | name: pvol0 31 | - mountPath: "/data1" 32 | name: pvol1 33 | - mountPath: "/data2" 34 | name: pvol2 35 | volumes: 36 | - name: pvol0 37 | persistentVolumeClaim: 38 | claimName: pvol0 39 | - name: pvol1 40 | persistentVolumeClaim: 41 | claimName: pvol1 42 | - name: pvol2 43 | persistentVolumeClaim: 44 | claimName: restorepvc 45 | -------------------------------------------------------------------------------- /test/helm/2vols/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: 2vols 2 | version: 1.0.0 3 | appVersion: 1.0.0 4 | description: | 5 | Tests isilon CSI deployments. 6 | keywords: 7 | - csi-isilon 8 | - storage 9 | engine: gotpl 10 | -------------------------------------------------------------------------------- /test/helm/2vols/templates/pvc0.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol0 5 | namespace: {{ .Values.namespace }} 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | -------------------------------------------------------------------------------- /test/helm/2vols/templates/pvc1.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol1 5 | namespace: {{ .Values.namespace }} 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 12Gi 13 | storageClassName: isilon 14 | -------------------------------------------------------------------------------- /test/helm/2vols/templates/test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: isilontest 5 | namespace: {{ .Values.namespace }} 6 | --- 7 | kind: StatefulSet 8 | apiVersion: apps/v1 9 | metadata: 10 | name: isilontest 11 | namespace: {{ .Values.namespace }} 12 | spec: 13 | serviceName: "isilontest" 14 | selector: 15 | matchLabels: 16 | app: isilontest 17 | template: 18 | metadata: 19 | labels: 20 | app: isilontest 21 | spec: 22 | serviceAccount: isilontest 23 | hostNetwork: true 24 | containers: 25 | - name: test 26 | image: quay.io/centos/centos:latest 27 | command: [ "/bin/sleep", "3600" ] 28 | volumeMounts: 29 | - mountPath: "/data0" 30 | name: pvol0 31 | - mountPath: "/data1" 32 | name: pvol1 33 | volumes: 34 | - name: pvol0 35 | persistentVolumeClaim: 36 | claimName: pvol0 37 | - name: pvol1 38 | persistentVolumeClaim: 39 | claimName: pvol1 40 | -------------------------------------------------------------------------------- /test/helm/7vols/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: 7vols 2 | version: 1.0.0 3 | appVersion: 1.0.0 4 | description: | 5 | Tests CSI deployments. 6 | keywords: 7 | - csi-isilon 8 | - storage 9 | engine: gotpl 10 | -------------------------------------------------------------------------------- /test/helm/7vols/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvol0 5 | namespace: {{ .Values.namespace }} 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | storageClassName: isilon 14 | --- 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: pvol1 19 | namespace: {{ .Values.namespace }} 20 | spec: 21 | accessModes: 22 | - ReadWriteOnce 23 | volumeMode: Filesystem 24 | resources: 25 | requests: 26 | storage: 8Gi 27 | storageClassName: isilon 28 | --- 29 | kind: PersistentVolumeClaim 30 | apiVersion: v1 31 | metadata: 32 | name: pvol2 33 | namespace: {{ .Values.namespace }} 34 | spec: 35 | accessModes: 36 | - ReadWriteOnce 37 | volumeMode: Filesystem 38 | resources: 39 | requests: 40 | storage: 8Gi 41 | storageClassName: isilon 42 | --- 43 | kind: PersistentVolumeClaim 44 | apiVersion: v1 45 | metadata: 46 | name: pvol3 47 | namespace: {{ .Values.namespace }} 48 | spec: 49 | accessModes: 50 | - ReadWriteOnce 51 | volumeMode: Filesystem 52 | resources: 53 | requests: 54 | storage: 8Gi 55 | storageClassName: isilon 56 | --- 57 | kind: PersistentVolumeClaim 58 | apiVersion: v1 59 | metadata: 60 | name: pvol4 61 | namespace: {{ .Values.namespace }} 62 | spec: 63 | accessModes: 64 | - ReadWriteOnce 65 | volumeMode: Filesystem 66 | resources: 67 | requests: 68 | storage: 8Gi 69 | storageClassName: isilon 70 | --- 71 | kind: PersistentVolumeClaim 72 | apiVersion: v1 73 | metadata: 74 | name: pvol5 75 | namespace: {{ .Values.namespace }} 76 | spec: 77 | accessModes: 78 | - ReadWriteOnce 79 | volumeMode: Filesystem 80 | resources: 81 | requests: 82 | storage: 8Gi 83 | storageClassName: isilon 84 | --- 85 | kind: PersistentVolumeClaim 86 | apiVersion: v1 87 | metadata: 88 | name: pvol6 89 | namespace: {{ .Values.namespace }} 90 | spec: 91 | accessModes: 92 | - ReadWriteOnce 93 | volumeMode: Filesystem 94 | resources: 95 | requests: 96 | storage: 8Gi 97 | storageClassName: isilon 98 | -------------------------------------------------------------------------------- /test/helm/7vols/templates/test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: isilontest 5 | namespace: {{ .Values.namespace }} 6 | --- 7 | kind: StatefulSet 8 | apiVersion: apps/v1 9 | metadata: 10 | name: isilontest 11 | namespace: {{ .Values.namespace }} 12 | spec: 13 | serviceName: "isilontest" 14 | selector: 15 | matchLabels: 16 | app: isilontest 17 | template: 18 | metadata: 19 | labels: 20 | app: isilontest 21 | spec: 22 | serviceAccount: isilontest 23 | hostNetwork: true 24 | containers: 25 | - name: test 26 | image: quay.io/centos/centos:latest 27 | command: [ "/bin/sleep", "3600" ] 28 | volumeMounts: 29 | - mountPath: "/data0" 30 | name: pvol0 31 | - mountPath: "/data1" 32 | name: pvol1 33 | - mountPath: "/data2" 34 | name: pvol2 35 | - mountPath: "/data3" 36 | name: pvol3 37 | - mountPath: "/data4" 38 | name: pvol4 39 | - mountPath: "/data5" 40 | name: pvol5 41 | - mountPath: "/data6" 42 | name: pvol6 43 | volumes: 44 | - name: pvol0 45 | persistentVolumeClaim: 46 | claimName: pvol0 47 | - name: pvol1 48 | persistentVolumeClaim: 49 | claimName: pvol1 50 | - name: pvol2 51 | persistentVolumeClaim: 52 | claimName: pvol2 53 | - name: pvol3 54 | persistentVolumeClaim: 55 | claimName: pvol3 56 | - name: pvol4 57 | persistentVolumeClaim: 58 | claimName: pvol4 59 | - name: pvol5 60 | persistentVolumeClaim: 61 | claimName: pvol5 62 | - name: pvol6 63 | persistentVolumeClaim: 64 | claimName: pvol6 65 | -------------------------------------------------------------------------------- /test/helm/README.md: -------------------------------------------------------------------------------- 1 | # Various test Helm charts and test scripts 2 | 3 | ## Helm charts 4 | 5 | | Name | Usage | 6 | |---------|-------| 7 | |1vol | Creates 1 filesystem mount | 8 | |2vols | Creates 2 filesystem mounts | 9 | |7vols | Creates 7 filesystem mounts | 10 | |10vols | Creates 10 filesystem mounts | 11 | |2vols+restore | Upgraded version of 2vols that also mounts a volume created from snap | 12 | 13 | ## Scripts 14 | 15 | | Name | Usage | 16 | |----------------|-------| 17 | | deletepvcs.sh | Script to delete all PVCS in a namespace | 18 | | get.volume.ids | Script to list the volume IDs for all PVS | 19 | | logit.sh | Script to print number of pods and pvcs in a namespace | 20 | | starttest.sh | Used to instantiate one of the Helm charts above. Requires argument of Helm chart | 21 | | stoptest.sh | Stops currently running Helm chart and deletes all PVCS | 22 | | snaptest.sh | Script to create volume and snapshot from volume | 23 | | snaprestoretest.sh | Script to instantiate 2vols; then upgrade to 2vols+restore (with volume from snapshot) | 24 | 25 | ## Usage 26 | 27 | The starttest.sh script is used to deploy Helm charts that test the deployment of a simple pod 28 | with various storage configurations. The stoptest.sh script will delete the Helm chart and cleanup after the test. 29 | Procedure 30 | 31 | 1. Navigate to the test/helm directory, which contains the starttest.sh and various Helm charts. 32 | 33 | 2. Run the starttest.sh script with an argument of the specific Helm chart to deploy and test. For example: 34 | 35 | > ./starttest.sh -t 2vols 36 | 37 | 3. After the test has completed, run the stoptest.sh script to delete the Helm chart and cleanup the volumes. 38 | 39 | > ./stoptest.sh -t 2vols 40 | -------------------------------------------------------------------------------- /test/helm/deletepvcs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright © 2019-2020 Dell Inc. or its subsidiaries. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License 14 | 15 | force=no 16 | NAMESPACE="test" 17 | 18 | # Usage information 19 | function usage { 20 | echo 21 | echo "`basename ${0}`" 22 | echo " -n namespace - Namespace in which the release is running. Default is: ${NAMESPACE}" 23 | echo " -f - force delete" 24 | exit 1 25 | } 26 | 27 | # Parse the options passed on the command line 28 | while getopts "fn:" opt; do 29 | case $opt in 30 | n) 31 | NAMESPACE="${OPTARG}" 32 | ;; 33 | f) 34 | force=yes 35 | ;; 36 | \?) 37 | echo "Invalid option: -$OPTARG" >&2 38 | usage 39 | ;; 40 | :) 41 | echo "Option -$OPTARG requires an argument." >&2 42 | usage 43 | ;; 44 | esac 45 | done 46 | 47 | pvcs=$(kubectl get pvc -n $NAMESPACE | awk '/pvol/ { print $1; }') 48 | echo deleting... $pvcs 49 | for pvc in $pvcs 50 | do 51 | if [ $force == "yes" ]; 52 | then 53 | echo kubectl delete --force --grace-period=0 pvc $pvc -n $NAMESPACE 54 | kubectl delete --force --grace-period=0 pvc $pvc -n $NAMESPACE 55 | else 56 | echo kubectl delete pvc $pvc -n $NAMESPACE 57 | kubectl delete pvc $pvc -n $NAMESPACE 58 | fi 59 | done 60 | 61 | -------------------------------------------------------------------------------- /test/helm/get.volume.ids: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ids=$(kubectl describe persistentvolume -n test | grep VolumeHandle | awk ' { print $2; }') 3 | echo ids $ids 4 | ids=$(echo $ids | tr ' ' ',' ) 5 | echo ids $ids 6 | -------------------------------------------------------------------------------- /test/helm/logit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2021 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | while true 15 | do 16 | date 17 | date >>log.output 18 | running=$(kubectl get pods -n test --no-headers=true | grep "Running" | wc -l) 19 | creating=$(kubectl get pods -n test --no-headers=true | grep "ContainerCreating" | wc -l) 20 | pvcs=$(kubectl get pvc -n test --no-headers=true | wc -l) 21 | echo pods running $running, pods creating $creating, pvcs count $pvcs 22 | echo pods running $running, pods creating $creating, pvcs count $pvcs >>log.output 23 | sleep 30 24 | done 25 | 26 | -------------------------------------------------------------------------------- /test/helm/snap1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: pvol0-snap1 5 | namespace: test 6 | spec: 7 | volumeSnapshotClassName: isilon-snapclass 8 | source: 9 | persistentVolumeClaimName: pvol0 10 | -------------------------------------------------------------------------------- /test/helm/snap2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: pvol0-snap2 5 | namespace: test 6 | spec: 7 | volumeSnapshotClassName: isilon-snapclass 8 | source: 9 | persistentVolumeClaimName: pvol0 10 | -------------------------------------------------------------------------------- /test/helm/snaprestoretest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2020 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | echo "installing a 2 volume container" 15 | sh starttest.sh -t 2vols 16 | echo "done installing a 2 volume container" 17 | 18 | echo "marking volume" 19 | kubectl exec -n test isilontest-0 -- touch /data0/orig 20 | kubectl exec -n test isilontest-0 -- ls -l /data0 21 | kubectl exec -n test isilontest-0 -- sync 22 | kubectl exec -n test isilontest-0 -- sync 23 | 24 | echo "creating snap1 of pvol0" 25 | kubectl create -f snap1.yaml 26 | sleep 20 27 | kubectl get volumesnapshot -n test 28 | 29 | echo "updating container to add a volume sourced from snapshot" 30 | helm upgrade 2vols 2vols+restore 31 | echo "waiting for container to upgrade/stabalize" 32 | sleep 20 33 | up=0 34 | while [ $up -lt 1 ]; do 35 | sleep 5 36 | kubectl get pods -n test 37 | up=`kubectl get pods -n test | grep '1/1 *Running' | wc -l` 38 | done 39 | kubectl describe pods -n test 40 | kubectl exec -n test isilontest-0 -it df | grep data 41 | kubectl exec -n test isilontest-0 -it mount | grep data 42 | echo "updating container finished" 43 | 44 | echo "marking volume" 45 | kubectl exec -n test isilontest-0 -- touch /data2/new 46 | echo "listing /data0" 47 | kubectl exec -n test isilontest-0 -- ls -l /data0 48 | echo "listing /data2" 49 | kubectl exec -n test isilontest-0 -- ls -l /data2 50 | sleep 20 51 | 52 | echo "deleting container" 53 | sh stoptest.sh -t 2vols 54 | sleep 5 55 | 56 | echo "deleting snap" 57 | kubectl delete volumesnapshot pvol0-snap1 -n test 58 | -------------------------------------------------------------------------------- /test/helm/snaptest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2020 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | echo "creating snap1 of pvol0" 15 | kubectl create -f snap1.yaml 16 | sleep 10 17 | kubectl get volumesnapshot -n test 18 | kubectl describe volumesnapshot -n test 19 | sleep 10 20 | 21 | echo "creating snap2 of pvol0" 22 | kubectl create -f snap2.yaml 23 | sleep 10 24 | kubectl describe volumesnapshot -n test 25 | sleep 10 26 | 27 | echo "deleting snapshots..." 28 | kubectl delete volumesnapshot pvol0-snap1 -n test 29 | sleep 10 30 | kubectl delete volumesnapshot pvol0-snap2 -n test 31 | sleep 10 32 | kubectl get volumesnapshot -n test 33 | -------------------------------------------------------------------------------- /test/helm/starttest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2020 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | TEST="" 15 | NAMESPACE="test" 16 | 17 | # Usage information 18 | function usage { 19 | echo 20 | echo "`basename ${0}`" 21 | echo " -t test - Test to run. Should be the name of a directory holding a Helm Chart" 22 | echo " -n namespace - Namespace in which to place the test. Default is: ${NAMESPACE}" 23 | exit 1 24 | } 25 | 26 | # Parse the options passed on the command line 27 | while getopts "t:n:" opt; do 28 | case $opt in 29 | t) 30 | TEST="${OPTARG}" 31 | ;; 32 | n) 33 | NAMESPACE="${OPTARG}" 34 | ;; 35 | \?) 36 | echo "Invalid option: -$OPTARG" >&2 37 | usage 38 | ;; 39 | :) 40 | echo "Option -$OPTARG requires an argument." >&2 41 | usage 42 | ;; 43 | esac 44 | done 45 | 46 | waitOnRunning() { 47 | if [ "$1" = "" ]; 48 | then echo "arg: target" ; 49 | exit 2; 50 | fi 51 | WAITINGFOR=$1 52 | 53 | RUNNING=$(kubectl get pods -n "${NAMESPACE}" | grep "Running" | wc -l) 54 | while [ $RUNNING -ne $WAITINGFOR ]; 55 | do 56 | RUNNING=$(kubectl get pods -n "${NAMESPACE}" | grep "Running" | wc -l) 57 | CREATING=$(kubectl get pods -n "${NAMESPACE}" | grep "ContainerCreating" | wc -l) 58 | TERMINATING=$(kubectl get pods -n "${NAMESPACE}" | grep "Terminating" | wc -l) 59 | PVCS=$(kubectl get pvc -n "${NAMESPACE}" | grep -v "STATUS" | wc -l) 60 | date 61 | date >>log.output 62 | echo running $RUNNING creating $CREATING terminating $TERMINATING pvcs $PVCS 63 | echo running $RUNNING creating $CREATING terminating $TERMINATING pvcs $PVCS >>log.output 64 | sleep 30 65 | done 66 | } 67 | 68 | 69 | # Ensure a test was named and that it exists 70 | if [ "${TEST}" == "" ]; then 71 | echo "The name of a test must be specified" 72 | usage 73 | fi 74 | if [ ! -d "${TEST}" ]; then 75 | echo "Unable to find test named: ${TEST}" 76 | usage 77 | fi 78 | 79 | # Validate that the namespace exists 80 | NUM=`kubectl get namespaces | grep "^${NAMESPACE} " | wc -l` 81 | if [ $NUM -ne 1 ]; then 82 | echo "Unable to find a namespace called: ${NAMESPACE}" 83 | exit 1 84 | fi 85 | 86 | # the helm release name will be the basename of the test 87 | RELEASE=`basename "${TEST}"` 88 | 89 | # create a temporary values file to hold the user supplied information 90 | VALUES="__${NAMESPACE}-${RELEASE}__.yaml" 91 | if [ -f "${VALUES}" ]; then 92 | echo "There appears to already be a release/test named ${RELEASE} in namespace ${NAMESPACE}" 93 | echo "Please stop it with the stoptest.sh script before starting another" 94 | exit 1 95 | fi 96 | 97 | echo "namespace: ${NAMESPACE}" >> "${VALUES}" 98 | echo "release: ${RELEASE}" >> "${VALUES}" 99 | 100 | # Start the tests 101 | helm version | grep "v3." --quiet 102 | if [ $? -eq 0 ]; then 103 | helm install "${RELEASE}" -f "${VALUES}" "${TEST}" 104 | else 105 | helm install --name "${RELEASE}" -f "${VALUES}" "${TEST}" 106 | fi 107 | 108 | echo "waiting 60 seconds on pod to initialize" 109 | sleep 60 110 | kubectl describe pods -n "${NAMESPACE}" 111 | waitOnRunning 1 112 | kubectl describe pods -n "${NAMESPACE}" 113 | kubectl exec -n "${NAMESPACE}" isilontest-0 -it df | grep data 114 | kubectl exec -n "${NAMESPACE}" isilontest-0 -it mount | grep data 115 | -------------------------------------------------------------------------------- /test/helm/stoptest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2020 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | TEST="" 15 | NAMESPACE="test" 16 | 17 | # Usage information 18 | function usage { 19 | echo 20 | echo "`basename ${0}`" 21 | echo " -t test - Test to stop" 22 | echo " -n namespace - Namespace in which the release is running. Default is: ${NAMESPACE}" 23 | exit 1 24 | } 25 | 26 | # Parse the options passed on the command line 27 | while getopts "t:n:" opt; do 28 | case $opt in 29 | t) 30 | TEST="${OPTARG}" 31 | ;; 32 | n) 33 | NAMESPACE="${OPTARG}" 34 | ;; 35 | \?) 36 | echo "Invalid option: -$OPTARG" >&2 37 | usage 38 | ;; 39 | :) 40 | echo "Option -$OPTARG requires an argument." >&2 41 | usage 42 | ;; 43 | esac 44 | done 45 | 46 | # Ensure a test was named and that it exists 47 | if [ "${TEST}" == "" ]; then 48 | echo "The name of a test must be specified" 49 | usage 50 | fi 51 | if [ ! -d "${TEST}" ]; then 52 | echo "Unable to find test named: ${TEST}" 53 | usage 54 | fi 55 | 56 | # the helm release name will be the basename of the test 57 | RELEASE=`basename "${TEST}"` 58 | 59 | VALUES="__${NAMESPACE}-${RELEASE}__.yaml" 60 | 61 | helm version | grep "v3." --quiet 62 | if [ $? -eq 0 ]; then 63 | helm delete "${RELEASE}" 64 | else 65 | helm delete --purge "${RELEASE}" 66 | fi 67 | 68 | sleep 10 69 | kubectl get pods -n "${NAMESPACE}" 70 | echo "waiting for persistent volumes to be cleaned up" 71 | sleep 90 72 | sh deletepvcs.sh -n "${NAMESPACE}" 73 | kubectl get persistentvolumes -o wide 74 | 75 | if [ -f "${VALUES}" ]; then 76 | rm "${VALUES}" 77 | fi 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /test/ingestion/README.md: -------------------------------------------------------------------------------- 1 | # Volume Ingestion 2 | This script is for static provisioning in csi-powerscale. You can manage volumes which exist on PowerScale but were created outside of CSI driver. 3 | ## Prerequisites 4 | The NFS export corresponding to the directory needs to exist. It's ID would be used in the volumehandle as described below. It need not have the kubernetes nodes added as clients. 5 | 6 | If Quotas are enabled in the driver, it is recommended that you add the Quota ID to the description of the NFS export in the following format: 7 | CSI_QUOTA_ID:sC-kAAEAAAAAAAAAAAAAQEpVAAAAAAAA 8 | 9 | The details of various Quotas can be obtained via the following REST API of OneFS: 10 | GET 11 | /platform/1/quota/quotas 12 | 13 | Starting from csi-powerscale 1.5, volume handle should include cluster name also (due to multi array support) 14 | 15 | Volume Handle is expected to be present in this pattern VolName + VolumeIDSeparator + exportID + VolumeIDSeparator + accessZone + clusterName for ex. "demovol1=\_=\_=303=\_=\_=System_=\_=cluster" 16 | 17 | ## Running the script 18 | Command Line inputs are taken in this order: volumename, volumehandle, storageclassname, accessmode, storage size, pvname, pvcname 19 | ## Examples 20 | To provision a Volume named sample14 in access zone csi-zone having export-id as 6 and cluster name 'cluster1', volumehandle will be sample14=\_=\_=6=\_=\_=csi-zone=\_=\_=cluster1. Here we are using a custom storage class named as customstorageclass1, access mode as ReadWriteMany, storage size as 500M, pv name as pv1, pvc name as pvc1, we will be running : 21 | 22 | ./ingestion_test.sh sample14 sample14=\_=\_=6=\_=\_=csi-zone=\_=\_=cluster1 customstorageclass1 ReadWriteMany 500M pv1 pvc1 23 | -------------------------------------------------------------------------------- /test/ingestion/ingestion_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright © 2020-2021 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # volumename volumehandle storageclass accessmode storagesize pvname pvcname clustername 15 | # 1 2 3 4 5 6 7 8 16 | 17 | if [[ $2 =~ ^[a-zA-Z0-9_-]+=_=_=[0-9]+=_=_=[a-zA-Z0-9_-]+=_=_=[a-zA-Z0-9_-]+$ ]] 18 | then 19 | echo "Volume handle pattern matched" 20 | 21 | #getting ip from storageclass: 22 | ip=$(kubectl get storageclass $3 -o yaml| grep AzServiceIP: | tail -1 | cut -d ':' -f 2,2| sed -e 's/^[[:space:]]*//' ) 23 | 24 | #getting path from storageclass 25 | pathnew=$(kubectl get storageclass $3 -o yaml| grep IsiPath: | tail -1 | cut -d ':' -f 2,2| sed -e 's/^[[:space:]]*//' ) 26 | path="$pathnew/$1" 27 | 28 | #getting accesszone from storage class 29 | acz=$(kubectl get storageclass $3 -o yaml| grep AccessZone: |cut -d ':' -f 2,2| sed -e 's/^[[:space:]]*//' ) 30 | 31 | cat < static_pv_$6.yaml 32 | apiVersion: v1 33 | kind: PersistentVolume 34 | metadata: 35 | name: $6 36 | namespace: default 37 | spec: 38 | capacity: 39 | storage: "$5" 40 | accessModes: 41 | - "$4" 42 | persistentVolumeReclaimPolicy: Retain 43 | storageClassName: $3 44 | csi: 45 | driver: csi-isilon.dellemc.com 46 | volumeAttributes: 47 | Path: "$path" 48 | Name: "$1" 49 | AzServiceIP: '$ip' 50 | volumeHandle: $2 51 | claimRef: 52 | name: $7 53 | namespace: default 54 | EOF 55 | 56 | cat < static_pvc_$7.yaml 57 | apiVersion: v1 58 | kind: PersistentVolumeClaim 59 | metadata: 60 | name: $7 61 | namespace: default 62 | spec: 63 | accessModes: 64 | - "$4" 65 | resources: 66 | requests: 67 | storage: "$5" 68 | volumeName: "$6" 69 | EOF 70 | 71 | cat < static_pod.yaml 72 | apiVersion: v1 73 | kind: Pod 74 | metadata: 75 | name: testpod-script 76 | namespace: default 77 | spec: 78 | containers: 79 | - name: task-pv-containe 80 | image: nginx 81 | ports: 82 | - containerPort: 80 83 | name: "http-server" 84 | volumeMounts: 85 | - mountPath: "/usr/share/nginx/html" 86 | name: nov-eleventh-1-pv-storage 87 | volumes: 88 | - name: nov-eleventh-1-pv-storage 89 | persistentVolumeClaim: 90 | claimName: $7 91 | EOF 92 | 93 | kubectl create -f static_pv_$6.yaml 94 | echo "Persistent Volume $6 creation successful" 95 | kubectl create -f static_pvc_$7.yaml 96 | echo "Persistent Volume Claim $7 creation successful" 97 | kubectl create -f static_pod.yaml 98 | echo "Pod created successfully with ingested volume" 99 | 100 | #cleaning files created: 101 | rm -rf static_pv_$6.yaml static_pvc_$7.yaml static_pod.yaml 102 | 103 | else 104 | echo "Volume handle $2 pattern does not matched the regex: ^[a-zA-Z0-9_-]+=_=_=+[0-9]*=_=_=+[a-zA-Z0-9_-]+$" 105 | echo "Volume handle is expected in this format: demovol=_=_=251=_=_=System" 106 | 107 | fi 108 | echo "done" 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /test/ingestion/sample/isilonstaticpv.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: isilonstaticpv 5 | namespace: default 6 | spec: 7 | capacity: 8 | storage: 5Gi 9 | accessModes: 10 | - ReadWriteMany 11 | persistentVolumeReclaimPolicy: Retain 12 | storageClassName: isilon 13 | csi: 14 | driver: csi-isilon.dellemc.com 15 | volumeAttributes: 16 | Path: "/ifs/data/csi/isilonvol" 17 | Name: "isilonvol" 18 | AzServiceIP: "XX.XX.XX.XX" 19 | volumeHandle: isilonvol=_=_=652=_=_=System=_=_=cluster 20 | claimRef: 21 | name: isilonstaticpvc 22 | namespace: default 23 | -------------------------------------------------------------------------------- /test/ingestion/sample/isilonstaticpvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: isilonstaticpvc 5 | namespace: default 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 5Gi 12 | volumeName: isilonstaticpv 13 | storageClassName: isilon 14 | -------------------------------------------------------------------------------- /test/integration/README.md: -------------------------------------------------------------------------------- 1 | # Integration test for CSI PowerScale driver 2 | 3 | This test is run on a Kubernetes node, this will make real calls to the 4 | PowerScale. 5 | 6 | There are four scripts to set environment variables, env_Quota_Enabled.sh, env_Quota_notEnabled.sh, env_nodeIP1.sh, env_nodeIP2.sh. All files should be populated with values for PowerScale. env_Quota_Enabled.sh is used for Quota enabled, env_Quota_notEnabled.sh is for Quota not enabled. The file env_nodeIP1.sh and file env_nodeIP2.sh added to mock different node IPs for NodeStageVolume with different accessModes, the corresponding feature file is mock_different_nodeIPs.feature. The file main_integration.feature is used to test most scenarios. 7 | 8 | There is a config file to set secrets details, either this file can be updated or the path for the same can be updated in all the environment files, under the variable name 'X_CSI_ISI_CONFIG_PATH' 9 | 10 | To launch the integration test, just run `make integration-test` from csi-powerscale root directory. Whichever environment script, feature file and tag needed can be specified in this script. 11 | -------------------------------------------------------------------------------- /test/integration/config: -------------------------------------------------------------------------------- 1 | isilonClusters: 2 | - clusterName: "cluster1" 3 | username: "user" 4 | password: "password" 5 | isDefault: true 6 | endpoint: "1.2.3.4" 7 | skipCertificateValidation: true 8 | - clusterName: "cluster2" 9 | username: "user" 10 | password: "password" 11 | isDefault: false 12 | endpoint: "1.2.3.5" 13 | skipCertificateValidation: true 14 | -------------------------------------------------------------------------------- /test/integration/env_Custom_Topology_Enabled.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # This should be like 111.222.333.444 15 | export X_CSI_CLUSTER_NAME="cluster1" 16 | export X_CSI_ISI_PATH="/ifs/data/csi/integration" 17 | export X_CSI_ISI_PORT="8080" 18 | export X_CSI_ISI_QUOTA_ENABLED="true" 19 | export X_CSI_CUSTOM_TOPOLOGY_ENABLED="true" 20 | export X_CSI_NODE_IP=`hostname -I | head -1 | awk ' { print $1; } '` 21 | NODENAME=`hostname` 22 | export X_CSI_NODE_NAME=$NODENAME 23 | export X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION="true" 24 | export X_CSI_ISI_AUTOPROBE="true" 25 | export X_CSI_ISI_NO_PROBE_ON_START="false" 26 | export X_CSI_MODE="" 27 | export X_CSI_ISI_CONFIG_PATH=`pwd`/config 28 | 29 | # Variables for using tests 30 | export CSI_ENDPOINT=`pwd`/unix_sock 31 | -------------------------------------------------------------------------------- /test/integration/env_Quota_Enabled.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # This should be like 111.222.333.444 15 | export X_CSI_CLUSTER_NAME="cluster1" 16 | export X_CSI_ISI_PATH="/ifs/data/csi/integration" 17 | export X_CSI_ISI_PORT="8080" 18 | export X_CSI_ISI_QUOTA_ENABLED="true" 19 | export X_CSI_NODE_IP=`hostname -I | head -1 | awk ' { print $1; } '` 20 | NODEFQDN=`hostname -f` 21 | NODENAME=`hostname` 22 | SEPARATOR="=#=#=" 23 | NODEID=$NODENAME$SEPARATOR$NODEFQDN$SEPARATOR$X_CSI_NODE_IP 24 | export X_CSI_NODE_NAME=$NODEID 25 | export X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION="true" 26 | export X_CSI_ISI_AUTOPROBE="true" 27 | export X_CSI_ISI_NO_PROBE_ON_START="false" 28 | export X_CSI_MODE="" 29 | export X_CSI_ISI_CONFIG_PATH=`pwd`/config 30 | export X_CSI_ISI_ACCESS_ZONE="integration-test-zone" 31 | export X_CSI_ISI_AZ_SERVICE_IP="1.2.3.4" 32 | 33 | # Variables for using tests 34 | export CSI_ENDPOINT=`pwd`/unix_sock 35 | -------------------------------------------------------------------------------- /test/integration/env_Quota_notEnabled.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # This should be like 111.222.333.444 15 | export X_CSI_CLUSTER_NAME="cluster1" 16 | export X_CSI_ISI_PATH="/ifs/data/csi/integration" 17 | export X_CSI_ISI_PORT="8080" 18 | export X_CSI_ISI_QUOTA_ENABLED="false" 19 | export X_CSI_NODE_IP=`hostname -I | head -1 | awk ' { print $1; } '` 20 | NODEFQDN=`hostname -f` 21 | NODENAME=`hostname` 22 | SEPARATOR="=#=#=" 23 | NODEID=$NODENAME$SEPARATOR$NODEFQDN$SEPARATOR$X_CSI_NODE_IP 24 | export X_CSI_NODE_NAME=$NODEID 25 | export X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION="true" 26 | export X_CSI_ISI_AUTOPROBE="true" 27 | export X_CSI_ISI_NO_PROBE_ON_START="false" 28 | export X_CSI_MODE="" 29 | export X_CSI_ISI_CONFIG_PATH=`pwd`/config 30 | export X_CSI_ISI_ACCESS_ZONE="integration-test-zone" 31 | export X_CSI_ISI_AZ_SERVICE_IP="1.2.3.4" 32 | 33 | # Variables for using tests 34 | export CSI_ENDPOINT=`pwd`/unix_sock 35 | -------------------------------------------------------------------------------- /test/integration/env_nodeIP1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # This is used for mocking different node IPs in order to test accessModes 15 | 16 | # This should be like 111.222.333.444 17 | export X_CSI_CLUSTER_NAME="cluster1" 18 | export X_CSI_ISI_PATH="/ifs/data/csi/integration" 19 | export X_CSI_ISI_PORT="8080" 20 | export X_CSI_ISI_QUOTA_ENABLED="false" 21 | export X_CSI_NODE_IP="1.1.1.2" 22 | NODEFQDN=`hostname -f` 23 | NODENAME=`hostname` 24 | SEPARATOR="=#=#=" 25 | NODEID=$NODENAME$SEPARATOR$NODEFQDN$SEPARATOR$X_CSI_NODE_IP 26 | export X_CSI_NODE_NAME=$NODEID 27 | export X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION="true" 28 | export X_CSI_ISI_AUTOPROBE="true" 29 | export X_CSI_ISI_NO_PROBE_ON_START="false" 30 | export X_CSI_MODE="" 31 | export X_CSI_ISI_CONFIG_PATH=`pwd`/config 32 | export X_CSI_ISI_ACCESS_ZONE="integration-test-zone" 33 | export X_CSI_ISI_AZ_SERVICE_IP="1.2.3.4" 34 | 35 | # Variables for using tests 36 | export CSI_ENDPOINT=`pwd`/unix_sock 37 | -------------------------------------------------------------------------------- /test/integration/env_nodeIP2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2022 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # This is used for mocking different node IPs in order to test accessModes 15 | 16 | # This should be like 111.222.333.444 17 | export X_CSI_CLUSTER_NAME="cluster1" 18 | export X_CSI_ISI_PATH="/ifs/data/csi/integration" 19 | export X_CSI_ISI_PORT="8080" 20 | export X_CSI_ISI_QUOTA_ENABLED="false" 21 | export X_CSI_NODE_NAME="xyz=#=#=xyz.com=#=#=1.1.1.2" 22 | export X_CSI_NODE_IP="1.1.1.2" 23 | export X_CSI_ISI_SKIP_CERTIFICATE_VALIDATION="true" 24 | export X_CSI_ISI_AUTOPROBE="true" 25 | export X_CSI_ISI_NO_PROBE_ON_START="false" 26 | export X_CSI_MODE="" 27 | export X_CSI_ISI_CONFIG_PATH=`pwd`/config 28 | export X_CSI_ISI_ACCESS_ZONE="integration-test-zone" 29 | export X_CSI_ISI_AZ_SERVICE_IP="1.2.3.4" 30 | 31 | # Variables for using tests 32 | export CSI_ENDPOINT=`pwd`/unix_sock 33 | -------------------------------------------------------------------------------- /test/integration/features/integration.feature: -------------------------------------------------------------------------------- 1 | Feature: Isilon CSI interface 2 | As a consumer of the CSI interface 3 | I want to run a system test 4 | So that I know the service functions correctly 5 | 6 | @v1.0 7 | Scenario: Create and delete basic volume with/without Quota enabled 8 | Given a Isilon service 9 | And a basic volume request "integration0" "8" 10 | When I call CreateVolume 11 | Then there is a directory "integration0" 12 | Then there is an export "integration0" 13 | Then verify "integration0" size 14 | When I call DeleteVolume 15 | And there is not an export "integration0" 16 | And there is not a quota "integration0" 17 | Then there are no errors 18 | 19 | @v1.0 20 | Scenario: Idempotent create and delete basic volume with/without Quota enabled 21 | Given a Isilon service 22 | And a basic volume request "integration0" "8" 23 | When I call CreateVolume 24 | When I call CreateVolume 25 | Then there is a directory "integration0" 26 | Then there is an export "integration0" 27 | Then verify "integration0" size 28 | When I call DeleteVolume 29 | When I call DeleteVolume 30 | Then there is not a directory "integration0" 31 | Then there is not an export "integration0" 32 | 33 | @v1.0 34 | Scenario: Create volume, create snapshot, create volume from snapshot, delete original volume, delete new volume 35 | Given a Isilon service 36 | And a basic volume request "integration0" "8" 37 | When I call CreateVolume 38 | Then there is a directory "integration0" 39 | Then there is an export "integration0" 40 | Then verify "integration0" size 41 | When I call CreateSnapshot "snapshot0" "integration0" 42 | Then there is a snapshot "snapshot0" 43 | When I call CreateVolumeFromSnapshot "volFromSnap0" 44 | Then there is a directory "volFromSnap0" 45 | And there is an export "volFromSnap0" 46 | And verify "volFromSnap0" size 47 | When I call DeleteSnapshot 48 | Then there is not a snapshot "snapshot0" 49 | When I call DeleteVolume 50 | Then there is not a directory "volFromSnap0" 51 | And there is not an export "volFromSnap0" 52 | And there is not a quota "volFromSnap0" 53 | When I call DeleteAllVolumes 54 | Then there are no errors 55 | 56 | @v1.0 57 | Scenario Outline: Create, ControllerPublish, NodeStage, NodePublish, NodeUnpublish, NodeUnstage, ControllerUnpublish, delete basic volume 58 | Given a Isilon service 59 | And a capability with access 60 | And a volume request "integration0" "8" 61 | When I call CreateVolume 62 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 63 | Then check Isilon client exists "X_CSI_NODE_NAME" 64 | When I call NodeStageVolume 65 | Then there are no errors 66 | When I call NodePublishVolume "datadir0" 67 | Then verify published volume with access "datadir0" 68 | When I call NodeUnpublishVolume "datadir0" 69 | Then verify not published volume with access "datadir0" 70 | When I call NodeUnstageVolume 71 | Then there are no errors 72 | When I call ControllerUnpublishVolume "X_CSI_NODE_NAME" 73 | Then check Isilon client not exists "X_CSI_NODE_IP" 74 | When I call DeleteVolume 75 | Then there is not a directory "integration0" 76 | Then there is not an export "integration0" 77 | 78 | Examples: 79 | | access | 80 | | "single-writer" | 81 | | "multi-reader" | 82 | | "multi-writer" | 83 | -------------------------------------------------------------------------------- /test/integration/features/mock_different_nodeIPs.feature: -------------------------------------------------------------------------------- 1 | Feature: Isilon CSI interface 2 | As a consumer of the CSI interface 3 | I want to run a system test 4 | So that I know the service functions correctly 5 | 6 | @first_run 7 | Scenario: Create, ControllerPublish, NodeStage, NodeUnstage, ControllerUnpublish, delete basic volume with accessMode multi-reader 8 | Given a Isilon service 9 | And a capability with access "multi-reader" 10 | And a volume request "integration0" "8" 11 | When I call CreateVolume 12 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 13 | Then check Isilon client exists "X_CSI_NODE_NAME" 14 | When I call NodeStageVolume 15 | Then there are no errors 16 | 17 | @first_run 18 | Scenario: Create, ControllerPublish, NodeStage, NodeUnstage, ControllerUnpublish, delete basic volume with accessMode multi-writer 19 | Given a Isilon service 20 | And a capability with access "multi-writer" 21 | And a volume request "integration1" "8" 22 | When I call CreateVolume 23 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 24 | Then check Isilon client exists "X_CSI_NODE_NAME" 25 | When I call NodeStageVolume 26 | Then there are no errors 27 | 28 | @first_run 29 | Scenario: Create, ControllerPublish, NodeStage, NodeUnstage, ControllerUnpublish, delete basic volume with accessMode single-writer 30 | Given a Isilon service 31 | And a capability with access "single-writer" 32 | And a volume request "integration2" "8" 33 | When I call CreateVolume 34 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 35 | Then check Isilon client exists "X_CSI_NODE_NAME" 36 | When I call NodeStageVolume 37 | Then there are no errors 38 | 39 | @second_run 40 | Scenario: Create, ControllerPublish, NodeStage, NodeUnstage, ControllerUnpublish, delete basic volume with accessMode multi-reader 41 | Given a Isilon service 42 | And a capability with access "multi-reader" 43 | And a volume request "integration0" "8" 44 | When I call CreateVolume 45 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 46 | Then check Isilon client exists "X_CSI_NODE_NAME" 47 | When I call NodeStageVolume 48 | Then there are no errors 49 | When I call NodeUnstageVolume 50 | Then there are no errors 51 | When I call ControllerUnpublishVolume "X_CSI_NODE_NAME" 52 | Then check Isilon client not exists "X_CSI_NODE_NAME" 53 | When I call DeleteVolume 54 | Then there is not a directory "integration0" 55 | Then there is not an export "integration0" 56 | 57 | @second_run 58 | Scenario: Create, ControllerPublish, NodeStage, NodeUnstage, ControllerUnpublish, delete basic volume with accessMode multi-writer 59 | Given a Isilon service 60 | And a capability with access "multi-writer" 61 | And a volume request "integration1" "8" 62 | When I call CreateVolume 63 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 64 | Then check Isilon client exists "X_CSI_NODE_NAME" 65 | When I call NodeStageVolume 66 | Then there are no errors 67 | When I call NodeUnstageVolume 68 | Then there are no errors 69 | When I call ControllerUnpublishVolume "X_CSI_NODE_NAME" 70 | Then check Isilon client not exists "X_CSI_NODE_NAME" 71 | When I call DeleteVolume 72 | Then there is not a directory "integration1" 73 | Then there is not an export "integration1" 74 | 75 | @second_run 76 | Scenario: Create, ControllerPublish, NodeStage, NodeUnstage, ControllerUnpublish, delete basic volume with accessMode single-writer 77 | Given a Isilon service 78 | And a capability with access "single-writer" 79 | And a volume request "integration2" "8" 80 | When I call CreateVolume 81 | When I call ControllerPublishVolume "X_CSI_NODE_NAME" 82 | Then the error contains "already has other clients added to it, and the access mode is SINGLE_NODE_WRITER" 83 | When I call ControllerUnpublishVolume "X_CSI_NODE_NAME" 84 | Then check Isilon client not exists "X_CSI_NODE_NAME" 85 | When I call DeleteVolume 86 | Then there is not a directory "integration2" 87 | Then there is not an export "integration2" 88 | -------------------------------------------------------------------------------- /test/integration/kubevirt/README.md: -------------------------------------------------------------------------------- 1 | # KubeVirt Qual files for CSI PowerScale driver for OpenShift virtualization CSI certification tests 2 | 3 | Check https://confluence.cec.lab.emc.com/display/CSIECO/KubeVirt for details on running KubeVirt tests. 4 | 5 | manifest.yaml - use this file as an input to the Kubevirt test. 6 | isilon-sc.yaml - This storage class yaml is referred to by the manifest and used by the test. Ensure the Directory already exists on the array, or rename it. 7 | -------------------------------------------------------------------------------- /test/integration/kubevirt/isilon-sc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: isilon 5 | allowVolumeExpansion: true 6 | parameters: 7 | AccessZone: System 8 | # Make sure this directory exists on the array before using 9 | IsiPath: /ifs/data/qual 10 | RootClientEnabled: "true" 11 | provisioner: csi-isilon.dellemc.com 12 | reclaimPolicy: Delete 13 | volumeBindingMode: WaitForFirstConsumer 14 | -------------------------------------------------------------------------------- /test/integration/kubevirt/manifest.yaml: -------------------------------------------------------------------------------- 1 | ShortName: isilon 2 | StorageClass: 3 | # Load a StorageClass from the given file. This file must be in the same directory as this one 4 | FromFile: isilon-sc.yaml 5 | 6 | SnapshotClass: 7 | # Must be set to enable snapshotting tests 8 | FromName: false 9 | 10 | DriverInfo: 11 | # Internal name of the driver, this is used as a display name in the test case and test objects 12 | Name: isilon 13 | 14 | # The range of disk size supported by this driver. Note that Min must be the EXACT size of a volume 15 | # that can be provisioned by the CSI driver. For example, when the driver requires volume sizes to be 16 | # rounded to a certain value (typically 1 or 4 GiB), Min must be rounded to that value. A test will 17 | # check that when it asks for a volume with size Min, it will get the volume with exactly that size. 18 | SupportedSizeRange: 19 | Min: 5Gi 20 | Max: 16Ti 21 | 22 | # Map of strings for supported FS types PowerScale supports nfs for sure, not sure about the others 23 | SupportedFsType: 24 | nfs: {} 25 | 26 | # Map of strings for supported mount options. This will be used to test that the CSI driver correctly 27 | # passes a mount option from Kubernetes to the kernel mount table. The mount options listed here must be: 28 | # 1. Supported by both the CSI driver and the kernel. 29 | # 2. Non-default. Note that the real set of all default mount options depends on the kernel and filesystem type. 30 | # 3. Visible in /proc/mounts after mount. 31 | # 4. Harmless, i.e., the mount option should not affect how the storage behaves too much. 32 | SupportedMountOption: 33 | noatime: {} 34 | 35 | # Optional list of topology keys that the driver supports 36 | # TopologyKeys: ["topology.ebs.csi.aws.com/zone"] 37 | TopologyKeys: 38 | 39 | # Optional number of allowed topologies that the driver requires. Only relevenat if TopologyKeys is set 40 | NumAllowedTopologies: 1 41 | 42 | # Map of strings for required mount options 43 | # RequiredMountOption: 44 | 45 | # Optional list of access modes required for provisiong. Default is RWO 46 | # RequiredAccessModes: 47 | 48 | # Map that represents the capabilities the driver supports 49 | Capabilities: 50 | # Data is persistest accross pod restarts 51 | persistence: true 52 | 53 | # Volume ownership via fsGroup 54 | fsGroup: false 55 | 56 | # Raw block mode - PowerScale does not support raw block volume 57 | block: false 58 | 59 | # Exec a file in the volume 60 | exec: true 61 | 62 | # Support for volume limits 63 | volumeLimits: false 64 | 65 | # Support for volume expansion in controllers 66 | controllerExpansion: false 67 | 68 | # Support for volume expansion in nodes 69 | nodeExpansion: false 70 | 71 | # Support volume that an run on single node only (like hostpath) 72 | singleNodeVolume: false 73 | 74 | # Support ReadWriteMany access modes (runs the mulit pod test which fails to clean up) 75 | RWX: true 76 | 77 | # Support topology 78 | topology: false 79 | 80 | # Support populate data from snapshot 81 | snapshotDataSource: false 82 | 83 | # Support populated data from PVC 84 | pvcDataSource: false 85 | -------------------------------------------------------------------------------- /test/integration/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2019-2021 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | # This will run coverage analysis using the integration testing. 15 | # The env.sh must point to a valid Isilon deployment 16 | 17 | function runTest() { 18 | rm -f unix_sock 19 | source ${1} 20 | go test -v -coverprofile=c.linux.out -timeout 30m -coverpkg=../../service *test.go -args ${2} ${3} 21 | wait 22 | } 23 | 24 | echo "Quota is enabled" 25 | runTest ./env_Quota_Enabled.sh ./features/main_integration.feature "v1.0" 26 | mv ./Powerscale_integration_test_results.xml Powerscale_integration_test_results_QuotaEnabled.xml 27 | 28 | echo "Quota is not enabled" 29 | runTest ./env_Quota_notEnabled.sh ./features/integration.feature "v1.0" 30 | mv ./Powerscale_integration_test_results.xml Powerscale_integration_test_results_QuotaNotEnabled.xml 31 | 32 | echo "test accessModes with nodeIP1" 33 | runTest ./env_nodeIP1.sh ./features/mock_different_nodeIPs.feature "first_run" 34 | mv ./Powerscale_integration_test_results.xml Powerscale_integration_test_results_AccessModeIP1.xml 35 | 36 | echo "test accessModes with nodeIP2" 37 | runTest ./env_nodeIP2.sh ./features/mock_different_nodeIPs.feature "second_run" 38 | mv ./Powerscale_integration_test_results.xml Powerscale_integration_test_results_AccessModesIP2.xml 39 | 40 | echo "Custom Topology is enabled" 41 | runTest ./env_Custom_Topology_Enabled.sh ./features/integration.feature "v1.0" 42 | mv ./Powerscale_integration_test_results.xml Powerscale_integration_test_results_CustomTopology.xml 43 | -------------------------------------------------------------------------------- /test/scale_longevity/README.md: -------------------------------------------------------------------------------- 1 | # Helm charts and scripts for scalability and longevity tests 2 | 3 | This test holds a few scripts that can be used to test scalability and longevity 4 | for CSI driver 5 | 6 | ## Scalability 7 | 8 | The scaletest.sh script can be used to kick off scalability tests. 9 | This will run one series of 3 Helm deployments, causing a number of pods and replicas to be 10 | created, each with a certain number of volumes. Once the specified number of replicas have 11 | been launched, the deployments will be scaled down and removed. 12 | 13 | Log files will be created in the directory, titled `scalability-YYYYMMDD-HHMMSS.log` 14 | 15 | To launch the scalability test, a number of parameters are needed: 16 | 17 | ```sh 18 | scaletest.sh 19 | -n namespace - Namespace in which to place the test. 20 | -r replicas - Number of replicas to create 21 | -v number_volumes - Number of volumes for each pod. Default is: 1 22 | 23 | Default values for everything are set in the driver specific file at env.sh 24 | ``` 25 | 26 | An example of running the scalability tests for Isilon is: 27 | 28 | ```sh 29 | ./scaletest.sh -n test -r 33 -v 30 30 | ``` 31 | 32 | That test will deploy 3 Helm charts, with 33 replicas of each pod and 30 volumes per pod (a total of 99 pods and 2970 volumes). Once the pods are running, the system will scale down and terminate the test. 33 | 34 | ## Longevity 35 | 36 | The longevity.sh script can be used to kick off longevity tests. 37 | This will run a series of 3 Helm deployments over and over, causing a number of pods and replicas to be created and deleted until the test is stopped. To stop the test, create a file named 'stop' in the directory. Upon stopping, the deployments will be scaled down and removed. 38 | 39 | Log files will be created in the directory, titled `longevity-YYYYMMDD-HHMMSS.log` 40 | 41 | To launch the longevity test, a number of parameters are needed: 42 | 43 | ```sh 44 | longevity.sh 45 | -n namespace - Namespace in which to place the test. 46 | -r replicas - Number of replicas to create 47 | -v number_volumes - Number of volumes for each pod. Default is: 1 48 | 49 | Default values for everything are set in the driver specific file at env.sh 50 | ``` 51 | 52 | An example of running the longevity tests for Isilon is: 53 | 54 | ```sh 55 | ./longevity.sh -n test -r 10 -v 10 56 | ``` 57 | 58 | That test will deploy 3 Helm charts, with 10 replicas of each pod and 10 volumes per pod (a total of 30 pods and 300 volumes). Once the pods are running, the system will scale down to zero and repeat the process until stopped. 59 | 60 | Note that values specified on the command line override values defined in the env file. 61 | -------------------------------------------------------------------------------- /test/scale_longevity/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright © 2019 Dell Inc. or its subsidiaries. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | 15 | # Configuration file for isilon driver 16 | # This file is sourced from the longevity and scalbility test scripts 17 | # It will be executed with 'cwd' set to this directory 18 | 19 | # Longevity test helm chart 20 | LONGTEST="${LONGTEST:-volumes}" 21 | LONGREPLICAS="${LONGREPLICAS:-2}" 22 | 23 | # Scalability test helm chart 24 | SCALETEST="${SCALETEST:-volumes}" 25 | SCALEREPLICAS="${SCALEREPLICAS:-3}" 26 | 27 | # Namespace to run tests in. Will be created if it does not exist 28 | NAMESPACE="${NAMESPACE:-test}" 29 | 30 | # Storage Class names. Three of these are required but they can be the same. 31 | # These must exist before starting tests 32 | STORAGECLASS1="${STORAGECLASS1:-isilon}" 33 | STORAGECLASS2="${STORAGECLASS2:-isilon}" 34 | STORAGECLASS3="${STORAGECLASS3:-isilon}" 35 | 36 | # The namespace that the driver is running within 37 | DRIVERNAMESPACE="isilon" -------------------------------------------------------------------------------- /test/scale_longevity/volumes/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: volumes 2 | version: 1.0.0 3 | appVersion: 1.0.0 4 | description: | 5 | Test CSI Isilon deployment. 6 | keywords: 7 | - csi-isilon 8 | - storage 9 | engine: gotpl 10 | -------------------------------------------------------------------------------- /test/scale_longevity/volumes/templates/test.yaml: -------------------------------------------------------------------------------- 1 | # yamllint disable-file 2 | # This file is not valid YAML because it is a Helm template 3 | apiVersion: apps/v1 4 | kind: StatefulSet 5 | metadata: 6 | name: {{ required "name required " .Values.name | quote }} 7 | spec: 8 | selector: 9 | matchLabels: 10 | app: csi-test 11 | serviceName: csi-test 12 | replicas: {{ required "replicas required" .Values.replicas }} 13 | podManagementPolicy: "Parallel" 14 | template: 15 | metadata: 16 | labels: 17 | app: csi-test 18 | spec: 19 | containers: 20 | - name: test 21 | image: quay.io/centos/centos:latest 22 | imagePullPolicy: IfNotPresent 23 | volumeMounts: 24 | {{ range $i, $e := until (int .Values.numberOfVolumes) }} 25 | - name: pvol-{{ $i }} 26 | mountPath: /data{{ $i }} 27 | {{ end }} 28 | command: ["/bin/bash"] 29 | args: ["-c", "trap 'exit 0' SIGTERM;while true; do sleep 1; done"] 30 | volumeClaimTemplates: 31 | {{ $storageClass := .Values.storageClass | quote }} 32 | {{ range $i, $e := until (int .Values.numberOfVolumes) }} 33 | - metadata: 34 | name: pvol-{{ $i }} 35 | spec: 36 | accessModes: [ "ReadWriteOnce" ] 37 | storageClassName: {{ required "storageClass required" $storageClass }} 38 | resources: 39 | requests: 40 | storage: 8Gi 41 | {{ end }} 42 | -------------------------------------------------------------------------------- /test/scale_longevity/volumes/values.yaml: -------------------------------------------------------------------------------- 1 | name: scaleStatefulSet 2 | replicas: 1 3 | storageClass: default 4 | numberOfVolumes: 5 5 | --------------------------------------------------------------------------------