helpers.py 8.08 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# coding: utf-8
#
# Copyright (C) 2016 Savoir-faire Linux Inc. (<www.savoirfairelinux.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from __future__ import unicode_literals
from getpass import getuser
from fabric.api import lcd, cd, task, roles, env, local, run, runs_once, execute
from fabric.colors import red, green
from fabric.contrib.console import confirm
from fabric.contrib.files import exists

# Import socket to find the localhost IP address
import socket

# Import datetime
from datetime import datetime

# Import default variables
from default_vars import *

# Import local variables' overrides, if they exist
if path.exists(path.join(path.dirname(__file__), 'local_vars.py')):
    from local_vars import *


#####################################################################
# Function to manage differents users, hosts, roles, and variables  #
#####################################################################

# Get info of the current user and host
user_name = getuser()
host_name = local("hostname", capture=True)

# Set the env dict with the roles and the hosts
env.roledefs['local'] = ["{}@{}".format(user_name, host_name)]
Emmanuel Milou's avatar
Emmanuel Milou committed
50
env.roledefs['docker'] = ["root@{}".format(env.site_hostname)]
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

# Flag to use for install the site with or without translations
LOCALE = False

# The CONTAINER_IP will be set at the creation of the container, see @task docker_run_container
CONTAINER_IP = None

env.builddir = path.join(env.workspace, 'build')
env.makefile = '{}/{}/{}'.format(env.builddir, env.site_profile, env.site_profile_makefile)
env.site_drush_aliases = path.join(env.site_root, 'sites/all/drush')

def set_env(role):
    """
    Helper function to set the correct values of the global variables in function of the role
    :param role: the role to use for define the host
    :return:
    """
    global INTERACTIVE_MODE
    INTERACTIVE_MODE = False if hasattr(env, 'mode') and env.mode == 'release' else True

    global WORKSPACE
    WORKSPACE = {
        'local': LOCAL_WORKSPACE,
        'docker': DOCKER_WORKSPACE
    }[role]

    global DRUPAL_ROOT
    DRUPAL_ROOT = {
        'local': LOCAL_DRUPAL_ROOT,
        'docker': '{}/src/drupal'.format(DOCKER_WORKSPACE)
    }[role]

    global BUILDDIR
    BUILDDIR = path.join(WORKSPACE, 'build')

    global MAKEFILE
    MAKEFILE = '{}/{}/{}'.format(BUILDDIR, PROFILE.keys()[0], PROFILE_MAKE_FILE)

    global DRUSH_ALIASES
    DRUSH_ALIASES = path.join(DRUPAL_ROOT, 'sites/all/drush')

    global DOCKER_IFACE_IP
    DOCKER_IFACE_IP = None
    if CONTAINER_IP:
        DOCKER_IFACE_IP = [(s.connect((CONTAINER_IP, 80)), s.getsockname()[0], s.close())
                           for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]


def fab_run(role="local", cmd="", capture=False):
    """
    Helper function to run the task locally or remotely
    :param role: the role to use for define the host
    :param cmd: the command to execute
    :param capture: if it should return or not the output of the command
    :return: the function to execute the command locally or remotely
    """
    if role == "local":
        return local(cmd, capture)
    else:
        return run(cmd)


def fab_cd(role, directory):
    """
    Helper function to manage the context locally or remotely
    :param role: the role to use for define the host
    :param directory: the directory of context
    :return: the function to manage the context locally or remotely
    """
    if role == "local":
        return lcd(directory)
    else:
        return cd(directory)


def fab_exists(role, directory):
    """
    Herlper function to check if a directory exist locally or remotely
    :param role: the role to use for define the host.
    :param directory: the directory to check
    :return: the function for check the existence of the directory locally or remotely
    """
    if role == "local":
        return path.exists(directory)
    else:
        return exists(directory)


def fab_add_to_hosts(ip, site_hostname):
    """
    Helper function to add the ip and hostname to /etc/hosts
    :param ip:
    :param site_hostname:
    :return:
    """
    if confirm(green('Do you want add to the /etc/hosts the line "{}    {}"? '
                     'If you say yes you will be able to visit the site using a more frienldy url '
                     '"http://{}".'.format(ip, site_hostname, site_hostname))):
        # Add if not find the comment "# Docker auto-added host" to the file /etc/hosts
        local('grep "# Docker auto-added host" /etc/hosts > /dev/null || '
              'sudo sed -i "$ a # Docker auto-added host" /etc/hosts')

        # Add the ip address and hostname after the comment "# Docker auto-added host"
        local('sudo sed -i "/# Docker auto-added host/a {}     {}" /etc/hosts'.format(ip, site_hostname))


def fab_remove_from_hosts(site_hostname):
    """
    Helper function to remove the ip  and the hostname to /etc/hosts
    :param site_hostname:
    :return:
    """
    print(green('Enter your password to remove the {} from your /etc/hosts file'.format(site_hostname)))
    local('sudo sed -i "/{}/d" /etc/hosts'.format(site_hostname))


def fab_update_hosts(ip, site_hostname):
    """
    Helper function to update the file /etc/hosts
    :param ip:
    :param site_hostname:
    :return:
    """
    fab_remove_from_hosts(site_hostname)
    fab_add_to_hosts(ip, site_hostname)


def hook_execute(hook, role='docker'):
    """
    Execute a list of drush commands after the installation or update process
    :param role Default 'role' where to run the task
    :param cmds Drush commands to run, default to POST_INSTALL, it could be POST_UPDATE too.
    """

    cmds = env.hook_post_install

    for cmd in cmds:
        with fab_cd(role, env.docker_site_root):
            fab_run(role, cmd)

191
192
193
194
195
196
197
198
199
200
201
202

def _copy_public_ssh_keys(role='local'):
    """
    Copy your public SSH keys to use it in the docker container to connect to it using ssh protocol.
    :param role Default 'role' where to run the task
    """
    set_env(role)
    with fab_cd(role, WORKSPACE):
        fab_run(role, 'cp ~/.ssh/id_rsa.pub conf/')
        print(green('Public SSH key copied successful'))


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
def _update_profile(role='local'):
    """
    Update or clone the installation profile specified in the configuration file.
    The build file included will be used to build the application.
    """
    if fab_exists(role, '{}/{}'.format(env.builddir, env.site_profile)):
        with fab_cd(role, path.join(env.builddir, env.site_profile)):
            fab_run(role, 'git checkout . && git pull')
            print green('{} installation profile updated in {}/{}'.format(env.site_profile, env.builddir, env.site_profile))
    else:
        with fab_cd(role, env.builddir):
            fab_run(role, 'git clone {} {}'.format(env.site_profile_repo, env.site_profile))
            print green('{} installation profile cloned in {}/{}'.format(env.site_profile, env.builddir, env.site_profile))


@roles('docker')
def _init_db(role='docker'):
    """
    Create a database and a user that can access it.
    """

    set_env(role)

    fab_run(role, 'mysql -uroot -e "CREATE DATABASE IF NOT EXISTS {}; GRANT ALL PRIVILEGES ON {}.* TO '
                  '\'{}\'@\'localhost\' IDENTIFIED BY \'{}\'; GRANT ALL PRIVILEGES ON {}.* TO \'{}\'@\'{}\' '
                  'IDENTIFIED BY \'{}\'; FLUSH PRIVILEGES;"'.format(env.site_db_name, env.site_db_name, env.site_db_user, env.site_db_pass,
                                                                    env.site_db_name, env.site_db_user, DOCKER_IFACE_IP, env.site_db_user))