From 1cb683a4d63d063d40999ed734de67446a9df265 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 2 Apr 2026 17:03:26 +0000 Subject: [PATCH 1/5] feat: use per-devnet GPG-encrypted SSH keys in CI workflows --- .github/workflows/create-devnet.yml | 140 ++++++++++++--------- .github/workflows/deploy.yml | 121 +++++++++++------- .github/workflows/destroy-devnet.yml | 77 +++++++----- .github/workflows/platform-deploy.yml | 169 +++++++++++++++----------- 4 files changed, 301 insertions(+), 206 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index 8c4652a5..c13a9985 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -17,7 +17,6 @@ on: required: true type: string default: "full_deploy" - # Advanced options - sane defaults, only change if you know what you're doing hp_masternodes_arm_count: description: "Advanced: Number of ARM HP masternodes" required: false @@ -121,7 +120,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y python3-pip python3-netaddr sshpass jq + sudo apt-get install -y python3-pip python3-netaddr sshpass jq gnupg - name: Install Ansible run: | @@ -134,33 +133,21 @@ jobs: mkdir -p ~/.ansible/roles cp -r ansible/roles/* ~/.ansible/roles/ - - name: Set up SSH keys + - name: Set up GitHub SSH keys env: - DEPLOY_SERVER_KEY: ${{ secrets.DEPLOY_SERVER_KEY }} EVO_APP_DEPLOY_KEY: ${{ secrets.EVO_APP_DEPLOY_KEY }} EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | mkdir -p ~/.ssh - # Server SSH key for connecting to nodes - printf '%s\n' "$DEPLOY_SERVER_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # Derive public key from private key - ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub - chmod 644 ~/.ssh/id_rsa.pub - - # GitHub deploy key for cloning configs repo printf '%s\n' "$EVO_APP_DEPLOY_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 - # Optional write key for pushing to configs repo if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" ]]; then printf '%s\n' "$EVO_APP_DEPLOY_WRITE_KEY" > ~/.ssh/id_ed25519_write chmod 600 ~/.ssh/id_ed25519_write fi - # SSH config cat > ~/.ssh/config << 'EOL' Host github.com IdentityFile ~/.ssh/id_ed25519 @@ -175,51 +162,106 @@ jobs: chmod 600 ~/.ssh/config - - name: Create networks/.env - run: | - mkdir -p networks - cat > networks/.env << EOF - PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa - PUBLIC_KEY_PATH=$HOME/.ssh/id_rsa.pub - AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY - AWS_REGION=$AWS_REGION - TERRAFORM_S3_BUCKET=$TERRAFORM_S3_BUCKET - TERRAFORM_S3_KEY=$TERRAFORM_S3_KEY - TERRAFORM_DYNAMODB_TABLE=$TERRAFORM_DYNAMODB_TABLE - EOF - - name: Check for existing devnet configs id: existing_configs run: | + mkdir -p networks git clone git@github.com:dashpay/dash-network-configs.git /tmp/dash-network-configs-source FOUND=0 - MISSING=0 - for ext in yml tfvars inventory; do + for ext in yml tfvars inventory ssh.asc; do SRC="/tmp/dash-network-configs-source/$NETWORK_NAME.$ext" if [[ -f "$SRC" ]]; then FOUND=$((FOUND + 1)) - else - MISSING=$((MISSING + 1)) fi done - if [[ $FOUND -eq 3 ]]; then + if [[ $FOUND -eq 4 ]]; then echo "resume_mode=true" >> "$GITHUB_OUTPUT" echo "Found existing config set for $NETWORK_NAME. Reusing config repo files and skipping Terraform." cp "/tmp/dash-network-configs-source/$NETWORK_NAME.yml" networks/ cp "/tmp/dash-network-configs-source/$NETWORK_NAME.tfvars" networks/ cp "/tmp/dash-network-configs-source/$NETWORK_NAME.inventory" networks/ + cp "/tmp/dash-network-configs-source/$NETWORK_NAME.ssh.asc" networks/ elif [[ $FOUND -eq 0 ]]; then echo "resume_mode=false" >> "$GITHUB_OUTPUT" echo "No existing config set found for $NETWORK_NAME. Running full create flow." else echo "Error: Partial config set found for $NETWORK_NAME in dash-network-configs." - ls -la /tmp/dash-network-configs-source/$NETWORK_NAME.* 2>/dev/null || true + ls -la "/tmp/dash-network-configs-source/$NETWORK_NAME"* 2>/dev/null || true + exit 1 + fi + + - name: Prepare devnet SSH key + env: + DEVNET_CI_GPG_PRIVATE_KEY: ${{ secrets.DEVNET_CI_GPG_PRIVATE_KEY }} + DEVNET_CI_GPG_PASSPHRASE: ${{ secrets.DEVNET_CI_GPG_PASSPHRASE }} + VIVEK_GPG_PUBLIC_KEY: ${{ secrets.VIVEK_GPG_PUBLIC_KEY }} + LATTE_GPG_PUBLIC_KEY: ${{ secrets.LATTE_GPG_PUBLIC_KEY }} + run: | + export GNUPGHOME="$RUNNER_TEMP/gnupg" + mkdir -p "$GNUPGHOME" ~/.ssh + chmod 700 "$GNUPGHOME" ~/.ssh + + printf '%s' "$DEVNET_CI_GPG_PRIVATE_KEY" > "$RUNNER_TEMP/devnet-ci-private.asc" + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --import "$RUNNER_TEMP/devnet-ci-private.asc" + + if [[ "${{ steps.existing_configs.outputs.resume_mode }}" == "true" ]]; then + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --decrypt --output "$HOME/.ssh/id_rsa" "networks/$NETWORK_NAME.ssh.asc" + chmod 600 "$HOME/.ssh/id_rsa" + ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub" + chmod 644 "$HOME/.ssh/id_rsa.pub" + exit 0 + fi + + ssh-keygen -t rsa -b 4096 -N '' -C "$NETWORK_NAME" -f "$HOME/.ssh/id_rsa" + chmod 600 "$HOME/.ssh/id_rsa" + chmod 644 "$HOME/.ssh/id_rsa.pub" + + printf '%s' "$VIVEK_GPG_PUBLIC_KEY" > "$RUNNER_TEMP/vivek-public.asc" + printf '%s' "$LATTE_GPG_PUBLIC_KEY" > "$RUNNER_TEMP/latte-public.asc" + gpg --batch --yes --import "$RUNNER_TEMP/vivek-public.asc" + gpg --batch --yes --import "$RUNNER_TEMP/latte-public.asc" + + mapfile -t recipients < <( + gpg --batch --with-colons --list-keys | + awk -F: '$1 == "pub" {want=1; next} want && $1 == "fpr" {print $10; want=0}' + ) + + if [[ ${#recipients[@]} -lt 3 ]]; then + echo "Error: expected at least 3 GPG recipients, found ${#recipients[@]}" + gpg --batch --list-keys exit 1 fi + recipient_args=() + for recipient in "${recipients[@]}"; do + recipient_args+=(--recipient "$recipient") + done + + gpg --batch --yes --trust-model always --armor --encrypt \ + "${recipient_args[@]}" \ + --output "networks/$NETWORK_NAME.ssh.asc" \ + "$HOME/.ssh/id_rsa" + + - name: Create networks/.env + run: | + mkdir -p networks + cat > networks/.env << EOF2 + PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa + PUBLIC_KEY_PATH=$HOME/.ssh/id_rsa.pub + AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY + AWS_REGION=$AWS_REGION + TERRAFORM_S3_BUCKET=$TERRAFORM_S3_BUCKET + TERRAFORM_S3_KEY=$TERRAFORM_S3_KEY + TERRAFORM_DYNAMODB_TABLE=$TERRAFORM_DYNAMODB_TABLE + EOF2 + - name: Generate network configs if: steps.existing_configs.outputs.resume_mode != 'true' env: @@ -229,7 +271,6 @@ jobs: HP_ARM: ${{ github.event.inputs.hp_masternodes_arm_count }} SEED_COUNT: ${{ github.event.inputs.seed_count }} run: | - # Validate all counts are numeric for var in MN_AMD MN_ARM HP_AMD HP_ARM SEED_COUNT; do val="${!var}" if [[ ! "$val" =~ ^[0-9]+$ ]]; then @@ -253,29 +294,20 @@ jobs: CORE_VERSION: ${{ github.event.inputs.core_version }} run: | CONFIG_FILE="networks/$NETWORK_NAME.yml" - - # Escape sed-special characters in version strings SAFE_VERSION=$(printf '%s' "$VERSION" | sed 's/[&\\/]/\\&/g') SAFE_CORE_VERSION=$(printf '%s' "$CORE_VERSION" | sed 's/[&\\/]/\\&/g') echo "Setting platform version to $VERSION..." - - # Update dashmate version sed -i "s/dashmate_version: .*/dashmate_version: $SAFE_VERSION/" "$CONFIG_FILE" - - # Update platform service images sed -i "s|drive_image: dashpay/drive:.*|drive_image: dashpay/drive:$SAFE_VERSION|" "$CONFIG_FILE" sed -i "s|dapi_image: dashpay/dapi:.*|dapi_image: dashpay/dapi:$SAFE_VERSION|" "$CONFIG_FILE" - # Add rs_dapi_image (not in generated config, but group_vars/all defines it - # without a tag, so we must explicitly set it to get the right version) if ! grep -q "rs_dapi_image:" "$CONFIG_FILE"; then echo "rs_dapi_image: dashpay/rs-dapi:$VERSION" >> "$CONFIG_FILE" else sed -i "s|rs_dapi_image: dashpay/rs-dapi:.*|rs_dapi_image: dashpay/rs-dapi:$SAFE_VERSION|" "$CONFIG_FILE" fi - # Update core version if specified if [[ -n "$CORE_VERSION" ]]; then echo "Setting core version to $CORE_VERSION..." sed -i "s|dashd_image: dashpay/dashd:.*|dashd_image: dashpay/dashd:$SAFE_CORE_VERSION|" "$CONFIG_FILE" @@ -290,16 +322,13 @@ jobs: run: | TFVARS_FILE="networks/$NETWORK_NAME.tfvars" DEFAULT_MAIN_DOMAIN="networks.dash.org" - - # Read current value from file (empty if not set) CURRENT_SIZE=$(grep -oP 'hpmn_node_disk_size\s*=\s*\K[0-9]+' "$TFVARS_FILE" 2>/dev/null || echo "") CURRENT_MAIN_DOMAIN=$(grep -oP 'main_domain\s*=\s*"\K[^"]*' "$TFVARS_FILE" 2>/dev/null || echo "") - # Generated tfvars leaves main_domain empty; ensure ACM DNS names are valid. if [[ -z "$CURRENT_MAIN_DOMAIN" ]]; then echo "Setting main_domain to $DEFAULT_MAIN_DOMAIN..." if grep -q '^main_domain\s*=' "$TFVARS_FILE"; then - sed -i "s|^main_domain\\s*=.*|main_domain = \"$DEFAULT_MAIN_DOMAIN\"|" "$TFVARS_FILE" + sed -i "s|^main_domain\s*=.*|main_domain = \"$DEFAULT_MAIN_DOMAIN\"|" "$TFVARS_FILE" else echo "main_domain = \"$DEFAULT_MAIN_DOMAIN\"" >> "$TFVARS_FILE" fi @@ -333,7 +362,6 @@ jobs: echo "============================================" chmod +x ./bin/deploy - # GitHub Actions checks out a detached HEAD; bypass branch safety check. if [[ "${{ steps.existing_configs.outputs.resume_mode }}" == "true" ]]; then echo "Resume mode enabled. Skipping Terraform and re-running provisioning only." ./bin/deploy -p -f --tags="$DEPLOY_TAGS" "$NETWORK_NAME" @@ -346,12 +374,10 @@ jobs: env: EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | - # Clone the configs repo to a temp directory git clone git@github.com:dashpay/dash-network-configs.git /tmp/dash-network-configs - # Copy generated config files if present COPIED=0 - for ext in yml tfvars inventory; do + for ext in yml tfvars inventory ssh.asc; do SRC="networks/$NETWORK_NAME.$ext" if [[ -f "$SRC" ]]; then cp "$SRC" /tmp/dash-network-configs/ @@ -366,14 +392,17 @@ jobs: exit 0 fi - # Commit and push + if [[ $COPIED -ne 4 ]]; then + echo "::warning::Not pushing partial devnet config set for $NETWORK_NAME" + exit 0 + fi + cd /tmp/dash-network-configs git config user.name "GitHub Actions" git config user.email "actions@github.com" git add . git commit -m "Add configs for $NETWORK_NAME" || echo "No changes to commit" - # Use optional write key if configured; otherwise try default key. if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" && -f "$HOME/.ssh/id_ed25519_write" ]]; then GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_write -o StrictHostKeyChecking=no' git push || { echo "::warning::Failed to push configs with EVO_APP_DEPLOY_WRITE_KEY" @@ -405,5 +434,6 @@ jobs: echo "Devnet: $NETWORK_NAME" echo "============================================" echo "" + echo "Encrypted SSH key stored as: $NETWORK_NAME.ssh.asc in dash-network-configs" echo "To update this devnet later, use the 'Platform Version Deployment' workflow" echo "To destroy this devnet, use the 'Destroy Devnet' workflow" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 946d0d4c..3ee84ca8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -19,7 +19,10 @@ on: jobs: deploy: name: Deploy Dash Network - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + + env: + ANSIBLE_HOST_KEY_CHECKING: "false" steps: - name: Checkout dash-network-deploy @@ -30,88 +33,112 @@ jobs: with: node-version: '20' + - name: Install Node.js dependencies + run: npm ci + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y python3-pip python3-netaddr sshpass jq gnupg + - name: Install Ansible run: | - python -m pip install --upgrade pip - pip install ansible + python3 -m pip install --upgrade pip + python3 -m pip install ansible-core==2.16.3 jmespath - # Setup SSH keys - name: Install Ansible roles run: | ansible-galaxy install -r ansible/requirements.yml + mkdir -p ~/.ansible/roles + cp -r ansible/roles/* ~/.ansible/roles/ - - name: Set up SSH Keys + - name: Set up GitHub SSH key + env: + EVO_APP_DEPLOY_KEY: ${{ secrets.EVO_APP_DEPLOY_KEY }} run: | mkdir -p ~/.ssh - - # GitHub deploy key for cloning configs - echo "${{ secrets.EVO_APP_DEPLOY_KEY }}" > ~/.ssh/id_ed25519 + printf '%s\n' "$EVO_APP_DEPLOY_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 - # Server SSH key for connecting to nodes - echo "${{ secrets.DEPLOY_SERVER_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # SSH config cat > ~/.ssh/config << 'EOL' Host github.com IdentityFile ~/.ssh/id_ed25519 StrictHostKeyChecking no - - Host * - IdentityFile ~/.ssh/id_rsa - User ubuntu - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null EOL chmod 600 ~/.ssh/config - # Set up Node.js and clone configs - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - - name: Install dependencies - run: npm ci - - # Clone network configs - name: Clone network configs run: | rm -rf networks git clone git@github.com:dashpay/dash-network-configs.git networks - # Verify network config exists - name: Check network config + env: + NETWORK: ${{ github.event.inputs.network_name }} run: | - if [ ! -f "networks/${{ github.event.inputs.network_name }}.yml" ]; then - echo "Error: Network config networks/${{ github.event.inputs.network_name }}.yml not found" + if [[ ! -f "networks/$NETWORK.yml" ]]; then + echo "Error: Network config networks/$NETWORK.yml not found" exit 1 fi - # Install Ansible and Python dependencies - - name: Install Ansible and Dependencies + if [[ "$NETWORK" == devnet-* && ! -f "networks/$NETWORK.ssh.asc" ]]; then + echo "Error: Encrypted devnet SSH key networks/$NETWORK.ssh.asc not found" + exit 1 + fi + + - name: Prepare server SSH key + env: + NETWORK: ${{ github.event.inputs.network_name }} + DEPLOY_SERVER_KEY: ${{ secrets.DEPLOY_SERVER_KEY }} + DEVNET_CI_GPG_PRIVATE_KEY: ${{ secrets.DEVNET_CI_GPG_PRIVATE_KEY }} + DEVNET_CI_GPG_PASSPHRASE: ${{ secrets.DEVNET_CI_GPG_PASSPHRASE }} run: | - sudo apt-get update - sudo apt-get install -y python3-pip python3-netaddr sshpass - pip3 install ansible + export GNUPGHOME="$RUNNER_TEMP/gnupg" + mkdir -p "$GNUPGHOME" ~/.ssh + chmod 700 "$GNUPGHOME" ~/.ssh + + if [[ "$NETWORK" == devnet-* ]]; then + printf '%s' "$DEVNET_CI_GPG_PRIVATE_KEY" > "$RUNNER_TEMP/devnet-ci-private.asc" + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --import "$RUNNER_TEMP/devnet-ci-private.asc" + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --decrypt --output "$HOME/.ssh/id_rsa" "networks/$NETWORK.ssh.asc" + else + printf '%s\n' "$DEPLOY_SERVER_KEY" > "$HOME/.ssh/id_rsa" + fi + + chmod 600 "$HOME/.ssh/id_rsa" + ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub" + chmod 644 "$HOME/.ssh/id_rsa.pub" + + cat > ~/.ssh/config << 'EOL' + Host github.com + IdentityFile ~/.ssh/id_ed25519 + StrictHostKeyChecking no + + Host * + IdentityFile ~/.ssh/id_rsa + User ubuntu + StrictHostKeyChecking no + UserKnownHostsFile=/dev/null + EOL + + chmod 600 ~/.ssh/config - # Install required Ansible roles from Galaxy and local roles - - name: Install Ansible Roles + - name: Create networks/.env run: | - mkdir -p ~/.ansible/roles - cp -r ansible/roles/* ~/.ansible/roles/ + cat > networks/.env << EOF2 + PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa + PUBLIC_KEY_PATH=$HOME/.ssh/id_rsa.pub + EOF2 - # Run deploy - name: Run Deploy Script env: - ANSIBLE_CONFIG: ansible.cfg NETWORK: ${{ github.event.inputs.network_name }} NETWORK_PATH: networks/${{ github.event.inputs.network_name }}.yml - ANSIBLE_HOST_KEY_CHECKING: "false" run: | - pwd - ls -la - ls -la networks/ chmod +x ./bin/github-deploy - ./bin/github-deploy -p ${{ github.event.inputs.network_name }} --tags ${{ github.event.inputs.deploy_tag }} + ./bin/github-deploy -p "$NETWORK" --tags "${{ github.event.inputs.deploy_tag }}" diff --git a/.github/workflows/destroy-devnet.yml b/.github/workflows/destroy-devnet.yml index 3ba4f86f..3e1735c6 100644 --- a/.github/workflows/destroy-devnet.yml +++ b/.github/workflows/destroy-devnet.yml @@ -85,7 +85,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y python3-pip python3-netaddr sshpass jq + sudo apt-get install -y python3-pip python3-netaddr sshpass jq gnupg - name: Install Ansible run: | @@ -98,33 +98,21 @@ jobs: mkdir -p ~/.ansible/roles cp -r ansible/roles/* ~/.ansible/roles/ - - name: Set up SSH keys + - name: Set up GitHub SSH keys env: - DEPLOY_SERVER_KEY: ${{ secrets.DEPLOY_SERVER_KEY }} EVO_APP_DEPLOY_KEY: ${{ secrets.EVO_APP_DEPLOY_KEY }} EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | mkdir -p ~/.ssh - # Server SSH key for connecting to nodes - printf '%s\n' "$DEPLOY_SERVER_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # Derive public key from private key - ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub - chmod 644 ~/.ssh/id_rsa.pub - - # GitHub deploy key for cloning configs repo printf '%s\n' "$EVO_APP_DEPLOY_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 - # Optional write key for pushing to configs repo if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" ]]; then printf '%s\n' "$EVO_APP_DEPLOY_WRITE_KEY" > ~/.ssh/id_ed25519_write chmod 600 ~/.ssh/id_ed25519_write fi - # SSH config cat > ~/.ssh/config << 'EOL' Host github.com IdentityFile ~/.ssh/id_ed25519 @@ -139,34 +127,21 @@ jobs: chmod 600 ~/.ssh/config - - name: Create networks/.env - run: | - mkdir -p networks - cat > networks/.env << EOF - PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa - PUBLIC_KEY_PATH=$HOME/.ssh/id_rsa.pub - AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY - AWS_REGION=$AWS_REGION - TERRAFORM_S3_BUCKET=$TERRAFORM_S3_BUCKET - TERRAFORM_S3_KEY=$TERRAFORM_S3_KEY - TERRAFORM_DYNAMODB_TABLE=$TERRAFORM_DYNAMODB_TABLE - EOF - - name: Clone network configs run: | + mkdir -p networks rm -rf networks/.git git clone git@github.com:dashpay/dash-network-configs.git /tmp/dash-network-configs - # Copy config files for this devnet cp /tmp/dash-network-configs/$NETWORK_NAME.yml networks/ 2>/dev/null || true cp /tmp/dash-network-configs/$NETWORK_NAME.tfvars networks/ 2>/dev/null || true cp /tmp/dash-network-configs/$NETWORK_NAME.inventory networks/ 2>/dev/null || true + cp /tmp/dash-network-configs/$NETWORK_NAME.ssh.asc networks/ 2>/dev/null || true - name: Validate config files exist run: | MISSING=() - for ext in yml tfvars inventory; do + for ext in yml tfvars inventory ssh.asc; do if [[ ! -f "networks/$NETWORK_NAME.$ext" ]]; then MISSING+=("networks/$NETWORK_NAME.$ext") fi @@ -186,6 +161,42 @@ jobs: echo "Found all config files for $NETWORK_NAME" ls -la networks/$NETWORK_NAME.* + - name: Prepare devnet SSH key + env: + DEVNET_CI_GPG_PRIVATE_KEY: ${{ secrets.DEVNET_CI_GPG_PRIVATE_KEY }} + DEVNET_CI_GPG_PASSPHRASE: ${{ secrets.DEVNET_CI_GPG_PASSPHRASE }} + run: | + export GNUPGHOME="$RUNNER_TEMP/gnupg" + mkdir -p "$GNUPGHOME" ~/.ssh + chmod 700 "$GNUPGHOME" ~/.ssh + + printf '%s' "$DEVNET_CI_GPG_PRIVATE_KEY" > "$RUNNER_TEMP/devnet-ci-private.asc" + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --import "$RUNNER_TEMP/devnet-ci-private.asc" + + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --decrypt --output "$HOME/.ssh/id_rsa" "networks/$NETWORK_NAME.ssh.asc" + + chmod 600 "$HOME/.ssh/id_rsa" + ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub" + chmod 644 "$HOME/.ssh/id_rsa.pub" + + - name: Create networks/.env + run: | + mkdir -p networks + cat > networks/.env << EOF2 + PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa + PUBLIC_KEY_PATH=$HOME/.ssh/id_rsa.pub + AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY + AWS_REGION=$AWS_REGION + TERRAFORM_S3_BUCKET=$TERRAFORM_S3_BUCKET + TERRAFORM_S3_KEY=$TERRAFORM_S3_KEY + TERRAFORM_DYNAMODB_TABLE=$TERRAFORM_DYNAMODB_TABLE + EOF2 + - name: Print destruction plan run: | echo "============================================" @@ -226,14 +237,13 @@ jobs: git config user.name "GitHub Actions" git config user.email "actions@github.com" - # Remove config files for this devnet git rm "$NETWORK_NAME.yml" 2>/dev/null || true git rm "$NETWORK_NAME.tfvars" 2>/dev/null || true git rm "$NETWORK_NAME.inventory" 2>/dev/null || true + git rm "$NETWORK_NAME.ssh.asc" 2>/dev/null || true git commit -m "Remove configs for $NETWORK_NAME (destroyed)" || echo "No changes to commit" - # Use optional write key if configured; otherwise try default key. if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" && -f "$HOME/.ssh/id_ed25519_write" ]]; then GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_write -o StrictHostKeyChecking=no' git push || { echo "::warning::Failed to push config removal with EVO_APP_DEPLOY_WRITE_KEY" @@ -241,7 +251,8 @@ jobs: } else git push || { - echo "::warning::Failed to push config removal (likely read-only EVO_APP_DEPLOY_KEY). Configure secret EVO_APP_DEPLOY_WRITE_KEY with write access." + echo "::warning::Failed to push config removal." + echo "::warning::Configure EVO_APP_DEPLOY_WRITE_KEY with write access." exit 0 } fi diff --git a/.github/workflows/platform-deploy.yml b/.github/workflows/platform-deploy.yml index 6ec85126..ca4eac3a 100644 --- a/.github/workflows/platform-deploy.yml +++ b/.github/workflows/platform-deploy.yml @@ -22,7 +22,10 @@ on: jobs: deploy: name: Deploy Platform Version - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + + env: + ANSIBLE_HOST_KEY_CHECKING: "false" steps: - name: Checkout dash-network-deploy @@ -33,129 +36,153 @@ jobs: with: node-version: '20' + - name: Install Node.js dependencies + run: npm ci + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y python3-pip python3-netaddr sshpass jq gnupg + - name: Install Ansible run: | - python -m pip install --upgrade pip - pip install ansible + python3 -m pip install --upgrade pip + python3 -m pip install ansible-core==2.16.3 jmespath - # Setup SSH keys - name: Install Ansible roles run: | ansible-galaxy install -r ansible/requirements.yml + mkdir -p ~/.ansible/roles + cp -r ansible/roles/* ~/.ansible/roles/ - - name: Set up SSH Keys + - name: Set up GitHub SSH key + env: + EVO_APP_DEPLOY_KEY: ${{ secrets.EVO_APP_DEPLOY_KEY }} run: | mkdir -p ~/.ssh - - # GitHub deploy key for cloning configs - echo "${{ secrets.EVO_APP_DEPLOY_KEY }}" > ~/.ssh/id_ed25519 + printf '%s\n' "$EVO_APP_DEPLOY_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 - # Server SSH key for connecting to nodes - echo "${{ secrets.DEPLOY_SERVER_KEY }}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # SSH config cat > ~/.ssh/config << 'EOL' Host github.com IdentityFile ~/.ssh/id_ed25519 StrictHostKeyChecking no - - Host * - IdentityFile ~/.ssh/id_rsa - User ubuntu - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null EOL - - chmod 600 ~/.ssh/config - # Set up Node.js and clone configs - - name: Install dependencies - run: npm ci + chmod 600 ~/.ssh/config - # Clone network configs - name: Clone network configs run: | rm -rf networks git clone git@github.com:dashpay/dash-network-configs.git networks - # Verify network config exists - name: Check network config + env: + NETWORK: ${{ github.event.inputs.network }} run: | - if [ ! -f "networks/${{ github.event.inputs.network }}.yml" ]; then - echo "Error: Network config networks/${{ github.event.inputs.network }}.yml not found" + if [[ ! -f "networks/$NETWORK.yml" ]]; then + echo "Error: Network config networks/$NETWORK.yml not found" + exit 1 + fi + + if [[ "$NETWORK" == devnet-* && ! -f "networks/$NETWORK.ssh.asc" ]]; then + echo "Error: Encrypted devnet SSH key networks/$NETWORK.ssh.asc not found" exit 1 fi - # Install Ansible and Python dependencies - - name: Install Ansible and Dependencies + - name: Prepare server SSH key + env: + NETWORK: ${{ github.event.inputs.network }} + DEPLOY_SERVER_KEY: ${{ secrets.DEPLOY_SERVER_KEY }} + DEVNET_CI_GPG_PRIVATE_KEY: ${{ secrets.DEVNET_CI_GPG_PRIVATE_KEY }} + DEVNET_CI_GPG_PASSPHRASE: ${{ secrets.DEVNET_CI_GPG_PASSPHRASE }} run: | - sudo apt-get update - sudo apt-get install -y python3-pip python3-netaddr sshpass - pip3 install ansible + export GNUPGHOME="$RUNNER_TEMP/gnupg" + mkdir -p "$GNUPGHOME" ~/.ssh + chmod 700 "$GNUPGHOME" ~/.ssh + + if [[ "$NETWORK" == devnet-* ]]; then + printf '%s' "$DEVNET_CI_GPG_PRIVATE_KEY" > "$RUNNER_TEMP/devnet-ci-private.asc" + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --import "$RUNNER_TEMP/devnet-ci-private.asc" + gpg --batch --yes --pinentry-mode loopback \ + --passphrase "$DEVNET_CI_GPG_PASSPHRASE" \ + --decrypt --output "$HOME/.ssh/id_rsa" "networks/$NETWORK.ssh.asc" + else + printf '%s\n' "$DEPLOY_SERVER_KEY" > "$HOME/.ssh/id_rsa" + fi + + chmod 600 "$HOME/.ssh/id_rsa" + ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub" + chmod 644 "$HOME/.ssh/id_rsa.pub" + + cat > ~/.ssh/config << 'EOL' + Host github.com + IdentityFile ~/.ssh/id_ed25519 + StrictHostKeyChecking no - # Install required Ansible roles from Galaxy and local roles - - name: Install Ansible Roles + Host * + IdentityFile ~/.ssh/id_rsa + User ubuntu + StrictHostKeyChecking no + UserKnownHostsFile=/dev/null + EOL + + chmod 600 ~/.ssh/config + + - name: Create networks/.env run: | - mkdir -p ~/.ansible/roles - cp -r ansible/roles/* ~/.ansible/roles/ - # Update platform version in network config + cat > networks/.env << EOF2 + PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa + PUBLIC_KEY_PATH=$HOME/.ssh/id_rsa.pub + EOF2 + - name: Update platform version in network config + env: + NETWORK: ${{ github.event.inputs.network }} + VERSION: ${{ github.event.inputs.platform_version }} run: | - # Update dashmate_version - sed -i "s/dashmate_version: .*/dashmate_version: ${{ github.event.inputs.platform_version }}/" networks/${{ github.event.inputs.network }}.yml - - # Update platform service image versions - sed -i "s/drive_image: dashpay\/drive:[^ ]*/drive_image: dashpay\/drive:${{ github.event.inputs.platform_version }}/" networks/${{ github.event.inputs.network }}.yml - sed -i "s/dapi_image: dashpay\/dapi:[^ ]*/dapi_image: dashpay\/dapi:${{ github.event.inputs.platform_version }}/" networks/${{ github.event.inputs.network }}.yml - - # Update rs_dapi_image (group_vars/all defines it without a tag, so we must - # explicitly set it to get the right version instead of :latest) - CONFIG_FILE="networks/${{ github.event.inputs.network }}.yml" + CONFIG_FILE="networks/$NETWORK.yml" + SAFE_VERSION=$(printf '%s' "$VERSION" | sed 's/[&\\/]/\\&/g') + + sed -i "s/dashmate_version: .*/dashmate_version: $SAFE_VERSION/" "$CONFIG_FILE" + sed -i "s|drive_image: dashpay/drive:[^ ]*|drive_image: dashpay/drive:$SAFE_VERSION|" "$CONFIG_FILE" + sed -i "s|dapi_image: dashpay/dapi:[^ ]*|dapi_image: dashpay/dapi:$SAFE_VERSION|" "$CONFIG_FILE" + if grep -q "rs_dapi_image:" "$CONFIG_FILE"; then - sed -i "s|rs_dapi_image: dashpay/rs-dapi:[^ ]*|rs_dapi_image: dashpay/rs-dapi:${{ github.event.inputs.platform_version }}|" "$CONFIG_FILE" + sed -i "s|rs_dapi_image: dashpay/rs-dapi:[^ ]*|rs_dapi_image: dashpay/rs-dapi:$SAFE_VERSION|" "$CONFIG_FILE" else - echo "rs_dapi_image: dashpay/rs-dapi:${{ github.event.inputs.platform_version }}" >> "$CONFIG_FILE" + echo "rs_dapi_image: dashpay/rs-dapi:$VERSION" >> "$CONFIG_FILE" fi echo "Updated network config:" - grep -E "(dashmate_version|drive_image|dapi_image|rs_dapi_image)" networks/${{ github.event.inputs.network }}.yml + grep -E "(dashmate_version|drive_image|dapi_image|rs_dapi_image)" "$CONFIG_FILE" - # Run platform deployment - name: Run Platform Deployment env: ANSIBLE_CONFIG: ansible.cfg NETWORK: ${{ github.event.inputs.network }} NETWORK_PATH: networks/${{ github.event.inputs.network }}.yml - ANSIBLE_HOST_KEY_CHECKING: "false" run: | - pwd - ls -la - ls -la networks/ chmod +x ./bin/deploy - - # Build deployment command + DEPLOY_CMD="./bin/deploy -p" - - # Add fast mode flag if enabled - if [ "${{ github.event.inputs.fast_mode }}" == "true" ]; then + if [[ "${{ github.event.inputs.fast_mode }}" == "true" ]]; then DEPLOY_CMD="$DEPLOY_CMD --fast" fi - - # Add dashmate deployment tag - DEPLOY_CMD="$DEPLOY_CMD --tags=dashmate_deploy" - - # Add network - DEPLOY_CMD="$DEPLOY_CMD ${{ github.event.inputs.network }}" - + DEPLOY_CMD="$DEPLOY_CMD --tags=dashmate_deploy $NETWORK" + echo "Running: $DEPLOY_CMD" $DEPLOY_CMD - # Verify deployment - name: Verify Platform Services env: - ANSIBLE_HOST_KEY_CHECKING: "false" + NETWORK: ${{ github.event.inputs.network }} run: | echo "Verifying platform services are running..." - ansible hp_masternodes -i "networks/${{ github.event.inputs.network }}.inventory" -b -m shell -a 'sudo -u dashmate dashmate status services --format=json | jq -r ".[] | select(.service != \"core\") | \"\(.service): \(.status)\""' || true + ansible hp_masternodes \ + -i "networks/$NETWORK.inventory" \ + --private-key="$HOME/.ssh/id_rsa" \ + -b -m shell \ + -a 'sudo -u dashmate dashmate status services --format=json | jq -r ".[] | select(.service != \"core\") | \"\(.service): \(.status)\""' || true From 537e52dbdb4d27cf194e3af773289ce16eda7ac1 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 2 Apr 2026 18:32:22 +0000 Subject: [PATCH 2/5] fix: use requested dashmate version for config format --- ansible/roles/dashmate/tasks/main.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ansible/roles/dashmate/tasks/main.yml b/ansible/roles/dashmate/tasks/main.yml index 83f67303..3633d866 100644 --- a/ansible/roles/dashmate/tasks/main.yml +++ b/ansible/roles/dashmate/tasks/main.yml @@ -255,9 +255,14 @@ - dashmate_version is defined - (dashmate_needs_update | default(true)) or force_dashmate_reinstall | default(false) -- name: Set dashmate config version from already extracted version +- name: Set dashmate config version ansible.builtin.set_fact: - dashmate_config_version: "{{ installed_dashmate_version }}" + dashmate_config_version: >- + {{ + dashmate_version + if dashmate_version is defined + else installed_dashmate_version + }} # This check will return an error code if config is missing, config schema is invalid or default config is not yet set - name: Check state of dashmate config From 318ceef32224e774fd0b7347c6b14aad716b9aba Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 2 Apr 2026 19:26:30 +0000 Subject: [PATCH 3/5] fix: always add dashmate user to docker group --- ansible/roles/dashmate/tasks/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/ansible/roles/dashmate/tasks/main.yml b/ansible/roles/dashmate/tasks/main.yml index 3633d866..61a0333c 100644 --- a/ansible/roles/dashmate/tasks/main.yml +++ b/ansible/roles/dashmate/tasks/main.yml @@ -133,7 +133,6 @@ append: true when: - not (skip_dashmate_image_update | default(false)) - - not dashmate_user_exists # ============================================================================ # EARLY PERMISSION FIXES - Ensure all dashmate directories have correct ownership From 7e18fde3889528867efe2cd4c7e236c2336fc078 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 2 Apr 2026 19:33:20 +0000 Subject: [PATCH 4/5] fix: resume HP dashmate setup after docker access fix --- ansible/deploy.yml | 690 ++++++++++++++++++++++----------------------- 1 file changed, 345 insertions(+), 345 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index caf71d2d..1f20f50c 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,351 +1,351 @@ ---- - -# Bootstrap - -- name: Remove latency on masternodes before deployment starts - hosts: masternodes,hp_masternodes - become: true - roles: - - remove_fake_latency - tags: - - full_deploy - - maintenance - -- name: Set up swap and aws environment vars - hosts: all - gather_facts: true - become: true - pre_tasks: - - name: Check if inside AWS - ansible.builtin.uri: - url: http://169.254.169.254/latest/meta-data - timeout: 2 - register: aws_uri_check - failed_when: false - - name: Set AWS environment variable - ansible.builtin.set_fact: - is_aws_environment: '{{ aws_uri_check.status == 200 }}' - roles: - - role: aws - when: is_aws_environment - - swap - tags: - - full_deploy - - infra_setup - -- name: Setup VPN - hosts: vpn - become: true - roles: - - role: openvpn - when: openvpn_enabled - tags: - - full_deploy - - infra_setup - - vpn - -- name: Setup jq, Python, CWAgent and Docker - hosts: all - become: true - pre_tasks: - - name: Update apt cache and install jq - ansible.builtin.apt: - pkg: - - jq - - unzip - update_cache: true - vars: - pip_package: python3-pip - pip_install_packages: - - name: docker - version: "6.0.1" - - name: docker-compose - version: "1.29.2" - - name: requests - version: "2.31.0" - roles: - - geerlingguy.pip - - role: geerlingguy.docker - vars: - docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" - docker_install_compose: false - docker_users: - - ubuntu - - docker_options - - eternal_terminal - - cwagent - tags: - - full_deploy - - infra_setup - -- name: Configure tcpdump - hosts: all - become: true - roles: - - role: tcpdumpd - when: dashd_network_logging != 0 - tags: - - full_deploy - - infra_setup - -- name: Setup logs - hosts: logs_nodes - become: true - roles: - - elastic_stack - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Setup load tester - hosts: load_test - become: true - roles: - - role: protobuf_compiler - - role: load_tool - tags: - - full_deploy - - infra_setup - -- name: Setup metrics - hosts: metrics - become: true - roles: - - metrics - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Set up miners - hosts: miners - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up mixers - hosts: mixer_nodes - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up core and tenderdash on seed nodes - hosts: seed_nodes - become: true - pre_tasks: - - name: Set node variables for seed nodes - ansible.builtin.set_fact: - node: "{{ seed_nodes[inventory_hostname] }}" - mode: "seed" - tags: always - when: inventory_hostname in seed_nodes - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - role: tenderdash - - core_filebeat - - metricbeat - tags: - - full_deploy - - update_seed_nodes - -- name: Set up core on masternodes - hosts: masternodes - become: true - pre_tasks: - - name: Check inventory for masternodes - ansible.builtin.set_fact: - masternode: "{{ masternodes[inventory_hostname] }}" - tags: always - when: inventory_hostname in masternodes - - name: Fail if no masternodes present - ansible.builtin.fail: - msg: Masternode not defined in network config - when: masternode is not defined - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - mn_status_report - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - - update_masternodes - - -# Start network - -- name: Generate first block to leave IBD mode - hosts: seed-1 - become: true - roles: - - role: generate_firstblock - when: dash_network == "devnet" or dash_network == "regtest" - tags: - - full_deploy - -- name: Start miner - hosts: miners - become: true - roles: - - role: dashd_generate_miner - when: dash_network != "mainnet" - tags: - - full_deploy - -- name: Setup faucet and insight - hosts: web - become: true - roles: - - multifaucet - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - dashd_listen: true - - insight - - role: status_dashboard - when: dash_network == "devnet" - - core_filebeat - - metricbeat - tags: - - full_deploy - - web - -- name: Deploy status monitoring to masternodes - hosts: masternodes,hp_masternodes - become: true - gather_facts: false - strategy: free - roles: - - status_monitoring - tags: - - full_deploy - - dashmate_deploy - - status_dashboard - -- name: Set up wallets - hosts: wallet_nodes - become: true - roles: - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - enable_wallet: true - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - -# Register masternodes and set sporks - -- name: Register masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ masternodes }}" - funding_amount: "{{ masternode_collaterals.mn | int }}" - tags: - - full_deploy - - unban_masternodes - -- name: Update inventory with protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ masternodes }}" - tags: - - full_deploy - - unban_masternodes - -- name: Register HP masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ hp_masternodes }}" - funding_amount: "{{ masternode_collaterals.hpmn | int }}" - tags: - - full_deploy - - unban_hp_masternodes - -- name: Update inventory with HPMN protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ hp_masternodes }}" - tags: - - full_deploy - - unban_hp_masternodes - - -- name: Fund load tester nodes - hosts: wallet_nodes - become: true - tasks: - - name: Extract load tester addresses - ansible.builtin.set_fact: - load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" - when: load_testers is defined and load_testers | length > 0 - - - name: Include funding for load testers - ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml - vars: - payment_targets: "{{ load_tester_addresses }}" - amount: "{{ load_tester_wallet_amount }}" - when: load_testers is defined and load_testers | length > 0 - tags: - - full_deploy - -- name: Activate sporks - hosts: wallet_nodes - become: true - roles: - - role: activate_dashd_sporks - when: dash_network != "mainnet" and dash_network != "testnet" - delegate_to: '{{ play_hosts | first }}' - tags: - - full_deploy - -# todo: partially working code causes errors in deploy, comment out for now and fix later -# - name: Create governance proposals +# --- +# +# # Bootstrap +# +# - name: Remove latency on masternodes before deployment starts +# hosts: masternodes,hp_masternodes +# become: true +# roles: +# - remove_fake_latency +# tags: +# - full_deploy +# - maintenance +# +# - name: Set up swap and aws environment vars +# hosts: all +# gather_facts: true +# become: true +# pre_tasks: +# - name: Check if inside AWS +# ansible.builtin.uri: +# url: http://169.254.169.254/latest/meta-data +# timeout: 2 +# register: aws_uri_check +# failed_when: false +# - name: Set AWS environment variable +# ansible.builtin.set_fact: +# is_aws_environment: '{{ aws_uri_check.status == 200 }}' +# roles: +# - role: aws +# when: is_aws_environment +# - swap +# tags: +# - full_deploy +# - infra_setup +# +# - name: Setup VPN +# hosts: vpn +# become: true +# roles: +# - role: openvpn +# when: openvpn_enabled +# tags: +# - full_deploy +# - infra_setup +# - vpn +# +# - name: Setup jq, Python, CWAgent and Docker +# hosts: all +# become: true +# pre_tasks: +# - name: Update apt cache and install jq +# ansible.builtin.apt: +# pkg: +# - jq +# - unzip +# update_cache: true +# vars: +# pip_package: python3-pip +# pip_install_packages: +# - name: docker +# version: "6.0.1" +# - name: docker-compose +# version: "1.29.2" +# - name: requests +# version: "2.31.0" +# roles: +# - geerlingguy.pip +# - role: geerlingguy.docker +# vars: +# docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" +# docker_install_compose: false +# docker_users: +# - ubuntu +# - docker_options +# - eternal_terminal +# - cwagent +# tags: +# - full_deploy +# - infra_setup +# +# - name: Configure tcpdump +# hosts: all +# become: true +# roles: +# - role: tcpdumpd +# when: dashd_network_logging != 0 +# tags: +# - full_deploy +# - infra_setup +# +# - name: Setup logs +# hosts: logs_nodes +# become: true +# roles: +# - elastic_stack +# - metricbeat +# tags: +# - full_deploy +# - infra_setup +# +# - name: Setup load tester +# hosts: load_test +# become: true +# roles: +# - role: protobuf_compiler +# - role: load_tool +# tags: +# - full_deploy +# - infra_setup +# +# - name: Setup metrics +# hosts: metrics +# become: true +# roles: +# - metrics +# - metricbeat +# tags: +# - full_deploy +# - infra_setup +# +# - name: Set up miners +# hosts: miners +# become: true +# roles: +# - role: dash_cli +# - role: dashd +# tags: +# - dashd +# - core_filebeat +# - metricbeat +# tags: +# - full_deploy +# +# - name: Set up mixers +# hosts: mixer_nodes +# become: true +# roles: +# - role: dash_cli +# - role: dashd +# tags: +# - dashd +# - core_filebeat +# - metricbeat +# tags: +# - full_deploy +# +# - name: Set up core and tenderdash on seed nodes +# hosts: seed_nodes +# become: true +# pre_tasks: +# - name: Set node variables for seed nodes +# ansible.builtin.set_fact: +# node: "{{ seed_nodes[inventory_hostname] }}" +# mode: "seed" +# tags: always +# when: inventory_hostname in seed_nodes +# roles: +# - role: dash_cli +# - role: dashd +# dashd_listen: true +# dashd_zmq: true +# dashd_indexes: true +# tags: +# - dashd +# - role: tenderdash +# - core_filebeat +# - metricbeat +# tags: +# - full_deploy +# - update_seed_nodes +# +# - name: Set up core on masternodes +# hosts: masternodes +# become: true +# pre_tasks: +# - name: Check inventory for masternodes +# ansible.builtin.set_fact: +# masternode: "{{ masternodes[inventory_hostname] }}" +# tags: always +# when: inventory_hostname in masternodes +# - name: Fail if no masternodes present +# ansible.builtin.fail: +# msg: Masternode not defined in network config +# when: masternode is not defined +# roles: +# - role: dash_cli +# - role: dashd +# dashd_listen: true +# dashd_zmq: true +# dashd_indexes: true +# tags: +# - dashd +# - mn_status_report +# - core_filebeat +# - metricbeat +# tags: +# - full_deploy +# - core_update +# - update_masternodes +# +# +# # Start network +# +# - name: Generate first block to leave IBD mode +# hosts: seed-1 +# become: true +# roles: +# - role: generate_firstblock +# when: dash_network == "devnet" or dash_network == "regtest" +# tags: +# - full_deploy +# +# - name: Start miner +# hosts: miners +# become: true +# roles: +# - role: dashd_generate_miner +# when: dash_network != "mainnet" +# tags: +# - full_deploy +# +# - name: Setup faucet and insight +# hosts: web +# become: true +# roles: +# - multifaucet +# - role: dash_cli +# - role: dashd +# dashd_indexes: true +# dashd_zmq: true +# dashd_listen: true +# - insight +# - role: status_dashboard +# when: dash_network == "devnet" +# - core_filebeat +# - metricbeat +# tags: +# - full_deploy +# - web +# +# - name: Deploy status monitoring to masternodes +# hosts: masternodes,hp_masternodes +# become: true +# gather_facts: false +# strategy: free +# roles: +# - status_monitoring +# tags: +# - full_deploy +# - dashmate_deploy +# - status_dashboard +# +# - name: Set up wallets # hosts: wallet_nodes # become: true # roles: -# - role: generate_proposals -# when: governance_proposal_count > 0 - +# - role: dash_cli +# - role: dashd +# dashd_indexes: true +# dashd_zmq: true +# enable_wallet: true +# tags: +# - dashd +# - core_filebeat +# - metricbeat +# tags: +# - full_deploy +# - core_update +# +# # Register masternodes and set sporks +# +# - name: Register masternodes +# hosts: wallet_nodes +# become: true +# roles: +# - role: mn_init +# mnlist: "{{ masternodes }}" +# funding_amount: "{{ masternode_collaterals.mn | int }}" +# tags: +# - full_deploy +# - unban_masternodes +# +# - name: Update inventory with protx values +# hosts: wallet_nodes +# roles: +# - role: mn_protx_config +# mnlist: "{{ masternodes }}" +# tags: +# - full_deploy +# - unban_masternodes +# +# - name: Register HP masternodes +# hosts: wallet_nodes +# become: true +# roles: +# - role: mn_init +# mnlist: "{{ hp_masternodes }}" +# funding_amount: "{{ masternode_collaterals.hpmn | int }}" +# tags: +# - full_deploy +# - unban_hp_masternodes +# +# - name: Update inventory with HPMN protx values +# hosts: wallet_nodes +# roles: +# - role: mn_protx_config +# mnlist: "{{ hp_masternodes }}" +# tags: +# - full_deploy +# - unban_hp_masternodes +# +# +# - name: Fund load tester nodes +# hosts: wallet_nodes +# become: true +# tasks: +# - name: Extract load tester addresses +# ansible.builtin.set_fact: +# load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" +# when: load_testers is defined and load_testers | length > 0 +# +# - name: Include funding for load testers +# ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml +# vars: +# payment_targets: "{{ load_tester_addresses }}" +# amount: "{{ load_tester_wallet_amount }}" +# when: load_testers is defined and load_testers | length > 0 +# tags: +# - full_deploy +# +# - name: Activate sporks +# hosts: wallet_nodes +# become: true +# roles: +# - role: activate_dashd_sporks +# when: dash_network != "mainnet" and dash_network != "testnet" +# delegate_to: '{{ play_hosts | first }}' +# tags: +# - full_deploy +# +# # todo: partially working code causes errors in deploy, comment out for now and fix later +# # - name: Create governance proposals +# # hosts: wallet_nodes +# # become: true +# # roles: +# # - role: generate_proposals +# # when: governance_proposal_count > 0 +# - name: Set up core and platform on HP masternodes hosts: hp_masternodes become: true From 6aec7cf99cba8450e5083bf1eb95e6df43beffeb Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 2 Apr 2026 19:42:50 +0000 Subject: [PATCH 5/5] fix: correct fresh-node dashmate setup --- ansible/deploy.yml | 690 ++++++++++++++++++++++----------------------- 1 file changed, 345 insertions(+), 345 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 1f20f50c..caf71d2d 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,351 +1,351 @@ -# --- -# -# # Bootstrap -# -# - name: Remove latency on masternodes before deployment starts -# hosts: masternodes,hp_masternodes -# become: true -# roles: -# - remove_fake_latency -# tags: -# - full_deploy -# - maintenance -# -# - name: Set up swap and aws environment vars -# hosts: all -# gather_facts: true -# become: true -# pre_tasks: -# - name: Check if inside AWS -# ansible.builtin.uri: -# url: http://169.254.169.254/latest/meta-data -# timeout: 2 -# register: aws_uri_check -# failed_when: false -# - name: Set AWS environment variable -# ansible.builtin.set_fact: -# is_aws_environment: '{{ aws_uri_check.status == 200 }}' -# roles: -# - role: aws -# when: is_aws_environment -# - swap -# tags: -# - full_deploy -# - infra_setup -# -# - name: Setup VPN -# hosts: vpn -# become: true -# roles: -# - role: openvpn -# when: openvpn_enabled -# tags: -# - full_deploy -# - infra_setup -# - vpn -# -# - name: Setup jq, Python, CWAgent and Docker -# hosts: all -# become: true -# pre_tasks: -# - name: Update apt cache and install jq -# ansible.builtin.apt: -# pkg: -# - jq -# - unzip -# update_cache: true -# vars: -# pip_package: python3-pip -# pip_install_packages: -# - name: docker -# version: "6.0.1" -# - name: docker-compose -# version: "1.29.2" -# - name: requests -# version: "2.31.0" -# roles: -# - geerlingguy.pip -# - role: geerlingguy.docker -# vars: -# docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" -# docker_install_compose: false -# docker_users: -# - ubuntu -# - docker_options -# - eternal_terminal -# - cwagent -# tags: -# - full_deploy -# - infra_setup -# -# - name: Configure tcpdump -# hosts: all -# become: true -# roles: -# - role: tcpdumpd -# when: dashd_network_logging != 0 -# tags: -# - full_deploy -# - infra_setup -# -# - name: Setup logs -# hosts: logs_nodes -# become: true -# roles: -# - elastic_stack -# - metricbeat -# tags: -# - full_deploy -# - infra_setup -# -# - name: Setup load tester -# hosts: load_test -# become: true -# roles: -# - role: protobuf_compiler -# - role: load_tool -# tags: -# - full_deploy -# - infra_setup -# -# - name: Setup metrics -# hosts: metrics -# become: true -# roles: -# - metrics -# - metricbeat -# tags: -# - full_deploy -# - infra_setup -# -# - name: Set up miners -# hosts: miners -# become: true -# roles: -# - role: dash_cli -# - role: dashd -# tags: -# - dashd -# - core_filebeat -# - metricbeat -# tags: -# - full_deploy -# -# - name: Set up mixers -# hosts: mixer_nodes -# become: true -# roles: -# - role: dash_cli -# - role: dashd -# tags: -# - dashd -# - core_filebeat -# - metricbeat -# tags: -# - full_deploy -# -# - name: Set up core and tenderdash on seed nodes -# hosts: seed_nodes -# become: true -# pre_tasks: -# - name: Set node variables for seed nodes -# ansible.builtin.set_fact: -# node: "{{ seed_nodes[inventory_hostname] }}" -# mode: "seed" -# tags: always -# when: inventory_hostname in seed_nodes -# roles: -# - role: dash_cli -# - role: dashd -# dashd_listen: true -# dashd_zmq: true -# dashd_indexes: true -# tags: -# - dashd -# - role: tenderdash -# - core_filebeat -# - metricbeat -# tags: -# - full_deploy -# - update_seed_nodes -# -# - name: Set up core on masternodes -# hosts: masternodes -# become: true -# pre_tasks: -# - name: Check inventory for masternodes -# ansible.builtin.set_fact: -# masternode: "{{ masternodes[inventory_hostname] }}" -# tags: always -# when: inventory_hostname in masternodes -# - name: Fail if no masternodes present -# ansible.builtin.fail: -# msg: Masternode not defined in network config -# when: masternode is not defined -# roles: -# - role: dash_cli -# - role: dashd -# dashd_listen: true -# dashd_zmq: true -# dashd_indexes: true -# tags: -# - dashd -# - mn_status_report -# - core_filebeat -# - metricbeat -# tags: -# - full_deploy -# - core_update -# - update_masternodes -# -# -# # Start network -# -# - name: Generate first block to leave IBD mode -# hosts: seed-1 -# become: true -# roles: -# - role: generate_firstblock -# when: dash_network == "devnet" or dash_network == "regtest" -# tags: -# - full_deploy -# -# - name: Start miner -# hosts: miners -# become: true -# roles: -# - role: dashd_generate_miner -# when: dash_network != "mainnet" -# tags: -# - full_deploy -# -# - name: Setup faucet and insight -# hosts: web -# become: true -# roles: -# - multifaucet -# - role: dash_cli -# - role: dashd -# dashd_indexes: true -# dashd_zmq: true -# dashd_listen: true -# - insight -# - role: status_dashboard -# when: dash_network == "devnet" -# - core_filebeat -# - metricbeat -# tags: -# - full_deploy -# - web -# -# - name: Deploy status monitoring to masternodes -# hosts: masternodes,hp_masternodes -# become: true -# gather_facts: false -# strategy: free -# roles: -# - status_monitoring -# tags: -# - full_deploy -# - dashmate_deploy -# - status_dashboard -# -# - name: Set up wallets -# hosts: wallet_nodes -# become: true -# roles: -# - role: dash_cli -# - role: dashd -# dashd_indexes: true -# dashd_zmq: true -# enable_wallet: true -# tags: -# - dashd -# - core_filebeat -# - metricbeat -# tags: -# - full_deploy -# - core_update -# -# # Register masternodes and set sporks -# -# - name: Register masternodes -# hosts: wallet_nodes -# become: true -# roles: -# - role: mn_init -# mnlist: "{{ masternodes }}" -# funding_amount: "{{ masternode_collaterals.mn | int }}" -# tags: -# - full_deploy -# - unban_masternodes -# -# - name: Update inventory with protx values -# hosts: wallet_nodes -# roles: -# - role: mn_protx_config -# mnlist: "{{ masternodes }}" -# tags: -# - full_deploy -# - unban_masternodes -# -# - name: Register HP masternodes -# hosts: wallet_nodes -# become: true -# roles: -# - role: mn_init -# mnlist: "{{ hp_masternodes }}" -# funding_amount: "{{ masternode_collaterals.hpmn | int }}" -# tags: -# - full_deploy -# - unban_hp_masternodes -# -# - name: Update inventory with HPMN protx values -# hosts: wallet_nodes -# roles: -# - role: mn_protx_config -# mnlist: "{{ hp_masternodes }}" -# tags: -# - full_deploy -# - unban_hp_masternodes -# -# -# - name: Fund load tester nodes -# hosts: wallet_nodes -# become: true -# tasks: -# - name: Extract load tester addresses -# ansible.builtin.set_fact: -# load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" -# when: load_testers is defined and load_testers | length > 0 -# -# - name: Include funding for load testers -# ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml -# vars: -# payment_targets: "{{ load_tester_addresses }}" -# amount: "{{ load_tester_wallet_amount }}" -# when: load_testers is defined and load_testers | length > 0 -# tags: -# - full_deploy -# -# - name: Activate sporks +--- + +# Bootstrap + +- name: Remove latency on masternodes before deployment starts + hosts: masternodes,hp_masternodes + become: true + roles: + - remove_fake_latency + tags: + - full_deploy + - maintenance + +- name: Set up swap and aws environment vars + hosts: all + gather_facts: true + become: true + pre_tasks: + - name: Check if inside AWS + ansible.builtin.uri: + url: http://169.254.169.254/latest/meta-data + timeout: 2 + register: aws_uri_check + failed_when: false + - name: Set AWS environment variable + ansible.builtin.set_fact: + is_aws_environment: '{{ aws_uri_check.status == 200 }}' + roles: + - role: aws + when: is_aws_environment + - swap + tags: + - full_deploy + - infra_setup + +- name: Setup VPN + hosts: vpn + become: true + roles: + - role: openvpn + when: openvpn_enabled + tags: + - full_deploy + - infra_setup + - vpn + +- name: Setup jq, Python, CWAgent and Docker + hosts: all + become: true + pre_tasks: + - name: Update apt cache and install jq + ansible.builtin.apt: + pkg: + - jq + - unzip + update_cache: true + vars: + pip_package: python3-pip + pip_install_packages: + - name: docker + version: "6.0.1" + - name: docker-compose + version: "1.29.2" + - name: requests + version: "2.31.0" + roles: + - geerlingguy.pip + - role: geerlingguy.docker + vars: + docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" + docker_install_compose: false + docker_users: + - ubuntu + - docker_options + - eternal_terminal + - cwagent + tags: + - full_deploy + - infra_setup + +- name: Configure tcpdump + hosts: all + become: true + roles: + - role: tcpdumpd + when: dashd_network_logging != 0 + tags: + - full_deploy + - infra_setup + +- name: Setup logs + hosts: logs_nodes + become: true + roles: + - elastic_stack + - metricbeat + tags: + - full_deploy + - infra_setup + +- name: Setup load tester + hosts: load_test + become: true + roles: + - role: protobuf_compiler + - role: load_tool + tags: + - full_deploy + - infra_setup + +- name: Setup metrics + hosts: metrics + become: true + roles: + - metrics + - metricbeat + tags: + - full_deploy + - infra_setup + +- name: Set up miners + hosts: miners + become: true + roles: + - role: dash_cli + - role: dashd + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + +- name: Set up mixers + hosts: mixer_nodes + become: true + roles: + - role: dash_cli + - role: dashd + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + +- name: Set up core and tenderdash on seed nodes + hosts: seed_nodes + become: true + pre_tasks: + - name: Set node variables for seed nodes + ansible.builtin.set_fact: + node: "{{ seed_nodes[inventory_hostname] }}" + mode: "seed" + tags: always + when: inventory_hostname in seed_nodes + roles: + - role: dash_cli + - role: dashd + dashd_listen: true + dashd_zmq: true + dashd_indexes: true + tags: + - dashd + - role: tenderdash + - core_filebeat + - metricbeat + tags: + - full_deploy + - update_seed_nodes + +- name: Set up core on masternodes + hosts: masternodes + become: true + pre_tasks: + - name: Check inventory for masternodes + ansible.builtin.set_fact: + masternode: "{{ masternodes[inventory_hostname] }}" + tags: always + when: inventory_hostname in masternodes + - name: Fail if no masternodes present + ansible.builtin.fail: + msg: Masternode not defined in network config + when: masternode is not defined + roles: + - role: dash_cli + - role: dashd + dashd_listen: true + dashd_zmq: true + dashd_indexes: true + tags: + - dashd + - mn_status_report + - core_filebeat + - metricbeat + tags: + - full_deploy + - core_update + - update_masternodes + + +# Start network + +- name: Generate first block to leave IBD mode + hosts: seed-1 + become: true + roles: + - role: generate_firstblock + when: dash_network == "devnet" or dash_network == "regtest" + tags: + - full_deploy + +- name: Start miner + hosts: miners + become: true + roles: + - role: dashd_generate_miner + when: dash_network != "mainnet" + tags: + - full_deploy + +- name: Setup faucet and insight + hosts: web + become: true + roles: + - multifaucet + - role: dash_cli + - role: dashd + dashd_indexes: true + dashd_zmq: true + dashd_listen: true + - insight + - role: status_dashboard + when: dash_network == "devnet" + - core_filebeat + - metricbeat + tags: + - full_deploy + - web + +- name: Deploy status monitoring to masternodes + hosts: masternodes,hp_masternodes + become: true + gather_facts: false + strategy: free + roles: + - status_monitoring + tags: + - full_deploy + - dashmate_deploy + - status_dashboard + +- name: Set up wallets + hosts: wallet_nodes + become: true + roles: + - role: dash_cli + - role: dashd + dashd_indexes: true + dashd_zmq: true + enable_wallet: true + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + - core_update + +# Register masternodes and set sporks + +- name: Register masternodes + hosts: wallet_nodes + become: true + roles: + - role: mn_init + mnlist: "{{ masternodes }}" + funding_amount: "{{ masternode_collaterals.mn | int }}" + tags: + - full_deploy + - unban_masternodes + +- name: Update inventory with protx values + hosts: wallet_nodes + roles: + - role: mn_protx_config + mnlist: "{{ masternodes }}" + tags: + - full_deploy + - unban_masternodes + +- name: Register HP masternodes + hosts: wallet_nodes + become: true + roles: + - role: mn_init + mnlist: "{{ hp_masternodes }}" + funding_amount: "{{ masternode_collaterals.hpmn | int }}" + tags: + - full_deploy + - unban_hp_masternodes + +- name: Update inventory with HPMN protx values + hosts: wallet_nodes + roles: + - role: mn_protx_config + mnlist: "{{ hp_masternodes }}" + tags: + - full_deploy + - unban_hp_masternodes + + +- name: Fund load tester nodes + hosts: wallet_nodes + become: true + tasks: + - name: Extract load tester addresses + ansible.builtin.set_fact: + load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" + when: load_testers is defined and load_testers | length > 0 + + - name: Include funding for load testers + ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml + vars: + payment_targets: "{{ load_tester_addresses }}" + amount: "{{ load_tester_wallet_amount }}" + when: load_testers is defined and load_testers | length > 0 + tags: + - full_deploy + +- name: Activate sporks + hosts: wallet_nodes + become: true + roles: + - role: activate_dashd_sporks + when: dash_network != "mainnet" and dash_network != "testnet" + delegate_to: '{{ play_hosts | first }}' + tags: + - full_deploy + +# todo: partially working code causes errors in deploy, comment out for now and fix later +# - name: Create governance proposals # hosts: wallet_nodes # become: true # roles: -# - role: activate_dashd_sporks -# when: dash_network != "mainnet" and dash_network != "testnet" -# delegate_to: '{{ play_hosts | first }}' -# tags: -# - full_deploy -# -# # todo: partially working code causes errors in deploy, comment out for now and fix later -# # - name: Create governance proposals -# # hosts: wallet_nodes -# # become: true -# # roles: -# # - role: generate_proposals -# # when: governance_proposal_count > 0 -# +# - role: generate_proposals +# when: governance_proposal_count > 0 + - name: Set up core and platform on HP masternodes hosts: hp_masternodes become: true