version: 2 jobs: verify: docker: - image: circleci/golang:latest steps: - checkout - run: name: Download and Install Terraform command: | wget -O terraform.zip https://releases.hashicorp.com/terraform/0.13.5/terraform_0.13.5_linux_amd64.zip unzip terraform.zip sudo mv terraform /usr/local/bin/terraform - run: for dir in $(find . -name \*.tf -exec dirname {} \; | sort | uniq | grep -v './ESXi'); do echo ${dir} && terraform init ${dir} && terraform validate ${dir}; done - run: terraform fmt -check hold: machine: true steps: - run: echo "This build requires approval to continue..." build: machine: true working_directory: ~/repo steps: - checkout - run: name: Create directory for artifacts command: | # Create artifacts directory if [ ! -d "/tmp/artifacts" ]; then mkdir /tmp/artifacts fi - run: name: Creating a Packet Server command: | ## Provision a Type1 baremetal Packet.net server echo "[$(date +%H:%M:%S)]: Provisioning a server on Packet.net" DEVICE_ID=$(curl -s -X POST --header 'Accept: application/json' --header 'Content-Type: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" -d '{ "facility": "sjc1", "plan": "baremetal_1", "hostname": "detectionlab", "description": "testing", "billing_cycle": "hourly", "operating_system": "ubuntu_18_04", "userdata": "", "locked": "false", "project_ssh_keys": ["315a9565-d5b1-41b6-913d-fcf022bb89a6", "755b134a-f63c-4fc5-9103-c1b63e65fdfc"] }' 'https://api.packet.net/projects/0b3f4f2e-ff05-41a8-899d-7923f620ca85/devices' | jq ."id" | tr -d '"') echo $DEVICE_ID > /tmp/device_id # Make sure the device ID is sane. # TODO: maybe make this a regex if [ "$(echo -n $DEVICE_ID | wc -c)" -ne 36 ]; then echo "[$(date +%H:%M:%S)]: Server may have failed provisionining. Device ID is set to: $DEVICE_ID" echo "[$(date +%H:%M:%S)]: This usually happens if there are no servers available in the selected datacenter." echo "[$(date +%H:%M:%S)]: Attempting to retry in another datacenter..." export DEVICE_ID=$(curl -s -X POST --header 'Accept: application/json' --header 'Content-Type: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" -d '{ "facility": "ewr1", "plan": "baremetal_1", "hostname": "detectionlab", "description": "testing", "billing_cycle": "hourly", "operating_system": "ubuntu_18_04", "userdata": "", "locked": "false", "project_ssh_keys": ["315a9565-d5b1-41b6-913d-fcf022bb89a6", "755b134a-f63c-4fc5-9103-c1b63e65fdfc"] }' 'https://api.packet.net/projects/0b3f4f2e-ff05-41a8-899d-7923f620ca85/devices' | jq ."id" | tr -d '"') if [ "$(echo -n $DEVICE_ID | wc -c)" -ne 36 ]; then echo "[$(date +%H:%M:%S)]: This script was still unable to successfully provision a server. Exiting." exit 1 fi fi echo "[$(date +%H:%M:%S)]: Server successfully created with ID: $DEVICE_ID" - run: name: Waiting for Packet server provisioning to complete command: | DEVICE_ID=$(cat /tmp/device_id) echo "[$(date +%H:%M:%S)]: Waiting for server to finish provisioning..." # Continue to poll the API until the state of the host is "active" export STATE="provisioning" while [ "$STATE" != "active" ]; do sleep 10 echo "[$(date +%H:%M:%S)]: Sleeping for 10 seconds. Server is still $STATE." export STATE="$(curl -s --header 'Accept: application/json' --header 'Content-Type: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" "https://api.packet.net/devices/$DEVICE_ID" | jq .state | tr -d '"')" done echo "[$(date +%H:%M:%S)]: Device with ID $DEVICE_ID has finished provisioning! Onto the build process..." - run: name: Mount external storage command: | DEVICE_ID=$(cat /tmp/device_id) ## Mount external storage containing Vagrant boxes echo "[$(date +%H:%M:%S)]: Attempting to mount external storage to this server..." MOUNT_STATUS=$(curl -s -X POST --header 'Accept: application/json' --header 'Content-Type: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" -d '{"device_id": "'"$DEVICE_ID"'"}' 'https://api.packet.net/storage/fed37d73-6719-451a-9160-df8b0addc915/attachments' | jq .id | wc -c) # Stupid check to make sure MOUNT_STATUS contains a UUID if [ "$MOUNT_STATUS" != "39" ]; then echo "[$(date +%H:%M:%S)]: Mounting may have failed. ID is $MOUNT_STATUS" else echo "[$(date +%H:%M:%S)]: External storage successfully mounted!" fi - run: name: Record the IP address of the Packet server command: | ## Recording the IP address of the newly provisioned Packet server DEVICE_ID=$(cat /tmp/device_id) IP_ADDRESS=$(curl -s -X GET --header 'Accept: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" "https://api.packet.net/devices/$DEVICE_ID/ips" | jq ."ip_addresses[0].address" | tr -d '"') echo $IP_ADDRESS > /tmp/ip_address - run: name: SCP Repo to Packet Server command: | # Copy repo to Packet server # TODO: Tar up the repo and expand it remotely IP_ADDRESS=$(cat /tmp/ip_address) cd ~/repo && rsync -Paq -e "ssh -i ~/.ssh/id_rsa" ~/repo/ root@"$IP_ADDRESS":/opt/DetectionLab - run: name: Run the build machine bootstrap script command: | IP_ADDRESS=$(cat /tmp/ip_address) ssh -i ~/.ssh/id_rsa root@"$IP_ADDRESS" 'bash -s' -- < ci/build_machine_bootstrap.sh - run: name: Wait for build results command: | export MINUTES_PAST=0 IP_ADDRESS=$(cat /tmp/ip_address) DEVICE_ID=$(cat /tmp/device_id) while [ "$MINUTES_PAST" -le 240 ]; do export STATUS=$(curl -s $IP_ADDRESS) if [ "$STATUS" == "building" ]; then echo "[$(date +%H:%M:%S)]: $STATUS" scp -q -i ~/.ssh/id_rsa root@"$IP_ADDRESS":/opt/DetectionLab/Vagrant/*.log /tmp/artifacts/ || echo "Vagrant log not yet present" sleep 300 ((MINUTES_PAST += 5)) else scp -q -i ~/.ssh/id_rsa root@"$IP_ADDRESS":/opt/DetectionLab/Vagrant/*.log /tmp/artifacts/ || echo "Vagrant log not yet present" echo "$STATUS" > /tmp/status break fi if [ "$MINUTES_PAST" -gt 120 ]; then echo "[$(date +%H:%M:%S)]: Serer timed out. Uptime: $MINUTES_PAST minutes." scp -q -i ~/.ssh/id_rsa root@"$IP_ADDRESS":/opt/DetectionLab/Vagrant/vagrant_up_*.log /tmp/artifacts/ curl -s -X DELETE --header 'Accept: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" 'https://api.packet.net/devices/'"$DEVICE_ID"'?force_delete=true' exit 1 fi done - run: name: Post the build results command: | ## Recording the build results STATUS=$(cat /tmp/status) IP_ADDRESS=$(cat /tmp/ip_address) DEVICE_ID=$(cat /tmp/device_id) echo "[$(date +%H:%M:%S)]: $STATUS" if [ "$STATUS" != "success" ]; then scp -q -i ~/.ssh/id_rsa root@"$IP_ADDRESS":/opt/DetectionLab/Vagrant/vagrant_up_*.log /tmp/artifacts/ echo "Build failed. Cleaning up server with ID $DEVICE_ID" curl -s -X DELETE --header 'Accept: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" 'https://api.packet.net/devices/'"$DEVICE_ID"'?force_delete=true' exit 1 fi echo "[$(date +%H:%M:%S)]: Build was successful. Cleaning up server with ID $DEVICE_ID" curl -s -X DELETE --header 'Accept: application/json' --header 'X-Auth-Token: '"$PACKET_API_TOKEN" 'https://api.packet.net/devices/'"$DEVICE_ID"'?force_delete=true' exit 0 - store_artifacts: path: /tmp/artifacts workflows: version: 2 workflow: jobs: - verify - hold: requires: - verify type: approval filters: branches: # Don't rebuild the PR after it has been merged into master # Users cannot push directly to master as it is a protected branch ignore: master - build: requires: - hold filters: branches: # Don't rebuild the PR after it has been merged into master ignore: master weekly-build: jobs: - build triggers: - schedule: cron: "0 0 * * 0" filters: branches: # Automatically re-build the contents of master once per week only: master