From 703e897424e6264c49935f42bc72f937d157c069 Mon Sep 17 00:00:00 2001 From: Michel Peterson Date: Mon, 24 Mar 2025 23:11:00 +0000 Subject: [PATCH] Added vagrant and devcontainers + fixed all tests --- .devcontainer/devcontainer.json | 38 ++++++++ .github/dependabot.yml | 12 +++ .gitignore | 4 +- CONTRIBUTING.md | 108 +++++++++++++++++++++ Vagrantfile | 71 ++++++++++++++ ci/bin/run.sh | 2 +- dev/run.sh | 34 +++++++ src/driver/controller-zfs-generic/index.js | 27 +++--- 8 files changed, 282 insertions(+), 14 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/dependabot.yml create mode 100644 CONTRIBUTING.md create mode 100644 Vagrantfile create mode 100755 dev/run.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..2835179 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,38 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node +{ + "name": "democratic-csi", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", + + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/go:1": {} // To compile csi-sanity during postCreateCommand + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "npm install", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "waderyan.nodejs-extension-pack", + "ms-vscode.node-debug2", + "christian-kohler.npm-intellisense", + "christian-kohler.path-intellisense", + "HashiCorp.terraform" + ] + } + } + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f33a02c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for more information: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://containers.dev/guide/dependabot + +version: 2 +updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/.gitignore b/.gitignore index 2855d28..b945e95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ **~ node_modules -dev +dev/* /ci/bin/*dev* +.vagrant +!dev/run.sh \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a770271 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,108 @@ +# Contributing to democratic-csi + +## Development Environment Setup + +This project uses a hybrid development approach with devcontainers for IDE configuration and Vagrant for system-level testing. + +### Prerequisites + +Before you begin, ensure you have the following installed: +- [Visual Studio Code](https://code.visualstudio.com/) +- [Docker](https://www.docker.com/get-started) +- [Vagrant](https://www.vagrantup.com/downloads) +- Virtualization Provider: + - For Intel/AMD Machines: VirtualBox + - For Apple Silicon: Qemu (`brew install qemu vagrant` and `vagrant plugin install vagrant-qemu`) + +### Development Workflow + +#### 1. Local Development with Devcontainers + +Devcontainers provide a consistent development environment with: +- Configured VSCode extensions +- Necessary development tools +- Integrated development experience + +To use the devcontainer: +1. Open the project in VSCode +2. Install the "Dev Containers" extension +3. Click "Reopen in Container" when prompted +4. Start coding with pre-configured environment + +#### 2. System Testing with Vagrant + +Vagrant provides a full virtual machine environment for: +- System-level testing +- Running code with kernel dependencies +- Simulating production-like environments + +Workflow: +```bash +# Navigate to project directory +cd ~/democratic-csi + +# Start the Vagrant VM +vagrant up + +# Connect to the VM +vagrant ssh + +# Inside the VM, navigate to the project +cd ~/democratic-csi + +# Run project tests, the config.yaml can be any from the examples folders +# just configured for your own environment. +# You can also create a file `dev/secrets.env` that has `export VARIABLE=VALUE` +# and reference those in your `config.yaml` +./dev/run.sh -c ./dev/config.yaml +``` + +##### Keeping Files in Sync + +Use these methods to keep your local files synchronized with the Vagrant VM: + +###### Manual Sync +```bash +# Sync files from local to Vagrant VM +vagrant rsync +``` + +###### Continuous Sync +```bash +# Automatically sync files as they change +vagrant rsync-auto +``` + +### Best Practices + +- Use devcontainer for day-to-day development and coding +- Use Vagrant for comprehensive system testing +- Always run `vagrant rsync` before running tests in the VM +- Commit and push changes frequently +- If encountering issues, try: + 1. Recreating the devcontainer + 2. Reprovisioning the Vagrant VM with `vagrant reload --provision` or `vagrant destroy -f && vagrant up` + +### Troubleshooting + +#### Devcontainer Issues +- Ensure Docker is running +- Rebuild the container if extensions fail to load +- Check VSCode Dev Containers extension logs + +#### Vagrant Issues +- Verify virtualization is enabled in your BIOS +- Ensure you have the latest Vagrant and virtualization provider +- For Apple Silicon, use Parallels or Lima + +### Contribution Guidelines + +1. Create a new branch for your feature targetting `next` +2. Write clear, concise commit messages +3. Include coverage for tests of csi-sanity for new functionality +4. Run tests in Vagrant VM +5. Submit a pull request with a clear description of changes + +### Contact + +For any questions or issues, please [open an issue](https://github.com/democratic-csi/democratic-csi/issues) on the project repository. \ No newline at end of file diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..294ceab --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,71 @@ +Vagrant.configure("2") do |config| + # Check the host's architecture + host_arch = `uname -m`.strip + + # Use a different box for ARM vs x86_64 + if host_arch == "arm64" + # requires qemu, install qemu and then: + # vagrant plugin install vagrant-qemu + config.vm.box = "perk/ubuntu-24.04-arm64" + else + # Use the x86_64 compatible Ubuntu box + config.vm.box = "ubuntu/jammy64" + end + + config.vm.provider "virtualbox" do |vb| + vb.memory = "2048" + vb.cpus = 2 + end + + config.vm.provision "shell", inline: <<-SHELL + sudo apt-get update -y + sudo apt-get install -y open-iscsi nodejs git make + + # Enable and start iscsid service + sudo systemctl enable --now iscsid + + # Verify installation + systemctl status iscsid --no-pager + + #### + # Install golang + #### + GO_VERSION="1.24.1" + ARCH=$(uname -m) + GO_TAR_URL="" + + if [[ "$ARCH" == "aarch64" ]]; then + GO_TAR_URL="https://go.dev/dl/go${GO_VERSION}.linux-arm64.tar.gz" + elif [[ "$ARCH" == "x86_64" ]]; then + GO_TAR_URL="https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" + else + echo "Unsupported architecture: $ARCH" + exit 1 + fi + + echo "Downloading Go version $GO_VERSION for $ARCH..." + wget -q "$GO_TAR_URL" -O go.tar.gz + tar -C /usr/local -xzf go.tar.gz + rm go.tar.gz + echo "export PATH=\$PATH:/usr/local/go/bin" >> /etc/profile + source /etc/profile + + #### + # Install csi-test + #### + echo "Installing csi-test" + git clone https://github.com/kubernetes-csi/csi-test /tmp/csi-test + pushd /tmp/csi-test/cmd/csi-sanity + make csi-sanity + sudo cp csi-sanity /usr/local/bin + popd + #rm -rf /tmp/csi-test + SHELL + + # Sync project directory for seamless workflow + config.vm.synced_folder ".", "/home/vagrant/democratic-csi", type: "rsync", + rsync__exclude: ".git/" + + # Allow SSH access with default key + config.ssh.insert_key = false + end \ No newline at end of file diff --git a/ci/bin/run.sh b/ci/bin/run.sh index 1d4eaf8..fd929f9 100755 --- a/ci/bin/run.sh +++ b/ci/bin/run.sh @@ -20,7 +20,7 @@ if [[ -f "node_modules-linux-amd64.tar.gz" && ! -d "node_modules" ]];then fi # generate key for paths etc -export CI_BUILD_KEY=$(uuidgen | cut -d "-" -f 1) +export CI_BUILD_KEY=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8) # launch the server sudo -E ci/bin/launch-server.sh & diff --git a/dev/run.sh b/dev/run.sh new file mode 100755 index 0000000..c38e310 --- /dev/null +++ b/dev/run.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -e +set -x +TEMPLATE_CONFIG="" + +ROOT_DIR="$(dirname "$(realpath "$0")")" + +while [[ "$#" -gt 0 ]]; do + case $1 in + -c|--config) TEMPLATE_CONFIG="$(realpath "$2")"; shift ;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +if [ -z "${TEMPLATE_CONFIG}" ]; then + echo "Error: --config or -c parameter is required." + exit 1 +fi + +if [ ! -f $ROOT_DIR/secrets.env ]; then + echo "Error: secrets.env file not found." + exit 1 +fi + +source $ROOT_DIR/secrets.env # needs to have exported variables + +# generate key for paths etc +export CI_BUILD_KEY=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8) + +export TEMPLATE_CONFIG_FILE=${TEMPLATE_CONFIG} + +$ROOT_DIR/../ci/bin/run.sh \ No newline at end of file diff --git a/src/driver/controller-zfs-generic/index.js b/src/driver/controller-zfs-generic/index.js index d560dd2..b7ed07b 100644 --- a/src/driver/controller-zfs-generic/index.js +++ b/src/driver/controller-zfs-generic/index.js @@ -300,12 +300,12 @@ create /backstores/block/${assetName} break; case "pcs": basename = this.options.iscsi.shareStrategyPcs.basename; - pcs_group = this.options.iscsi.shareStrategyPcs.pcs_group; + let pcs_group = this.options.iscsi.shareStrategyPcs.pcs_group; - let groupTerms = ['group', `${pcs_group}`]; + let extraTerms = ['group', `${pcs_group}`, '--wait']; // The wait is important to avoid race conditions let createTargetTerms = [ - 'resource', 'create', '--future', `target-${assetName}`, 'iSCSITarget', - 'implementation="lio-t"', `iqn="${basename}:${assetName}"` + 'resource', 'create', '--future', `target-${assetName}`, 'ocf:heartbeat:iSCSITarget', + 'implementation="lio-t"', 'portals=":::3260"', `iqn="${basename}:${assetName}"` ]; if (this.options.iscsi.shareStrategyPcs.auth.enabled) { @@ -317,7 +317,7 @@ create /backstores/block/${assetName} 3, 2000, async () => { - await this.pcsCommand(createTargetTerms.concat(groupTerms)); + await this.pcsCommand(createTargetTerms.concat(extraTerms)); }, { retryCondition: (err) => { @@ -330,8 +330,8 @@ create /backstores/block/${assetName} ); let createLunTerms = [ - 'resource', 'create', '--future', `lun-${assetName}`, 'iSCSILogicalUnit', - 'implementation="lio-t"', `target_iqn="${basename}:${assetName}"`, 'lun="1"', + 'resource', 'create', '--future', `lun-${assetName}`, 'ocf:heartbeat:iSCSILogicalUnit', + 'implementation="lio-t"', `target_iqn="${basename}:${assetName}"`, 'lun="0"', `path="/dev/${extentDiskName}"` ]; @@ -339,7 +339,7 @@ create /backstores/block/${assetName} 3, 2000, async () => { - await this.pcsCommand(createLunTerms.concat(groupTerms)); + await this.pcsCommand(createLunTerms.concat(extraTerms)); }, { retryCondition: (err) => { @@ -351,8 +351,6 @@ create /backstores/block/${assetName} } ); - await GeneralUtils.sleep(2000); // let things settle - break; default: @@ -791,8 +789,6 @@ delete ${assetName} } ); - await GeneralUtils.sleep(2000); // let things settle - break; default: @@ -1006,6 +1002,13 @@ save_config filename=${this.options.nvmeof.shareStrategySpdkCli.configPath} driver.ctx.logger.verbose( "pcs response: " + JSON.stringify(response) ); + + // Handle idempotence for create commands + if (response.code == 1 && response.stdout.includes("already exists")) { + driver.ctx.logger.verbose("pcs resource already exists, ignoring error (setting response.code=0)"); + response.code = 0; + } + if (response.code != 0) { throw response; }