diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 2747f98..e6ddc26 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -9,20 +9,50 @@ on: - dev jobs: - deploy_dev: - name: Deploy to dev server + deploy: runs-on: ubuntu-latest environment: deployment - if: ${{ github.event.workflow_run.conclusion == 'success' }} + concurrency: + group: deploy-dev + cancel-in-progress: true + steps: - - name: install ssh keys - # check this thread to understand why its needed: - # https://stackoverflow.com/a/70447517 - run: | - install -m 600 -D /dev/null ~/.ssh/id_rsa - echo "${{ secrets.SSH_PRIVATE_KEY_DEV }}" > ~/.ssh/id_rsa - ssh-keyscan -H ${{ secrets.SSH_HOST_DEV }} > ~/.ssh/known_hosts - - name: connect and pull - run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST_DEV }} "sudo ./update.sh && exit" - - name: cleanup - run: rm -rf ~/.ssh + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: ${{ github.event.workflow_run.head_branch }} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.11' + + - name: Install Ansible + run: | + python -m pip install --upgrade pip + pip install ansible + + - name: Install ssh keys + # For reference: https://stackoverflow.com/a/70447517 + run: | + install -m 600 -D /dev/null ~/.ssh/galaxy + echo "${{ secrets.SSH_PRIVATE_KEY_DEV }}" > ~/.ssh/galaxy + echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts + + - name: Add VAULT password + run: | + echo "${{ secrets.ANSIBLE_VAULT_PASS }}" > deploy/ansible/.vault.pass + + - name: Install ansible roles + run: | + cd deploy/ansible + ansible-galaxy install -p roles -r requirements.yml + + - name: Run Ansible Playbook + run: | + cd deploy/ansible + ansible-playbook -i hosts dev.yml --tags update + env: + ANSIBLE_HOST_KEY_CHECKING: 'False' + ANSIBLE_REMOTE_USER: ${{ secrets.SSH_USER }} + ANSIBLE_PRIVATE_KEY_FILE: ~/.ssh/galaxy diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 69283da..81bd88a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,20 +9,49 @@ on: - main jobs: - deploy_prod: - name: Deploy to prod server + deploy: runs-on: ubuntu-latest environment: deployment - if: ${{ github.event.workflow_run.conclusion == 'success' }} + concurrency: + group: deploy + cancel-in-progress: true + steps: - - name: install ssh keys - # check this thread to understand why its needed: - # https://stackoverflow.com/a/70447517 - run: | - install -m 600 -D /dev/null ~/.ssh/id_rsa - echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa - ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts - - name: connect and pull - run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "./update.sh && exit" - - name: cleanup - run: rm -rf ~/.ssh + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: ${{ github.event.workflow_run.head_branch }} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.11' + + - name: Install Ansible + run: | + python -m pip install --upgrade pip + pip install ansible + + - name: Install ssh keys + # For reference: https://stackoverflow.com/a/70447517 + run: | + install -m 600 -D /dev/null ~/.ssh/galaxy + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/galaxy + echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts + + - name: Add VAULT password + run: | + echo "${{ secrets.ANSIBLE_VAULT_PASS }}" > deploy/ansible/.vault.pass + + - name: Install ansible roles + run: | + cd deploy/ansible + ansible-galaxy install -p roles -r requirements.yml + + - name: Run Ansible Playbook + run: | + cd deploy/ansible + ansible-playbook -i hosts prod.yml --tags update + env: + ANSIBLE_HOST_KEY_CHECKING: 'False' + ANSIBLE_REMOTE_USER: ${{ secrets.SSH_USER }} diff --git a/deploy/ansible/roles/galaxy_media_site/defaults/main.yml b/deploy/ansible/roles/galaxy_media_site/defaults/main.yml index f1127c1..cd27219 100644 --- a/deploy/ansible/roles/galaxy_media_site/defaults/main.yml +++ b/deploy/ansible/roles/galaxy_media_site/defaults/main.yml @@ -10,8 +10,6 @@ gms: dest: "{{ server_root }}/gunicorn.py" - src: "{{ role_path }}/templates/gms.service.j2" dest: /etc/systemd/system/gms.service - - src: "{{ role_path }}/templates/setup.sh.j2" - dest: "{{ server_root }}/setup.sh" - src: "{{ role_path }}/templates/nginx.vhost.j2" dest: "/etc/nginx/sites-available/{{ inventory_hostname }}.conf" - src: "{{ role_path }}/templates/.env.j2" diff --git a/deploy/ansible/roles/galaxy_media_site/tasks/main.yml b/deploy/ansible/roles/galaxy_media_site/tasks/main.yml index 03335ba..e16f4a3 100644 --- a/deploy/ansible/roles/galaxy_media_site/tasks/main.yml +++ b/deploy/ansible/roles/galaxy_media_site/tasks/main.yml @@ -48,6 +48,9 @@ dest: "{{ project_root }}" clone: yes force: yes + update: yes + tags: + - update - name: create gms media directory file: @@ -64,12 +67,16 @@ src: "{{ item.src }}" dest: "{{ item.dest }}" loop: "{{ gms.templates }}" + tags: + - config - name: copy webserver configuration copy: src: "{{ item.src }}" dest: "{{ item.dest }}" loop: "{{ gms.files }}" + tags: + - config - name: link to enable nginx virtualhost ansible.builtin.file: @@ -82,25 +89,52 @@ requirements: "{{ project_root }}/requirements.txt" virtualenv: "{{ venv_root }}" virtualenv_python: python3.12 + tags: + - always - name: run gms setup script command: "bash {{ server_root }}/setup.sh" - name: create and install SSL certificate with letsencrypt - command: "certbot --nginx --noninteractive --agree-tos --redirect --email {{ certbot_renew_email }} -d {{ inventory_hostname }}" + command: > + certbot --nginx --noninteractive --agree-tos --redirect + --email {{ certbot_renew_email }} + -d {{ inventory_hostname }} when: certbot_ssl - name: Ensure gms superuser login - shell: | - cd {{ django_root }} && \ - export DJANGO_SUPERUSER_PASSWORD={{ admin_user.password }} && \ - {{ venv_root }}/bin/python manage.py createsuperuser --noinput \ - --email {{ admin_user.email }} \ - --first_name {{ admin_user.first_name }} \ + args: + chdir: "{{ django_root }}" + environment: + DJANGO_SETTINGS_MODULE: webapp.settings.prod + DJANGO_SUPERUSER_PASSWORD: "{{ admin_user.password }}" + command: > + {{ venv_root }}/bin/python manage.py createsuperuser --noinput + --email {{ admin_user.email }} + --first_name {{ admin_user.first_name }} --last_name {{ admin_user.last_name }} ignore_errors: yes when: admin_user and not skip_database_migration +- name: Run Django migrate + environment: + DJANGO_SETTINGS_MODULE: webapp.settings.prod + args: + chdir: "{{ django_root }}" + command: "{{ venv_root }}/bin/python manage.py migrate" + tags: + - update + when: not skip_database_migration + +- name: Run Django collectstatic + environment: + DJANGO_SETTINGS_MODULE: webapp.settings.prod + args: + chdir: "{{ django_root }}" + command: "{{ venv_root }}/bin/python manage.py collectstatic --noinput" + tags: + - update + - name: update project ownership ansible.builtin.file: path: /home/ubuntu @@ -108,12 +142,28 @@ recurse: yes owner: ubuntu group: ubuntu + tags: + - always - name: update media file ownership - file: dest={{ django_root }}/webapp/media owner=www-data group=www-data mode=u=rwX,g=rwX,o=rwX recurse=yes + file: > + dest={{ django_root }}/webapp/media + owner=www-data + group=www-data + mode=u=rwX,g=rwX,o=rwX + recurse=yes + tags: + - always - name: update log file ownership - file: dest={{ django_root }}/webapp/logs owner=www-data group=www-data mode=u=rwX,g=rwX,o=rwX recurse=yes + file: > + dest={{ django_root }}/webapp/logs + owner=www-data + group=www-data + mode=u=rwX,g=rwX,o=rwX + recurse=yes + tags: + - always - name: make update.sh executable file: dest=/home/ubuntu/update.sh mode=a+x @@ -132,3 +182,17 @@ minute: 0 job: "cd {{ django_root }} && {{ venv_root }}/bin/python manage.py scrape_news" when: check_scraper.rc == 0 + +- name: restart nginx + ansible.builtin.systemd: + name: nginx + state: restarted + tags: + - config + +- name: restart gms + ansible.builtin.systemd: + name: gms + state: restarted + tags: + - always diff --git a/deploy/ansible/roles/galaxy_media_site/templates/setup.sh.j2 b/deploy/ansible/roles/galaxy_media_site/templates/setup.sh.j2 deleted file mode 100644 index eae3540..0000000 --- a/deploy/ansible/roles/galaxy_media_site/templates/setup.sh.j2 +++ /dev/null @@ -1,23 +0,0 @@ -# Set up gms and restart web services - -set -e - -source {{ venv_root }}/bin/activate -cd {{ django_root }} - -# Set Django settings -export DJANGO_SETTINGS_MODULE=webapp.settings.prod - -# Collect static files for Nginx -python manage.py collectstatic --noinput - -{% if not skip_database_migration %} -# Migrate database -python manage.py migrate -{% endif %} - -# Restart services -sudo systemctl daemon-reload -sudo systemctl enable gms.service -sudo systemctl enable gms.socket -sudo service gms restart diff --git a/deploy/maintenance-site/README.md b/deploy/maintenance-site/README.md new file mode 100644 index 0000000..4b3b15a --- /dev/null +++ b/deploy/maintenance-site/README.md @@ -0,0 +1,12 @@ +# Maintenance page + +Show this when the main site is offline for maintenance/outage. + +- Make sure that this directory is symlinked to `/srv/sites/gms-maintenance-site/` +- Move the selected Nginx config to your /etc/nginx/sites-enabled/ to replace + the production nginx config. +- Make sure that the SSL cert paths defined in the nginx config exist on your + server (they should have be created with python-certbot-nginx) - they can be + tarred and copied from the main web server if running this somewhere else + (e.g. infra outage). +- `sudo systemctl nginx restart` diff --git a/deploy/maintenance-site/index.html b/deploy/maintenance-site/index.html index 48c9b4a..b56d61d 100644 --- a/deploy/maintenance-site/index.html +++ b/deploy/maintenance-site/index.html @@ -37,6 +37,11 @@
++ Our Media Site is currently undergoing maintenance. + You can continue using the service as normal during this time. +
+