Skip to content

Commit

Permalink
Merge pull request #125 from dimagi/sk/deploy-updates
Browse files Browse the repository at this point in the history
move env file management to Kamal
  • Loading branch information
snopoke authored Sep 21, 2023
2 parents b4d80ff + f9b51e0 commit f3bee9d
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 89 deletions.
13 changes: 13 additions & 0 deletions deploy/.env.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%#
This file is used by Kamal to generate the `deploy/.env` file when running `kamal envify`
It is a Ruby 'ERB' template, so you can use Ruby code in it.
See https://fireapp.kkbox.com/doc/tutorial_2.html for more information.
%>
<% `op signin --account dimagi.1password.com --raw` %>
<% if $?.exitstatus == 0 %>
<% vars = YAML.load(`op item get --vault "CommCare Connect" "Connect Secrets" --fields type=string,type=concealed`) %>
<% for var in vars %><% if var.key?("Value") %><% if var["Value"].kind_of?(Array) %>
<%= var['Label'] %>=<%= var['Value'].join(',') %>
<% else %><%= var['Label'] %>=<%= var['Value'] %>
<% end %><% end %><% end %>
<% else raise ArgumentError, "Error getting values from 1Password. Try sign in." end %>
28 changes: 20 additions & 8 deletions deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ Deploying commcare-connect uses the following tools:
- [Ansible](https://www.ansible.com/)

- Setup of EC2 instances
- Management of Docker container ENV files

- [Kamal](https://kamal-deploy.org/)

- Deployment of Docker containers
- Management of Docker env files

- [1Password CLI](https://developer.1password.com/docs/cli/get-started/)

- Some secrets are stored in 1Password and retrieved using the CLI
- Store secrets and SSH Keys (retrieved using the 1Password CLI and Ansible module)

- [AWS CLI](https://aws.amazon.com/cli/)
- Used to manage AWS resources
- Used to manage AWS resources, specifically the Container Registry

## Setup

Expand All @@ -37,7 +37,7 @@ gem install kamal -v '~> 1.0.0'

### Ansible

This is only required if you need to update Django settings.
This is only required if you need to set up a new EC2 instance.

```bash
python3 -m pip install --user pipx
Expand Down Expand Up @@ -76,18 +76,30 @@ aws sso login --profile commcare-connect

Note: If you used a different profile name you will need to set the `AWS_PROFILE` environment variable to the profile name.

## Updating Django Settings
## Django Settings

The Django settings are configured using the `deploy/roles/connect/templates/docker.env.j2` file. The plain text
settings values are in the `deploy/roles/connect/vars/main.yml` file. Secrets are stored in the 1Password under the
`Ansible Secrets` entry.
The Django settings (environment variables) are configured using in `config/deploy.yml` (see the `env` section).
That file defines all the settings that are required. The values for the 'secret' settings are stored in 1Password
and are extracted and added to the env file by Kamal when running `inv django-settings` (or `kamal envify`).

Kamal uses a Ruby template (`.env.erb`) to extract the settings from 1Pasword.

Secrets are stored in the 1Password under the `Connect Secrets` entry.

To update the Django settings:

```bash
inv django-settings
```

### Adding new settings

1. Add the setting to the `config/deploy.yml` file.
2. If it is a 'secret', edit the `Connect Secrets` entry in 1Password and add a 'text' or 'password' field with
the name of the setting and it's value.
3. Run `inv django-settings` to deploy the settings to the server.
4. Deploy the app to have it pick up the new settings.

## Deploy

Ideally deploy should be done via GitHub actions however it can be run locally as follows:
Expand Down
32 changes: 26 additions & 6 deletions deploy/config/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,39 @@ service: commcare-connect

image: commcare-connect

env:
clear:
AWS_DEFAULT_REGION: us-east-1
DJANGO_ACCOUNT_ALLOW_REGISTRATIONS: True
CONNECTID_URL: https://connectid.dimagi.com
DJANGO_ADMIN_URL: admin/
DJANGO_EMAIL_BACKEND: anymail.backends.amazon_ses.EmailBackend
SENTRY_ENVIRONMENT: staging
DJANGO_DEFAULT_FROM_EMAIL: [email protected]
DJANGO_AWS_STORAGE_BUCKET_NAME: commcare-connect-media
RDS_PORT: 5432
RDS_DB_NAME: ebdb
secret:
- CELERY_BROKER_URL
- CSRF_TRUSTED_ORIGINS
- cid_client_id
- cid_client_secret
- DJANGO_SECRET_KEY
- DJANGO_ALLOWED_HOSTS
- DJANGO_ALLOWED_CIDR_NETS
- REDIS_URL
- SENTRY_DSN
- RDS_HOSTNAME
- RDS_USERNAME
- RDS_PASSWORD

servers:
web:
hosts:
- 3.90.216.194
options:
# create by ansible
env-file: '/home/connect/www/commcare-connect/docker.env'
celery:
hosts:
- 3.90.216.194
options:
# create by ansible
env-file: '/home/connect/www/commcare-connect/docker.env'
cmd: /start_celery
labels:
traefik.enable: false
Expand Down
2 changes: 0 additions & 2 deletions deploy/play.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
- hosts: web0
become: true
strategy: free
vars:
- secrets: "{{ lookup('community.general.onepassword', 'Ansible Secrets', subdomain='dimagi', vault='CommCare Connect', field='secrets_yaml') | from_yaml }}"
roles:
- role: connect
7 changes: 0 additions & 7 deletions deploy/registry_password.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@
# Helper script to get the password for the ECR registry
# This is used by Kamal during deploy. See ./deploy/config/deploy.yml

set -e

REGION=us-east-1
PROFILE_ARG=""
if [ -z "$CI" ]; then
# if not in github actions, specify the profile
PROFILE_ARG=" --profile ${AWS_PROFILE:-commcare-connect}"
fi

aws sts get-caller-identity $PROFILE_ARG &> /dev/null
EXIT_CODE="$?" # $? is the exit code of the last statement
if [ $EXIT_CODE != 0 ]; then
aws sso login $PROFILE_ARG
fi
aws ecr get-login-password --region=$REGION $PROFILE_ARG
14 changes: 0 additions & 14 deletions deploy/roles/connect/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,4 @@ apt_update_cache: yes

app_name: commcare_connect
app_user: connect
home_dir: /home/{{ app_user }}
app_group: webapps
project_name: commcare-connect
base_dir: '{{home_dir}}/www'
project_dir: '{{ base_dir }}/{{ project_name }}'

docker_env_file: '{{ project_dir }}/docker.env'

# Django settings
aws_region: us-east-1
connectid_url: https://connectid.dimagi.com
django_admin_url: admin/
django_email_backend: anymail.backends.amazon_ses.EmailBackend
sentry_environment: staging
django_allow_registrations: True
25 changes: 0 additions & 25 deletions deploy/roles/connect/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,3 @@
key: "{{ lookup('community.general.onepassword', 'Deploy SSH Key', subdomain='dimagi', vault='CommCare Connect', field='public key') }}"
exclusive: yes
tags: auth

- name: Create {{ base_dir }} folder.
file:
path: '{{ base_dir }}'
group: '{{ app_group }}'
mode: 0755
state: directory

- name: Create {{ project_dir }}.
file:
path: '{{ project_dir }}'
owner: '{{ app_user }}'
group: '{{ app_group }}'
mode: 0750
state: directory

- name: Create Docker Env
template:
src: 'docker.env.j2'
dest: '{{ docker_env_file }}'
owner: '{{ app_user }}'
group: '{{ app_group }}'
mode: 0644
tags:
- django_settings
24 changes: 0 additions & 24 deletions deploy/roles/connect/templates/docker.env.j2

This file was deleted.

23 changes: 20 additions & 3 deletions tasks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Useful tasks for use when developing CommCare Connect.
This uses the `Invoke` library."""
import os
from pathlib import Path

from invoke import Context, Exit, call, task
from invoke import Context, Exit, UnexpectedExit, call, task

PROJECT_DIR = Path(__file__).parent

Expand Down Expand Up @@ -77,7 +78,8 @@ def setup_ec2(c: Context, verbose=False, diff=False):
@task
def django_settings(c: Context, verbose=False, diff=False):
"""Update the Django settings file on prod servers"""
run_ansible(c, tags="django_settings", verbose=verbose, diff=diff)
run_kamal(c, "envify")
os.remove(PROJECT_DIR / "deploy" / ".env")
print("\nSettings updated. A re-deploy is required to have the services use the new settings.")
val = input("Do you want to re-deploy the Django services? [y/N] ")
if val.lower() == "y":
Expand Down Expand Up @@ -106,5 +108,20 @@ def run_ansible(c: Context, play="play.yml", tags=None, verbose=False, diff=Fals
@task
def deploy(c: Context):
"""Deploy the app to prod servers"""
run_kamal(c, "deploy")


def run_kamal(c: Context, command: str):
"""Run Kamal commands"""
_check_sso(c)
with c.cd(PROJECT_DIR / "deploy"):
c.run("kamal deploy")
c.run(f"kamal {command}", echo=True)


def _check_sso(c: Context):
"""Check if SSO is enabled"""
profile = os.environ.get("AWS_PROFILE", "commcare-connect")
try:
c.run(f"aws sts get-caller-identity --profile {profile} &> /dev/null", hide=True)
except UnexpectedExit:
raise Exit("ERROR You must be logged into AWS. Run `aws sso login --profile commcare-connect`", -1)

0 comments on commit f3bee9d

Please sign in to comment.