def deploy(self): CLI.info('Deploying...') self.clean() self.upload() self.pull() self.reload() self.logs() self.status()
def restart_proxy(self): CLI.info('Restarting proxy...') steps = 1 CLI.step(1, steps, 'Reloading proxy container...') os.system( f'docker-compose {self.docker_ssh} -f configs/docker/docker-compose.{self.environment_id}.proxy.yml --project-name=reverse up -d' )
def pg_dump(self): now = datetime.datetime.now() # filename = now.strftime("%Y%m%d%H%M%S") filename = now.strftime(f"{self.PROJECT_NAME}_%Y%m%d_%H%M.pg") CLI.info(f'Backuping database into file {filename}') env = self.load_environment() os.system( f'docker {self.docker_ssh} exec -it {self.CONTAINER_DB} bash -c \'pg_dump -Fc -h {env["POSTGRES_HOST"]} -U {env["POSTGRES_USER"]} {env["POSTGRES_DBNAME"]} -W > /backups/{filename}\'' )
def pg_restore(self, params): CLI.info(f'Restoring database from file {params}') CLI.underline( "Don't forget to drop database at first to prevent constraints collisions!" ) env = self.load_environment() os.system( f'docker {self.docker_ssh} exec -it {self.CONTAINER_DB} bash -c \'pg_restore -h {env["POSTGRES_HOST"]} -U {env["POSTGRES_USER"]} -d {env["POSTGRES_DBNAME"]} -W < /backups/{params}\'' )
def restart(self): CLI.info('Restarting...') steps = 4 if self.SWARM: CLI.step(1, steps, 'Stopping and removing Docker app service...') for service in self.get_services(): if service == self.CONTAINER_APP: os.system(f'docker service rm {service}') CLI.step(2, steps, 'Recreating Docker swarm stack...') os.system( f'docker stack deploy -c configs/docker/{self.COMPOSE_PREFIX}.yml -c configs/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml {self.PROJECT_NAME}' ) CLI.step( 3, steps, 'Prune Docker images and volumes') # todo prune on every node os.system( f'docker {self.docker_ssh} system prune --volumes --force') CLI.step(4, steps, 'Collecting static files') # todo collect static app_container = self.get_containers_starts_with(self.CONTAINER_APP) if app_container: os.system( f'docker {self.docker_ssh} exec -i {app_container[0]} python manage.py collectstatic --noinput --verbosity 0' ) else: CLI.step(1, steps, 'Stopping and removing Docker containers...') for service in self.config['containers']['deploy'][ 'zero_downtime'] + self.config['containers']['deploy'][ 'restart']: container = self.get_container_name(service) os.popen(f'docker {self.docker_ssh} container stop {container}' ).read() os.system(f'docker {self.docker_ssh} container rm {container}') CLI.step(2, steps, 'Recreating Docker containers...') os.system( f'docker-compose {self.docker_ssh} -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.yml -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml --project-name={self.PROJECT_NAME} up -d' ) # os.system(f'docker-compose {self.docker_ssh} -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.yml -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml --project-name={self.PROJECT_NAME} up --remove-orphans -d') CLI.step(3, steps, 'Prune Docker images and volumes') os.system( f'docker {self.docker_ssh} system prune --volumes --force') CLI.step(4, steps, 'Collecting static files') os.system( f'docker {self.docker_ssh} exec -i {self.CONTAINER_APP} python manage.py collectstatic --noinput --verbosity 0' )
def upload(self, context='services'): CLI.info('Uploading...') steps = 1 if context == 'services': CLI.step( 1, steps, 'Uploading configs for context "services" [webserver, cache, htpasswd]' ) elif context == 'compose': CLI.step( 1, steps, 'Uploading configs for context "compose" [docker compose configs and environment]' ) elif context == 'mantis': CLI.step(1, steps, 'Uploading configs for mantis [mantis.json]') else: CLI.error(f'Unknown context "{context}"') if self.environment_id == 'dev': print('Skipping for dev...') elif self.mode == 'host': CLI.warning( 'Not uploading due to host mode! Be sure your configs on host are up to date!' ) else: if context == 'services': os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {self.cache_config} {self.user}@{self.host}:/home/{self.user}/public_html/web/configs/{self.CACHE}/' ) os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {self.webserver_config} {self.user}@{self.host}:/home/{self.user}/public_html/web/configs/{self.WEBSERVER}/' ) os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {self.webserver_config_proxy} {self.user}@{self.host}:/etc/nginx/conf.d/proxy/' ) os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {self.htpasswd} {self.user}@{self.host}:/etc/nginx/conf.d/' ) elif context == 'mantis': os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {self.config_file} {self.user}@{self.host}:/home/{self.user}/public_html/web/configs/' ) elif context == 'compose': os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {self.environment_file} {self.user}@{self.host}:/home/{self.user}/public_html/web/configs/environments/' ) for config in self.compose_configs: os.system( f'rsync -arvz -e \'ssh -p {self.port}\' -rvzh --progress {config} {self.user}@{self.host}:/home/{self.user}/public_html/web/configs/docker/' )
def push(self): CLI.info(f'Pushing...') steps = 2 CLI.step(1, steps, 'Tagging Docker image...') os.system( f'docker tag {self.IMAGE_NAME} {self.DOCKER_REPOSITORY}:{self.DOCKER_TAG}' ) print( f'Successfully tagged {self.DOCKER_REPOSITORY}:{self.DOCKER_TAG}') CLI.step(2, steps, 'Pushing Docker image...') os.system(f'docker push {self.DOCKER_REPOSITORY}:{self.DOCKER_TAG}')
def status(self): if self.SWARM: # todo remove containers as well ? CLI.info('Getting status...') os.system(f'docker stack services {self.PROJECT_NAME}') else: CLI.info('Getting status...') steps = 2 CLI.step(1, steps, 'List of Docker images') os.system(f'docker {self.docker_ssh} image ls') CLI.step(2, steps, 'Docker containers') os.system(f'docker {self.docker_ssh} container ls -a --size')
def remove(self, params=''): if self.SWARM: # todo remove containers as well ? CLI.info('Removing services...') os.system(f'docker stack rm {self.PROJECT_NAME}') else: CLI.info('Removing containers...') containers = self.get_containers( ) if params == '' else params.split(' ') steps = len(containers) for index, container in enumerate(containers): CLI.step(index + 1, steps, f'Removing {container}') os.system(f'docker {self.docker_ssh} container rm {container}')
def stop(self, params=None): if self.SWARM: # todo can stop service ? CLI.info('Removing services...') os.system(f'docker stack rm {self.PROJECT_NAME}') else: CLI.info('Stopping containers...') containers = self.get_containers() if not params else params.split( ' ') steps = len(containers) for index, container in enumerate(containers): CLI.step(index + 1, steps, f'Stopping {container}') os.system( f'docker {self.docker_ssh} container stop {container}')
def start(self, params): if self.SWARM: CLI.info('Starting services...') os.system( f'docker stack deploy -c configs/docker/{self.COMPOSE_PREFIX}.yml -c configs/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml {self.PROJECT_NAME}' ) else: CLI.info('Starting containers...') containers = self.get_containers() if not params else params.split( ' ') steps = len(containers) for index, container in enumerate(containers): CLI.step(index + 1, steps, f'Starting {container}') os.system( f'docker {self.docker_ssh} container start {container}')
def logs(self, params=None): if self.SWARM: CLI.info('Reading logs...') services = params.split(' ') if params else self.get_services() lines = '-f' if params else '--tail 10' steps = len(services) for index, service in enumerate(services): CLI.step(index + 1, steps, f'{service} logs') os.system(f'docker service logs {service} {lines}') else: CLI.info('Reading logs...') containers = params.split(' ') if params else self.get_containers() lines = '-f' if params else '--tail 10' steps = len(containers) for index, container in enumerate(containers): CLI.step(index + 1, steps, f'{container} logs') os.system(f'docker {self.docker_ssh} logs {container} {lines}')
def networks(self): # todo for swarm CLI.info('Getting networks...') steps = 1 CLI.step(1, steps, 'List of Docker networks') networks = os.popen(f'docker {self.docker_ssh} network ls').read() networks = networks.strip().split('\n') for index, network in enumerate(networks): network_data = list(filter(lambda x: x != '', network.split(' '))) network_name = network_data[1] if index == 0: print(f'{network}\tCONTAINERS') else: containers = os.popen( f'docker {self.docker_ssh} network inspect -f \'{{{{ range $key, $value := .Containers }}}}{{{{ .Name }}}} {{{{ end }}}}\' {network_name}' ).read() containers = ', '.join(containers.split()) print(f'{network}\t{containers}'.strip())
def build(self, params=''): CLI.info(f'Building...') CLI.info(f'Params = {params}') CLI.info(f'Dockerfile = {self.configs_path}/docker/{self.DOCKER_FILE}') steps = 1 CLI.step(1, steps, 'Building Docker image...') build_args = self.config['build']['args'] build_args = ','.join(map('='.join, build_args.items())) build_kit = self.config['build']['kit'] build_kit = 'DOCKER_BUILDKIT=1' if build_kit else '' if build_args != '': build_args = build_args.split(',') build_args = [f'--build-arg {arg}' for arg in build_args] build_args = ' '.join(build_args) CLI.info(f'Kit = {build_kit}') CLI.info(f'Args = {build_args}') os.system( f'time {build_kit} docker build . {build_args} -t {self.IMAGE_NAME} -f {self.configs_path}/docker/{self.DOCKER_FILE} {params}' )
def send_test_email(self): CLI.info('Sending test email...') os.system( f'docker {self.docker_ssh} exec -i {self.CONTAINER_APP} python manage.py sendtestemail --admins' )
def reload(self): # todo deploy swarm CLI.info('Reloading containers...') zero_downtime_services = self.config['containers']['deploy'][ 'zero_downtime'] restart_services = self.config['containers']['deploy']['restart'] steps = 5 step = 1 CLI.step(step, steps, f'Zero downtime services: {zero_downtime_services}') for service in zero_downtime_services: container = self.get_container_name(service) os.system( f'docker-compose {self.docker_ssh} -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.yml -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml --project-name={self.PROJECT_NAME} run -d --service-ports --name={container}_new {service}' ) CLI.info(f'Renaming old container [{container}_old]...') if container in self.get_containers(): os.system( f'docker {self.docker_ssh} container rename {container} {container}_old' ) else: CLI.info(f'{container}_old was not running') CLI.info(f'Renaming new container [{container}]...') os.system( f'docker {self.docker_ssh} container rename {container}_new {container}' ) step += 1 CLI.step(step, steps, 'Collecting static files') os.system( f'docker {self.docker_ssh} exec -i {self.CONTAINER_APP} python manage.py collectstatic --noinput --verbosity 0' ) step += 1 CLI.step(step, steps, 'Reloading webserver...') os.system( f'docker {self.docker_ssh} exec -it {self.CONTAINER_WEBSERVER} {self.WEBSERVER} -s reload' ) step += 1 CLI.step( step, steps, f'Stopping old zero downtime services: {zero_downtime_services}') for service in zero_downtime_services: container = self.get_container_name(service) if container in self.get_containers(): CLI.info(f'Stopping old container [{container}_old]...') os.system( f'docker {self.docker_ssh} container stop {container}_old') CLI.info(f'Removing old container [{container}_old]...') os.system( f'docker {self.docker_ssh} container rm {container}_old') else: CLI.info(f'{container}_old was not running') step += 1 CLI.step(step, steps, f'Restart services: {restart_services}') for service in restart_services: container = self.get_container_name(service) CLI.underline(f'Recreating {service} container ({container})...') if container in self.get_containers(): CLI.info(f'Stopping container [{container}]...') os.system( f'docker {self.docker_ssh} container stop {container}') CLI.info(f'Removing container [{container}]...') os.system(f'docker {self.docker_ssh} container rm {container}') CLI.info(f'Creating new container [{container}]...') os.system( f'docker-compose {self.docker_ssh} -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.yml -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml --project-name={self.PROJECT_NAME} run -d --service-ports --name={container} {service}' ) else: CLI.info(f'{container} was not running')
def exec(self, params): container, command = params.split(' ', maxsplit=1) CLI.info(f'Executing command "{command}" in container {container}...') os.system(f'docker {self.docker_ssh} exec -it {container} {command}')
def psql(self): CLI.info('Starting psql...') env = self.load_environment() os.system( f'docker {self.docker_ssh} exec -it {self.CONTAINER_DB} psql -h {env["POSTGRES_HOST"]} -U {env["POSTGRES_USER"]} -d {env["POSTGRES_DBNAME"]} -W' )
def manage(self, params): CLI.info('Django manage...') os.system( f'docker {self.docker_ssh} exec -ti {self.CONTAINER_APP} python manage.py {params}' )
def ssh(self, params): CLI.info('Logging to container...') os.system(f'docker {self.docker_ssh} exec -it {params} /bin/sh')
def shell(self): CLI.info('Connecting to Django shell...') os.system( f'docker {self.docker_ssh} exec -i {self.CONTAINER_APP} python manage.py shell' )
def pull(self): CLI.info('Pulling docker image...') os.system( f'docker-compose {self.docker_ssh} -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.yml -f {self.configs_path}/docker/{self.COMPOSE_PREFIX}.{self.environment_id}.yml pull' )
def reload_webserver(self): CLI.info('Reloading webserver...') os.system( f'docker {self.docker_ssh} exec -it {self.CONTAINER_WEBSERVER} {self.WEBSERVER} -s reload' )
def clean(self): # todo clean on all nodes CLI.info('Cleaning...') steps = 1 CLI.step(1, steps, 'Prune Docker images and volumes') os.system(f'docker {self.docker_ssh} system prune --volumes --force')