fabfile.py 7.42 KB
Newer Older
1
#!/bin/echo Usage: fab --list -f
Bach Dániel committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.

Őry Máté committed
20 21 22
import contextlib
import datetime

Őry Máté committed
23
from fabric.api import env, run, settings, sudo, prefix, cd, execute
Őry Máté committed
24
from fabric.context_managers import shell_env
Őry Máté committed
25
from fabric.decorators import roles, parallel
Őry Máté committed
26 27


Őry Máté committed
28
env.roledefs['portal'] = ['localhost']
29 30

try:
31 32
    import django
    django.setup()
33 34
    from vm.models import Node as _Node
    from storage.models import DataStore as _DataStore
35 36 37 38
except Exception as e:
    print e
else:
    env.roledefs['node'] = [unicode(n.host.ipv4)
39 40
                            for n in _Node.objects.filter(enabled=True)]
    env.roledefs['storage'] = [_DataStore.objects.get().hostname]
Őry Máté committed
41 42 43


def update_all():
Őry Máté committed
44
    "Update and restart portal+manager, nodes and storage"
Őry Máté committed
45
    execute(stop_portal)
Őry Máté committed
46
    execute(parallel(update_node))
Őry Máté committed
47
    execute(update_storage)
Őry Máté committed
48
    execute(update_portal)
Őry Máté committed
49 50


Őry Máté committed
51 52 53 54 55 56
def pip(env, req):
    "Install pip requirements"
    with _workon(env):
        run("pip install -r %s" % req)


Őry Máté committed
57 58 59 60
def bower(component=None):
    "Install bower component"
    with cd("~/circle/circle"):
        if component:
61
            run("bower install %s --config.interactive=false" % component)
Őry Máté committed
62
        else:
63
            run("bower install --config.interactive=false")
Őry Máté committed
64 65


Őry Máté committed
66
@roles('portal')
Bach Dániel committed
67 68 69 70 71 72 73 74
def flake8():
    "Run portal tests"
    with _workon("circle"), cd("~/circle/circle"):
        run("flake8 . --exclude=migrations,bower_components,"
            "south_migrations,static_collected --max-complexity 12")


@roles('portal')
Őry Máté committed
75 76 77
def migrate():
    "Run db migrations"
    with _workon("circle"), cd("~/circle/circle"):
78
        run("./manage.py migrate --fake-initial")
Őry Máté committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101


@roles('portal')
def compile_js():
    "Generate JS translation objects"
    with _workon("circle"), cd("~/circle/circle"):
        run("./manage.py compilejsi18n -o dashboard/static/jsi18n")


@roles('portal')
def collectstatic():
    "Collect static files"
    with _workon("circle"), cd("~/circle/circle"):
        run("./manage.py collectstatic --noinput")


@roles('portal')
def compile_messages():
    "Generate MO translation objects"
    with _workon("circle"), cd("~/circle/circle"):
        run("./manage.py compilemessages")


102 103 104 105 106 107
def compile_less():
    "Compile LESS files"
    with _workon("circle"), cd("~/circle/circle"):
        run("./manage.py compileless")


Őry Máté committed
108 109 110 111
@roles('portal')
def compile_things():
    "Compile translation and collect static files"
    compile_js()
112
    compile_less()
Őry Máté committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    collectstatic()
    compile_messages()


@roles('portal')
def make_messages():
    "Update PO translation templates and commit"
    with _workon("circle"), cd("~/circle/circle"):
        run("git status")
        run("./manage.py makemessages -d djangojs -a --ignore=jsi18n/*")
        run("./manage.py makemessages -d django -a")
        run("git commit -avm 'update PO templates'")


@roles('portal')
def test(test=""):
    "Run portal tests"
    with _workon("circle"), cd("~/circle/circle"):
Őry Máté committed
131 132 133 134
        if test == "f":
            test = "--failed"
        else:
            test += " --with-id"
Őry Máté committed
135 136 137
        run("./manage.py test --settings=circle.settings.test %s" % test)


138
@roles('portal')
139
def selenium(test=""):
140
    "Run selenium tests"
141
    with _workon("circle"), cd("~/circle/circle"):
142 143 144 145
        if test == "f":
            test = "--failed"
        else:
            test += " --with-id"
146 147
        run('xvfb-run --server-args="-screen 0, 1920x1080x24" ./manage.py'
            ' test --settings=circle.settings.selenium_test %s' % test)
Őry Máté committed
148 149 150 151 152


def pull(dir="~/circle/circle"):
    "Pull from upstream branch (stash any changes)"
    now = unicode(datetime.datetime.now())
Őry Máté committed
153 154 155 156 157
    with cd(dir), shell_env(GIT_AUTHOR_NAME="fabric",
                            GIT_AUTHOR_EMAIL="fabric@local",
                            GIT_COMMITTER_NAME="fabric",
                            GIT_COMMITTER_EMAIL="fabric@local"):
        run("git stash save update %s" % now)
Őry Máté committed
158 159 160 161
        run("git pull --ff-only")


@roles('portal')
162
def update_portal(test=False, git=True):
Őry Máté committed
163
    "Update and restart portal+manager"
Guba Sándor committed
164
    with _stopped("portal", "manager"):
165 166
        if git:
            pull()
Őry Máté committed
167
        cleanup()
Őry Máté committed
168
        pip("circle", "~/circle/requirements.txt")
169
        sudo("cp ~/circle/miscellaneous/*celery.conf /etc/init/")
Őry Máté committed
170
        bower()
Őry Máté committed
171 172 173 174 175 176
        migrate()
        compile_things()
        if test:
            test()


Őry Máté committed
177
@roles('portal')
178 179 180 181 182 183
def build_portal():
    "Update portal without pulling from git"
    return update_portal(False, False)


@roles('portal')
Őry Máté committed
184
def stop_portal(test=False):
Őry Máté committed
185
    "Stop portal and manager"
Guba Sándor committed
186
    _stop_services("portal", "manager")
Őry Máté committed
187 188


Őry Máté committed
189 190 191
@roles('node')
def update_node():
    "Update and restart nodes"
192
    with _stopped("node", "agentdriver", "monitor-client"):
Őry Máté committed
193
        pull("~/vmdriver")
Őry Máté committed
194
        pip("vmdriver", "~/vmdriver/requirements/production.txt")
Őry Máté committed
195 196
        _cleanup("~/vmdriver")

Őry Máté committed
197
        pull("~/agentdriver")
Őry Máté committed
198
        pip("agentdriver", "~/agentdriver/requirements.txt")
Őry Máté committed
199 200
        _cleanup("~/agentdriver")

201 202
        pull("~/monitor-client")
        pip("monitor-client", "~/monitor-client/requirements.txt")
Őry Máté committed
203
        _cleanup("~/monitor-client")
Őry Máté committed
204 205 206 207 208 209 210 211


@parallel
@roles('storage')
def update_storage():
    "Update and restart storagedriver"
    with _stopped("storage"):
        pull("~/storagedriver")
212
        pip("storagedriver", "~/storagedriver/requirements/production.txt")
Őry Máté committed
213 214 215 216 217 218 219 220 221 222


@parallel
@roles('node')
def checkout(vmdriver="master", agent="master"):
    """Checkout specific branch on nodes"""
    with settings(warn_only=True), cd("~/vmdriver"):
        run("git checkout %s" % vmdriver)
    with settings(warn_only=True), cd("~/agentdriver"):
        run("git checkout %s" % agent)
Őry Máté committed
223 224


Őry Máté committed
225 226 227 228 229 230 231 232
@roles('portal')
def cleanup():
    "Clean pyc files of portal"
    _cleanup()


def _cleanup(dir="~/circle/circle"):
    "Clean pyc files"
233
    with cd(dir):
Őry Máté committed
234 235 236
        run("find -name '*.py[co]' -exec rm -f {} +")


Őry Máté committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
def _stop_services(*services):
    "Stop given services (warn only if not running)"
    with settings(warn_only=True):
        for service in reversed(services):
            sudo("stop %s" % service)


def _start_services(*services):
    for service in services:
        sudo("start %s" % service)


def _restart_service(*services):
    "Stop and start services"
    _stop_services(*services)
    _start_services(*services)


@contextlib.contextmanager
def _stopped(*services):
Őry Máté committed
257
    _stop_services(*services)
Őry Máté committed
258 259 260 261 262 263 264
    yield
    _start_services(*services)


def _workon(name):
    return prefix("source ~/.virtualenvs/%s/bin/activate && "
                  "source ~/.virtualenvs/%s/bin/postactivate" % (name, name))
265 266 267 268 269 270 271 272 273


@roles('portal')
def install_bash_completion_script():
    sudo("wget https://raw.githubusercontent.com/marcelor/fabric-bash-"
         "autocompletion/48baf5735bafbb2be5be8787d2c2c04a44b6cdb0/fab "
         "-O /etc/bash_completion.d/fab")
    print("To have bash completion instantly, run\n"
          "  source /etc/bash_completion.d/fab")