diff --git a/.circleci/ansible/configure-server.yml b/.circleci/ansible/configure-server.yml index bc38c9d..3f4117d 100644 --- a/.circleci/ansible/configure-server.yml +++ b/.circleci/ansible/configure-server.yml @@ -14,15 +14,13 @@ pre_tasks: - name: "wait 600 seconds for target connection to become reachable/usable." - # Your code here + wait_for_connection: - name: "install python for Ansible." - # Your code here - - # Get the environment variables from CircleCI and add to the EC2 instance - environment: - - TYPEORM_CONNECTION: "{{ lookup('env', 'TYPEORM_CONNECTION')}}" - # Add more env vars here - + apt: + name: python3 + state: latest + roles: - # Your code here \ No newline at end of file + - configure-server + - configure-prometheus-node-exporter \ No newline at end of file diff --git a/.circleci/ansible/roles/configure-server/tasks/main.yml b/.circleci/ansible/roles/configure-server/tasks/main.yml new file mode 100644 index 0000000..6a3b29e --- /dev/null +++ b/.circleci/ansible/roles/configure-server/tasks/main.yml @@ -0,0 +1,30 @@ +--- +- name: "update apt packages." + become: yes + apt: + update_cache: yes + +- name: "upgrade packages." + become: yes + apt: + upgrade: "yes" + +- name: remove dependencies that are no longer required + become: yes + apt: + autoremove: yes + +- name: "install dependencies." + become: yes + apt: + name: ["nodejs", "npm"] + state: latest + update_cache: yes + +- name: "install pm2" + become: yes + npm: + name: pm2 + global: yes + production: yes + state: present \ No newline at end of file diff --git a/.circleci/ansible/roles/deploy/tasks/main.yml b/.circleci/ansible/roles/deploy/tasks/main.yml new file mode 100644 index 0000000..bfb916f --- /dev/null +++ b/.circleci/ansible/roles/deploy/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: copy dist backend folder to ec2 instance + become: yes + copy: + src: ~/project/artifact.tar.gz + dest: /home/ubuntu/artifact.tar.gz + +- name: prepare binaries + become: true + shell: | + cd /home/ubuntu + tar xvzf artifact.tar.gz -C . + +- name: "start server" + become: true + become_method: sudo + become_user: root + shell: | + cd /home/ubuntu + npm install + pm2 stop default + pm2 start npm -- start + pm2 startup + pm2 save \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index de97451..520075d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,30 +3,25 @@ version: 2.1 commands: destroy-environment: description: Destroy back-end and front-end cloudformation stacks given a workflow ID. - parameters: - workflow_id: - type: string - default: ${CIRCLE_WORKFLOW_ID:0:7} steps: - run: name: Destroy environments when: on_fail command: | + if aws s3 ls | grep "udapeople-${CIRCLE_WORKFLOW_ID:0:7}"; then + aws s3 rm s3://udapeople-${CIRCLE_WORKFLOW_ID:0:7} --recursive + fi aws cloudformation delete-stack --stack-name udapeople-backend-${CIRCLE_WORKFLOW_ID:0:7} aws cloudformation delete-stack --stack-name udapeople-frontend-${CIRCLE_WORKFLOW_ID:0:7} revert-migrations: description: Revert the last migration if successfully run in the current workflow. - parameters: - workflow_id: - type: string - default: ${CIRCLE_WORKFLOW_ID:0:7} steps: - run: name: Revert migrations when: on_fail command: | echo "insecure" >> ~/.curlrc - SUCCESS=$(curl --insecure https://kvdb.io/VZNDWCZz5NPBkEr81irH3u/migration_<< parameters.workflow_id >>) + SUCCESS=$(curl --insecure https://kvdb.io/VZNDWCZz5NPBkEr81irH3u/migration_${CIRCLE_WORKFLOW_ID:0:7}) if(( $SUCCESS==1 )); then cd ~/project/backend @@ -155,6 +150,19 @@ jobs: --tags project=cicd_project \ --stack-name "udapeople-frontend-${CIRCLE_WORKFLOW_ID:0:7}" \ --parameter-overrides ID="${CIRCLE_WORKFLOW_ID:0:7}" + - run: + name: Add env to backend + command: | + cd ~/project/backend + echo TYPEORM_CONNECTION=$TYPEORM_CONNECTION >> .env + echo TYPEORM_ENTITIES=$TYPEORM_ENTITIES >> .env + echo TYPEORM_HOST=$TYPEORM_HOST >> .env + echo TYPEORM_PORT=$TYPEORM_PORT >> .env + echo TYPEORM_USERNAME=$TYPEORM_USERNAME >> .env + echo TYPEORM_PASSWORD=$TYPEORM_PASSWORD >> .env + echo TYPEORM_DATABASE=$TYPEORM_DATABASE >> .env + echo TYPEORM_MIGRATIONS=$TYPEORM_MIGRATIONS >> .env + echo TYPEORM_MIGRATIONS_DIR=$TYPEORM_MIGRATIONS_DIR >> .env - run: name: Add back-end ip to ansible inventory command: | @@ -164,6 +172,7 @@ jobs: - persist_to_workspace: root: ~/ paths: + - project/backend/.env - project/.circleci/ansible/inventory.txt - destroy-environment @@ -193,6 +202,8 @@ jobs: - image: circleci/node:13.8.0 steps: - checkout + - restore_cache: + keys: [backend-build] - run: name: Run migrations command: | @@ -206,12 +217,12 @@ jobs: echo "insecure" >> ~/.curlrc if grep -q "has been executed successfully." ~/project/backend/migrations_dump.txt then - curl https://kvdb.io/VZNDWCZz5NPBkEr81irH3u/migration_$\{CIRCLE_WORKFLOW_ID:0:7\} -d '1' + curl https://kvdb.io/VZNDWCZz5NPBkEr81irH3u/migration_${CIRCLE_WORKFLOW_ID:0:7} -d '1' fi - run: name: Accessing key from kvdb.io command: | - curl https://kvdb.io/VZNDWCZz5NPBkEr81irH3u/migration_$\{CIRCLE_WORKFLOW_ID:0:7\} + curl --insecure https://kvdb.io/VZNDWCZz5NPBkEr81irH3u/migration_${CIRCLE_WORKFLOW_ID:0:7} - destroy-environment deploy-frontend: @@ -221,12 +232,15 @@ jobs: - checkout - restore_cache: keys: [frontend-build] + - attach_workspace: + at: ~/ - run: name: Install dependencies command: | apk update apk add tar gzip apk add npm nodejs + apk add --no-cache curl apk add --update ansible aws-cli - run: name: Get backend url @@ -253,7 +267,7 @@ jobs: - image: python:3.9.1-alpine3.12 steps: - checkout - - deploy-frontend: + - attach_workspace: at: ~/ - add_ssh_keys: fingerprints: [ad:8d:62:dc:0b:b1:23:7d:90:1f:17:39:51:2c:29:8f] @@ -263,6 +277,7 @@ jobs: apk update apk add tar gzip apk add npm nodejs + apk add --no-cache curl apk add --update ansible aws-cli - run: name: Deploy backend @@ -298,8 +313,10 @@ jobs: - run: name: Backend smoke test. command: | + export BACKEND_IP=$(cat ~/project/.circleci/ansible/inventory.txt | sed 1d) + echo ${BACKEND_IP} export API_URL="http://${BACKEND_IP}:3030" - echo "${API_URL}" + echo ${API_URL} if curl "${API_URL}/api/status" | grep "ok" then return 0 @@ -313,7 +330,7 @@ jobs: echo ${URL} if curl -s ${URL} | grep "Welcome" then - return 1 + return 0 else return 1 fi @@ -322,47 +339,48 @@ jobs: cloudfront-update: docker: - - image: amazon/aws-cli + - image: python:3.9.1-alpine3.12 steps: - checkout - run: name: Install dependencies command: | - sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - curl -sL https://rpm.nodesource.com/setup_14.x | sudo -E bash - - sudo yum install -y nodejs + apk update + apk add npm nodejs node -v npm -v + apk add --no-cache curl + apk add --update ansible aws-cli - run: name: Update cloudfront distribution command: | aws cloudformation deploy \ - --template-file .circleci/files/cloudfront.yml \ - --stack-name InitialStack \ - --parameter-overrides WorkflowID="udapeople-${CIRCLE_WORKFLOW_ID:0:7}" \ + --template-file ~/project/.circleci/files/cloudfront.yml \ + --stack-name InitialStackUpdate \ + --parameter-overrides NewWorkflowID="udapeople-${CIRCLE_WORKFLOW_ID:0:7}" \ --tags project=udapeople - destroy-environment - revert-migrations -# cleanup: -# docker: -# # Docker image here -# steps: -# # Checkout code from git -# - run: -# name: Get old stack workflow id -# command: | -# # your code here -# export OldWorkflowID="the id here" -# export STACKS=[] #put the list of stacks here -# - run: -# name: Remove old stacks and files -# command: | -# if [[ "${STACKS[@]}" =~ "${OldWorkflowID}" ]] -# then -# # your code here -# fi - + cleanup: + docker: + - image: amazon/aws-cli + steps: + - checkout + - run: + name: Get old stack workflow id + command: | + export OldWorkflowID=$(aws cloudformation \ + list-exports --query "Exports[?Name==\`NewWorkflowID\`].Value" \ + --no-paginate --output text) + echo OldWorkflowID: "${OldWorkflowID}" + echo CIRCLE_WORKFLOW_ID "${CIRCLE_WORKFLOW_ID:0:7}" + - run: + name: Remove old stacks and files + command: | + aws s3 rm "s3://${OldWorkflowID}" --recursive + aws cloudformation delete-stack --stack-name "udapeople-backend-${CIRCLE_WORKFLOW_ID:0:7}" + aws cloudformation delete-stack --stack-name "udapeople-frontend-${CIRCLE_WORKFLOW_ID:0:7}" workflows: default: @@ -381,7 +399,7 @@ workflows: requires: [test-frontend, test-backend, scan-frontend, scan-backend] filters: branches: - only: [test-feature-branch] + only: [master] - configure-infrastructure: requires: [deploy-infrastructure] - run-migrations: @@ -394,5 +412,5 @@ workflows: requires: [deploy-backend, deploy-frontend] - cloudfront-update: requires: [smoke-test] - # - cleanup: - # requires: [cloudfront-update] \ No newline at end of file + - cleanup: + requires: [cloudfront-update] \ No newline at end of file diff --git a/.circleci/files/backend.yml b/.circleci/files/backend.yml index 74047f6..d8c0e27 100644 --- a/.circleci/files/backend.yml +++ b/.circleci/files/backend.yml @@ -29,7 +29,7 @@ Resources: SecurityGroups: - Ref: InstanceSecurityGroup KeyName: test-key2 - ImageId: ami-0fc5d935ebf8bc3bc + ImageId: ami-068663a3c619dd892 Tags: - Key: Name Value: !Sub backend-${ID} diff --git a/.circleci/files/cloudfront.yml b/.circleci/files/cloudfront.yml index c51ef58..949c996 100644 --- a/.circleci/files/cloudfront.yml +++ b/.circleci/files/cloudfront.yml @@ -2,7 +2,7 @@ Description: > Cloudfront distribution for UdaPeople. Parameters: - WorkflowID: + NewWorkflowID: Description: Unique identifier. Type: String @@ -20,7 +20,7 @@ Resources: Properties: DistributionConfig: Origins: - - DomainName: !Sub "udapeople-${WorkflowID}.s3.amazonaws.com" + - DomainName: !Sub "udapeople-${NewWorkflowID}.s3.amazonaws.com" Id: webpage S3OriginConfig: OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}" @@ -33,8 +33,8 @@ Resources: ViewerProtocolPolicy: allow-all Outputs: - WorkflowID: - Value: !Sub ${WorkflowID} + NewWorkflowID: + Value: !Sub ${NewWorkflowID} Description: URL for website hosted on S3 Export: - Name: WorkflowID + Name: NewWorkflowID diff --git a/backend/.env.sample b/backend/.env.sample index 3b85707..a1dd31c 100644 --- a/backend/.env.sample +++ b/backend/.env.sample @@ -7,7 +7,7 @@ TYPEORM_MIGRATIONS=./src/migrations/*.ts # Use these values for the local PG database from the Docker Compose file TYPEORM_HOST=localhost -TYPEORM_PORT=5532 +TYPEORM_PORT=5432 TYPEORM_USERNAME=postgres TYPEORM_PASSWORD=password TYPEORM_DATABASE=glee \ No newline at end of file