mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-08-02 11:10:12 +03:00
added fabfile for docker controls
This commit is contained in:
parent
a6e10f6600
commit
d1fe1069c7
249
{{cookiecutter.repo_name}}/fabfile.py
vendored
Normal file
249
{{cookiecutter.repo_name}}/fabfile.py
vendored
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
This is a collection of useful utility functions when working with docker on different environments.
|
||||||
|
|
||||||
|
In order to use these functions, install fabric on your local machine with::
|
||||||
|
|
||||||
|
pip install fabric
|
||||||
|
|
||||||
|
Please note: Fabric is a remote code execution tool, NOT a remote configuration tool. While you can copy files
|
||||||
|
from here to there, it is not a good replacement for salt or ansible in this regard.
|
||||||
|
|
||||||
|
There is a function called `production` where you need to fill in the details about your production machine(s).
|
||||||
|
|
||||||
|
You can then run::
|
||||||
|
|
||||||
|
fab production status
|
||||||
|
|
||||||
|
to get the status of your stack
|
||||||
|
|
||||||
|
To list all available commands, run::
|
||||||
|
|
||||||
|
fab -l
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
from fabric.operations import local as lrun, run, sudo
|
||||||
|
from fabric.api import *
|
||||||
|
from fabric.colors import green, red, yellow
|
||||||
|
from fabric.contrib.console import confirm
|
||||||
|
|
||||||
|
|
||||||
|
def local():
|
||||||
|
"""
|
||||||
|
Work on the local environment
|
||||||
|
"""
|
||||||
|
env.compose_file = "dev.yml"
|
||||||
|
env.project_dir = "."
|
||||||
|
env.run = lrun
|
||||||
|
env.cd = lcd
|
||||||
|
|
||||||
|
|
||||||
|
def production():
|
||||||
|
"""
|
||||||
|
Work on the production environment
|
||||||
|
"""
|
||||||
|
env.hosts = [""] # list the ip addresses or domain names of your production boxes here
|
||||||
|
env.port = 22 # ssh port
|
||||||
|
env.user = "root" # remote user, see `env.run` if you don't log in as root
|
||||||
|
|
||||||
|
env.compose_file = "docker-compose.yml"
|
||||||
|
env.project_dir = "" # this is the project dir where your code lives on this machine
|
||||||
|
|
||||||
|
# if you don't use key authentication, add your password here
|
||||||
|
# env.password = "foobar"
|
||||||
|
# if your machine has no bash installed, fall back to sh
|
||||||
|
# env.shell = "/bin/sh -c"
|
||||||
|
|
||||||
|
env.run = run # if you don't log in as root, replace with 'env.run = sudo'
|
||||||
|
env.cd = cd
|
||||||
|
|
||||||
|
|
||||||
|
def rollback(commit="HEAD~1"):
|
||||||
|
"""
|
||||||
|
Rollback to a previous commit and build the stack
|
||||||
|
:param commit: Commit you want to roll back to. Default is the previous commit
|
||||||
|
"""
|
||||||
|
with env.cd(env.project_dir):
|
||||||
|
env.run("git checkout {}".format(commit))
|
||||||
|
|
||||||
|
docker_compose("build")
|
||||||
|
|
||||||
|
|
||||||
|
def deploy():
|
||||||
|
"""
|
||||||
|
Pulls the latest changes from master, rebuilt and restarts the stack
|
||||||
|
"""
|
||||||
|
with env.cd(env.project_dir):
|
||||||
|
env.run("git pull origin master")
|
||||||
|
|
||||||
|
build()
|
||||||
|
restart()
|
||||||
|
|
||||||
|
|
||||||
|
def scale(service, n):
|
||||||
|
"""
|
||||||
|
Scale a service
|
||||||
|
:param service: Service to scale
|
||||||
|
:param n: Number of containers
|
||||||
|
"""
|
||||||
|
if service not in ["celeryworker"]:
|
||||||
|
print(red("{} is not scalabale, aborting".format(service)))
|
||||||
|
return
|
||||||
|
docker_compose("scale {service} {n}".format(service=service, n=n))
|
||||||
|
|
||||||
|
|
||||||
|
def restart():
|
||||||
|
"""
|
||||||
|
Restart all services
|
||||||
|
"""
|
||||||
|
docker_compose("restart")
|
||||||
|
|
||||||
|
|
||||||
|
def build(cache=True):
|
||||||
|
"""
|
||||||
|
Builds the the stack
|
||||||
|
:param cache: Use docker cache. Default is True
|
||||||
|
"""
|
||||||
|
docker_compose("build" if cache else "build --no-cache")
|
||||||
|
|
||||||
|
|
||||||
|
def status():
|
||||||
|
"""
|
||||||
|
Display the status of all services
|
||||||
|
"""
|
||||||
|
docker_compose("ps")
|
||||||
|
|
||||||
|
|
||||||
|
def django_shell():
|
||||||
|
"""
|
||||||
|
Starts a Django shell
|
||||||
|
"""
|
||||||
|
docker_compose("run django python manage.py shell")
|
||||||
|
|
||||||
|
|
||||||
|
def sql_shell():
|
||||||
|
"""
|
||||||
|
Starts a postgres shell
|
||||||
|
"""
|
||||||
|
_postgres("psql")
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_database():
|
||||||
|
"""
|
||||||
|
Run a Django database migration
|
||||||
|
"""
|
||||||
|
docker_compose("run django python manage.py migrate")
|
||||||
|
|
||||||
|
|
||||||
|
def dump_database(filepath):
|
||||||
|
"""
|
||||||
|
Dumps the database to a file
|
||||||
|
:param filepath:
|
||||||
|
"""
|
||||||
|
filepath = '/Users/j/test/dump.sql'
|
||||||
|
|
||||||
|
# make sure that the directory exists
|
||||||
|
with settings(warn_only=True):
|
||||||
|
dir = "/".join(filepath.split("/")[:-1])
|
||||||
|
if env.run("cd {}".format(dir)).return_code != 0:
|
||||||
|
print(red("{dir} does not exist. Make sure to create the directory before creating a"
|
||||||
|
" database dump to it.".format(dir=dir)))
|
||||||
|
print(red("Aborting"))
|
||||||
|
return
|
||||||
|
|
||||||
|
_postgres(command="pg_dump", pipe_out="> " + filepath)
|
||||||
|
|
||||||
|
|
||||||
|
def restore_database(filepath):
|
||||||
|
"""
|
||||||
|
Restores the database from a sql file (Not yet implemented)
|
||||||
|
:param filepath:
|
||||||
|
"""
|
||||||
|
# that's a bit tricky because we can't pipe in from stdin. We need to mount a volume that contains the dump
|
||||||
|
# and pipe it in from there. Compose doesn't support mounting volumes in `run` yet, so we'll have to wait.
|
||||||
|
# see https://github.com/docker/compose/issues/1769
|
||||||
|
print(red("Not yet implemented"))
|
||||||
|
|
||||||
|
|
||||||
|
def drop_database():
|
||||||
|
"""
|
||||||
|
Drop the database (Not yet implemented)
|
||||||
|
"""
|
||||||
|
print(red("Not yet implemented"))
|
||||||
|
return
|
||||||
|
print(red("****************************************************"))
|
||||||
|
print(red("* DANGER ZONE *"))
|
||||||
|
print(red("****************************************************"))
|
||||||
|
if confirm(yellow("You are about to DELETE the whole database. Are you sure?"), default=False):
|
||||||
|
_postgres(command="psql", pipe_in="-c \'DROP DATABASE;\'")
|
||||||
|
|
||||||
|
|
||||||
|
def logs(service=""):
|
||||||
|
"""
|
||||||
|
Display logs
|
||||||
|
:param service: Service to display the logs from. Default is all
|
||||||
|
"""
|
||||||
|
docker_compose("logs" if not service else "logs {}".format(service))
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
"""
|
||||||
|
Run a few test commands to check if the environment is setup correctly
|
||||||
|
"""
|
||||||
|
# test that project dir is set
|
||||||
|
if env.project_dir == "":
|
||||||
|
print(red("You need to set env.project_dir, it is currently empty."))
|
||||||
|
return
|
||||||
|
|
||||||
|
with settings(warn_only=True):
|
||||||
|
# test that the project dir exists
|
||||||
|
if env.run("cd {}".format(env.project_dir)).return_code != 0:
|
||||||
|
print(red("Your project directory '{}' does not exist on this machine. ".format(env.project_dir)))
|
||||||
|
return
|
||||||
|
|
||||||
|
# check that docker is installed
|
||||||
|
if env.run("docker --version").return_code != 0:
|
||||||
|
print(red("Can't run docker, is it installed?"))
|
||||||
|
return
|
||||||
|
|
||||||
|
# check that docker-compose is installed
|
||||||
|
if env.run("docker-compose --version").return_code != 0:
|
||||||
|
print(red("Can't run docker-compose, is it installed?"))
|
||||||
|
return
|
||||||
|
|
||||||
|
# check that git is installed
|
||||||
|
if env.run("git --version").return_code != 0:
|
||||||
|
print(red("Can't run git, is it installed?"))
|
||||||
|
return
|
||||||
|
|
||||||
|
print(green("I'm completely operational, and all my circuits are functioning perfectly."))
|
||||||
|
|
||||||
|
|
||||||
|
def docker_compose(command):
|
||||||
|
"""
|
||||||
|
Run a docker-compose command
|
||||||
|
:param command: Command you want to run
|
||||||
|
"""
|
||||||
|
with env.cd(env.project_dir):
|
||||||
|
return env.run("docker-compose -f {file} {command}".format(file=env.compose_file, command=command))
|
||||||
|
|
||||||
|
|
||||||
|
def _postgres(command=None, pipe_out="", pipe_in=""):
|
||||||
|
remote_env = docker_compose("run postgres /bin/sh -c 'printenv'").stdout
|
||||||
|
if not "POSTGRES_PORT_5432_TCP" in remote_env:
|
||||||
|
print(red("Postgres commands can not be run on a stopped container, make sure the container is running"))
|
||||||
|
return
|
||||||
|
|
||||||
|
docker_compose(
|
||||||
|
"run postgres /bin/sh -c '{password} {command} -h {host} -p {port} -U {user} -d {user} {pipe_in}' {pipe_out}".
|
||||||
|
format(
|
||||||
|
host="postgres",
|
||||||
|
port="5432",
|
||||||
|
user="$POSTGRES_USER" if "POSTGRES_USER" in remote_env else "postgres",
|
||||||
|
password="export PGPASSWORD=$POSTGRES_PASSWORD;" if "POSTGRES_PASSWORD" in remote_env else "",
|
||||||
|
command=command,
|
||||||
|
pipe_out=pipe_out,
|
||||||
|
pipe_in=pipe_in,
|
||||||
|
)
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user