Skip to content

Deploy Network

Deploy Network #95

---
concurrency: ci-$ # Only a single workflow can be executed concurrently
name: Deploy Network
on: # yamllint disable-line rule:truthy
workflow_dispatch:
inputs:
environment:
description: The environment to run against
type: choice
options: [dev, test] # nightly should not be initiated manually
block_gas_limit:
description: Block Gas Limit
type: string
default: "200000000"
required: true
block_time:
description: Block Time
type: string
default: "2"
required: true
max_slots:
description: Max Slots
type: string
default: "276480"
required: true
max_enqueued:
description: Max Enqueued
type: string
default: "276480"
required: true
is_london_fork_active:
description: EIP-1559
type: boolean
default: true
is_bridge_active:
description: With Bridge
type: boolean
default: true
gossip_msg_size:
description: Gossip Message Size
type: string
default: "1048576"
required: true
notification:
description: Notification
type: boolean
default: true
workflow_call:
inputs:
environment:
description: The environment to run against
type: string
required: true
block_gas_limit:
description: Block Gas Limit
type: string
required: true
block_time:
description: Block Time
type: string
required: true
max_slots:
description: Max Slots
type: string
required: true
max_enqueued:
description: Max Enqueued
type: string
required: true
is_london_fork_active:
description: EIP-1559
type: boolean
required: true
is_bridge_active:
description: With Bridge
type: boolean
required: true
gossip_msg_size:
description: Gossip Message Size
type: string
required: true
notification:
description: Notification
type: boolean
required: true
outputs:
terraform_output:
description: Terraform output
value: ${{ jobs.deploy_network.outputs.terraform_output }}
ansible_output:
description: Ansible output
value: ${{ jobs.deploy_network.outputs.ansible_output }}
blade_healthcheck_output:
description: Blade Healthcheck output
value: ${{ jobs.deploy_network.outputs.blade_healthcheck_output }}
rpc_url:
description: RPC URL
value: ${{ jobs.check_network.outputs.rpc_url || jobs.deploy_network.outputs.rpc_url }}
secrets:
AWS_ROLE_ARN:
required: true
AWS_S3_BLADE_BUCKET:
required: true
VAULT_PASSWORD:
required: true
permissions:
id-token: write
contents: read
security-events: write
jobs:
check_network:
name: Check if the network is already deployed
runs-on: ubuntu-latest
outputs:
check_output: ${{ steps.check_state_file.outputs.resources }}
rpc_url: ${{ steps.rpc_url.outputs.url }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
aws-region: ${{ vars.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
- name: Retrieve state file from s3
id: retrieve_state
run: echo "retrieve_state_output=$(aws s3 cp s3://${{ secrets.AWS_S3_BLADE_BUCKET }}/states/${{ inputs.environment }} state.json)" >> $GITHUB_OUTPUT
- name: Check state file
id: check_state_file
if: contains(steps.retrieve_state.outputs.retrieve_state_output, 'download')
run: echo "resources=$(cat state.json | jq -r '.resources' | jq length)" >> $GITHUB_OUTPUT
- name: Set RPC URL
id: rpc_url
if: contains(steps.retrieve_state.outputs.retrieve_state_output, 'download')
run: echo "url=$(cat state.json | jq -r '.outputs.aws_lb_ext_domain.value // empty')" >> $GITHUB_OUTPUT
deploy_network:
name: Deploy the network
runs-on: ubuntu-latest
needs: check_network
if: needs.check_network.outputs.check_output == 0
environment: ${{ inputs.environment }}
outputs:
terraform_output: ${{ steps.terraform_failure.outputs.terraform_output }}
ansible_output: ${{ steps.ansible_failure.outputs.ansible_output }}
blade_healthcheck_output: ${{ steps.blade_healthcheck.outputs.healthcheck }}
rpc_url: ${{ steps.rpc_url.outputs.url }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1
with:
repository: Ethernal-Tech/blade-deployment
ref: main
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
aws-region: ${{ vars.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
- name: Install Terraform
uses: hashicorp/setup-terraform@v3.0.0
with:
terraform_version: 1.4.5
- name: Configure Terraform
run: sed 's/# backend "s3" {}/backend "s3" {}/' main.tf > main.tf.tmp && mv main.tf.tmp main.tf
- name: Terraform Init
run: terraform init -backend-config="bucket=${{ secrets.AWS_S3_BLADE_BUCKET }}" -backend-config="key=states/${{ inputs.environment }}" -backend-config="region=${{ vars.AWS_REGION }}"
- name: Terraform Validate
run: terraform validate -no-color
continue-on-error: true
- name: Terraform Apply
run: terraform apply -auto-approve
env:
TF_VAR_deployment_name: ${{ inputs.environment }}
TF_VAR_base_instance_type: ${{ vars.AWS_INSTANCE_TYPE }}
TF_VAR_geth_count: ${{ vars.GETH_COUNT }}
TF_VAR_fullnode_count: ${{ vars.FULLNODE_COUNT }}
TF_VAR_validator_count: ${{ vars.VALIDATOR_COUNT }}
- name: Terraform Failed
if: failure()
id: terraform_failure
run: echo "terraform_output=false" >> $GITHUB_OUTPUT
- name: Configure private keys
run: |
terraform output pk_ansible > ~/private.key
chmod 600 ~/private.key
eval "$(ssh-agent)"
ssh-add ~/private.key
- name: Install Ansible / botocore / boto3
run: |
python3 -m pip install --user ansible
python3 -m pip install boto3 botocore
- name: Configure Ansible
working-directory: ansible
run: |
echo "${{ secrets.VAULT_PASSWORD }}" > password.txt
sed 's/devnet/${{ inputs.environment }}/g' inventory/aws_ec2.yml > inventory/aws_ec2.yml.tmp && mv inventory/aws_ec2.yml.tmp inventory/aws_ec2.yml
sed 's/blade_tag: .*/blade_tag: ${{ github.sha }}/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/is_bridge_active: .*/is_bridge_active: ${{ inputs.is_bridge_active }}/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/is_london_fork_active: .*/is_london_fork_active: ${{ inputs.is_london_fork_active }}/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/gossip_msg_size: .*/gossip_msg_size: ${{ inputs.gossip_msg_size }}/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/tx_gossip_batch_size: .*/tx_gossip_batch_size: 10000/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/json_rpc_batch_request_limit: .*/json_rpc_batch_request_limit: 0/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/log_level: .*/log_level: ${{ vars.LOG_LEVEL }}/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/epoch_reward: .*/epoch_reward: 1000000000/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/reward_wallet_balance: .*/reward_wallet_balance: 0xD3C21BCECCEDA1000000/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
sed 's/config_socket: .*/config_socket: ${{ vars.CONFIG_SOCKET }}/g' group_vars/all.yml > group_vars/all.yml.tmp && mv group_vars/all.yml.tmp group_vars/all.yml
- name: Setup Ansible
working-directory: ansible
run: |
ansible-inventory --graph
ansible-galaxy install -r requirements.yml
- name: Check previous blade data
id: previous_data
run: echo "previous_data_output=$(aws s3 cp s3://${{ secrets.AWS_S3_BLADE_BUCKET }}/states/${{ inputs.environment }}.data.tar.gz .)" >> $GITHUB_OUTPUT
- name: Run Ansible (Bootstrap blade)
if: (steps.previous_data.outputs.previous_data_output == '' || contains(steps.previous_data.outputs.previous_data_output, 'error'))
working-directory: ansible
run: ansible-playbook site.yml --extra-vars "clean_deploy_title=${{ inputs.environment }} blade_repository=${{ github.repository }} block_gas_limit=${{ inputs.block_gas_limit }} block_time=${{ inputs.block_time }} max_slots=${{ inputs.max_slots }} max_enqueued=${{ inputs.max_enqueued }}"
- name: Run Ansible (Restore data)
if: contains(steps.previous_data.outputs.previous_data_output, 'download')
working-directory: ansible
run: ansible-playbook site.yml --extra-vars "clean_deploy_title=${{ inputs.environment }} blade_repository=${{ github.repository }} s3_bucket=${{ secrets.AWS_S3_BLADE_BUCKET }} restore_data=true"
- name: Ansible Failed
if: failure()
id: ansible_failure
run: echo "ansible_output=false" >> $GITHUB_OUTPUT
- name: Set RPC URL
id: rpc_url
run: echo "url=$(terraform output -raw aws_lb_ext_domain | grep -o -E '^ext[^:]*')" >> $GITHUB_OUTPUT
- name: Blade healthcheck
id: blade_healthcheck
run: echo "healthcheck=`curl http://${{ steps.rpc_url.outputs.url }} | jq -r 'select(.name == "blade") | length != 0'`" >> $GITHUB_OUTPUT
notification:
name: Deploy Notification
needs: [check_network, deploy_network]
uses: ./.github/workflows/notification-deploy-network.yml
if: ((success() || failure()) && inputs.notification)
with:
environment: ${{ inputs.environment }}
block_gas_limit: ${{ inputs.block_gas_limit }}
block_time: ${{ inputs.block_time }}
max_slots: ${{ inputs.max_slots }}
max_enqueued: ${{ inputs.max_enqueued }}
is_london_fork_active: ${{ inputs.is_london_fork_active }}
is_bridge_active: ${{ inputs.is_bridge_active }}
gossip_msg_size: ${{ inputs.gossip_msg_size }}
deploy_network_terraform_output: ${{ needs.deploy_network.outputs.terraform_output }}
deploy_network_ansible_output: ${{ needs.deploy_network.outputs.ansible_output }}
deploy_network_blade_healthcheck_output: ${{ needs.deploy_network.outputs.blade_healthcheck_output }}
rpc_url: ${{ needs.check_network.outputs.rpc_url || needs.deploy_network.outputs.rpc_url }}
secrets:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}