From 6f4d9f22318512a30f67c4facb0996ff9d7f7238 Mon Sep 17 00:00:00 2001 From: Andrew Myers Date: Fri, 8 Jul 2022 15:06:21 -0400 Subject: [PATCH] Adds command line script for deploying Open Vault resources (#12) * Adds command line script for deploying Open Vault resources * Adds ./deploy executable script for parsing command line args. (run ./deploy -h for usage). * Adds module 'deployer' which takes parsed command line args and provides methods for various deployment operations. * Adds Dockerfile and nginx config file for building/deploying the ov-nginx container used for serving both ov_wag and ov-frontend web apps. * Adds __pycache__ to .gitignore. Closes #11. * Format with black * Splits URLs to constants * Move arg parsing to cli.py, only run deploy steps when run as __main__ * Migrate to pydantic types * Adds missing deploy_ov_nginx def * Adds docstrings * Adds short args -b: backend, -f: frontend, -p: proxy * Raises Exception if no deployment specified. Removes else clause. * Migrates from os to subprocess to catch all errors Co-authored-by: Harpo --- .gitignore | 3 ++ cli.py | 67 +++++++++++++++++++++++++ deploy | 17 +++++++ deployer.py | 119 ++++++++++++++++++++++++++++++++++++++++++++ ov-nginx/Dockerfile | 3 ++ ov-nginx/nginx.conf | 12 +++++ 6 files changed, 221 insertions(+) create mode 100644 cli.py create mode 100755 deploy create mode 100644 deployer.py create mode 100644 ov-nginx/Dockerfile create mode 100644 ov-nginx/nginx.conf diff --git a/.gitignore b/.gitignore index d3df5dd..3e47841 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Python +__pycache__ + # Database db/ diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..76df6ba --- /dev/null +++ b/cli.py @@ -0,0 +1,67 @@ +from argparse import ArgumentParser + + +def cli(): + """parse CLI args""" + parser = ArgumentParser(description='Manage Open Vault deployments') + parser.add_argument( + '-c', + '--context', + required=True, + type=str, + choices=['openvault', 'openvault-demo'], + # TODO: elaborate. This is important and a bit complex. + # It requires that your local ~/.kube/config have these two + # contexts present and properly configured. + help='the kubectl context to use in the deployment', + ) + + parser.add_argument( + '-b', + '--ov_wag', + type=str, + metavar='TAG|COMMIT|BRANCH|HEAD', + help='version of the ov_wag headless CMS backend to be deployed', + ) + + parser.add_argument( + '-f', + '--ov-frontend', + type=str, + metavar='TAG|COMMIT|BRANCH|HEAD', + help='version of the ov-frontend website to be deployed', + ) + + parser.add_argument( + '-p', + '--ov-nginx', + action='store_true', + help='rebuild and redeploy ov-nginx image', + ) + + parser.add_argument( + '--ov_wag-env', + type=str, + metavar='PATH', + default='./ov_wag/env.yml', + help='path to environment file for ov_wag', + ) + + parser.add_argument( + '--ov_wag-secrets', + type=str, + metavar='PATH', + default='./ov_wag/secrets.yml', + help='path to secrets file for ov_wag', + ) + + parser.add_argument( + '--ov-frontend-env', + type=str, + metavar='PATH', + default='./ov-frontend/env.yml', + help='path to environment file for ov-frontend', + ) + + # Parses the command line args. + return parser.parse_args() diff --git a/deploy b/deploy new file mode 100755 index 0000000..5f6a9c9 --- /dev/null +++ b/deploy @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +### +# Command line tool for managing Open Vault deployments +### +from deployer import Deployer + + +if __name__ == '__main__': + from cli import cli + + args = cli() + + # Create a new Deployer instance form parsed command line args. + deployer = Deployer(**vars(args)) + + # Run the deployment. + deployer.deploy() diff --git a/deployer.py b/deployer.py new file mode 100644 index 0000000..13bac71 --- /dev/null +++ b/deployer.py @@ -0,0 +1,119 @@ +from subprocess import run +from pydantic import BaseModel + +OV_WAG_URL = 'https://github.com/WGBH-MLA/ov_wag.git' +OV_FRONTEND_URL = 'https://github.com/WGBH-MLA/ov-frontend.git' + + +class Deployer(BaseModel): + """Deployer class + + Used for openvault deployment configuration + """ + + context: str + ov_wag: str = None + ov_wag_env: str = None + ov_wag_secrets: str = None + ov_frontend: str = None + ov_frontend_env: str = None + ov_nginx: bool = None + + def run(self, cmd): + run(cmd, shell=True, check=True) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.set_current_context() + + def set_current_context(self): + """Switch to the specified kubectl context.""" + self.run(f'kubectl config use-context {self.context}') + + def build_ov_wag(self): + """Build the backend ov_wag docker image""" + self.run(f'docker build {OV_WAG_URL}#{self.ov_wag} -t {self.ov_wag_tag}') + + def build_ov_frontend(self): + """Build the frontend ov-frontend docker image""" + self.run( + f'docker build {OV_FRONTEND_URL}#{self.ov_frontend} -t {self.ov_frontend_tag}' + ) + + def build_nginx(self): + """Build the proxy nginx docker image""" + self.run(f'docker build ov-nginx') + + def push_ov_wag(self): + """Push the backend ov_wag docker image to hub.docker.com + + Requires the user to be logged in""" + self.run(f'docker push {self.ov_wag_tag}') + + def push_ov_frontend(self): + """Push the frontend ov-frontend docker image to hub.docker.com + + Requires the user to be logged in""" + self.run(f'docker push {self.ov_frontend_tag}') + + def push_nginx(self): + """Push the proxy nginx docker image to hub.docker.com + + Requires the user to be logged in""" + self.run(f'docker push {self.ov_nginx_tag}') + + def update_ov_wag_workload(self): + """Sets the backend pod image to""" + self.run(f'kubectl set image deployment.apps/ov ov={self.ov_wag_tag}') + + def update_ov_frontend_workload(self): + self.run( + f'kubectl set image deployment.apps/ov-frontend ov-frontend={self.ov_frontend_tag}' + ) + + def deploy_ov_wag(self): + """Deploy the backend""" + print(f'Deploying ov_wag: "{self.ov_wag}"') + self.build_ov_wag() + self.push_ov_wag() + self.update_ov_wag_workload() + + def deploy_ov_frontend(self): + """Deploy the frontend""" + print(f'Deploying ov-frontend: "{self.ov_frontend}"') + self.build_ov_frontend() + self.push_ov_frontend() + self.update_ov_frontend_workload() + + def deploy_ov_nginx(self): + """Deploy the proxy + + TODO: deploy proxy""" + print(f'Deploying ov_nginx: "{self.ov_nginx}"') + + def deploy(self): + """Run the deployment process using the current context""" + print(f'Starting deployment using context "{self.context}"') + + if not any([self.ov_wag, self.ov_frontend, self.ov_nginx]): + raise Exception(f'Nothing specified for deployment.') + if self.ov_wag: + self.deploy_ov_wag() + if self.ov_frontend: + self.deploy_ov_frontend() + if self.ov_nginx: + self.deploy_ov_nginx() + + print('Done!') + + @property + def ov_wag_tag(self): + return f'wgbhmla/ov_wag:{self.ov_wag}' + + @property + def ov_frontend_tag(self): + return f'wgbhmla/ov-frontend:{self.ov_frontend}' + + @property + def ov_nginx_tag(self): + return f'wgbhmla/ov-nginx:latest' diff --git a/ov-nginx/Dockerfile b/ov-nginx/Dockerfile new file mode 100644 index 0000000..8d7784b --- /dev/null +++ b/ov-nginx/Dockerfile @@ -0,0 +1,3 @@ +FROM foggbh/ov-nginx:latest + +COPY ./nginx.conf /etc/nginx/nginx.conf diff --git a/ov-nginx/nginx.conf b/ov-nginx/nginx.conf new file mode 100644 index 0000000..22574da --- /dev/null +++ b/ov-nginx/nginx.conf @@ -0,0 +1,12 @@ +events { + worker_connections 4096; ## Default: 1024 +} + +http { + server { + listen 80 default_server; + location / { + proxy_pass http://ov-frontend:3000; + } + } +}