Statistics
| Branch: | Tag: | Revision:

root / snf-deploy / snfdeploy / utils.py @ 3c3bccab

History | View | Annotate | Download (7.8 kB)

1
# Copyright (C) 2010, 2011, 2012, 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A. OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from __future__ import with_statement
35
from fabric.api import hide, env, settings, local, roles
36
from fabric.operations import run, put, get
37
import fabric
38
import re
39
import os
40
import shutil
41
import tempfile
42
import ast
43
from snfdeploy.lib import debug, Conf, Env, disable_color
44
from snfdeploy import massedit
45
from snfdeploy.components import *
46
from snfdeploy.roles import ROLES, CONFLICTS
47

    
48

    
49
def abort(action):
50
    def inner(*args, **kwargs):
51
        try:
52
            return action(*args, **kwargs)
53
        except BaseException as e:
54
            abort = kwargs.get("abort", True)
55
            force = env.force
56
            if not abort or force:
57
                 debug(env.host, "WARNING: command failed. Continuing anyway...")
58
            else:
59
                 fabric.utils.abort(e)
60
    return inner
61

    
62

    
63
@abort
64
def try_get(remote_path, local_path=None, **kwargs):
65
    if env.dry_run:
66
        debug(env.host, " * Fetching file localy... ", remote_path)
67
        return
68
    get(remote_path, local_path=local_path, **kwargs)
69

    
70

    
71
@abort
72
def try_put(local_path=None, remote_path=None, mode=0644, **kwargs):
73
    if env.dry_run:
74
        debug(env.host, " * Upload file... ", remote_path)
75
        return
76
    put(local_path=local_path, remote_path=remote_path, mode=mode)
77

    
78

    
79
@abort
80
def try_run(cmd, **kwargs):
81
    if env.dry_run:
82
        debug(env.host, cmd)
83
        return ""
84
    elif env.local:
85
        return local(cmd, capture=True, shell="/bin/bash")
86
    else:
87
        return run(cmd)
88

    
89

    
90
def install_package(package):
91
    debug(env.host, " * Installing package... ", package)
92
    apt_get = "export DEBIAN_FRONTEND=noninteractive ;" + \
93
              "apt-get install -y --force-yes "
94

    
95
    host_info = env.env.ips_info[env.host]
96
    env.env.update_packages(host_info.os)
97
    if ast.literal_eval(env.env.use_local_packages):
98
        with settings(warn_only=True):
99
            deb = local("ls %s/%s*%s_*.deb"
100
                        % (env.env.packages, package, host_info.os),
101
                        capture=True)
102
            if deb:
103
                debug(env.host,
104
                      " * Package %s found in %s..."
105
                      % (package, env.env.packages))
106
                try_put(deb, "/tmp/")
107
                try_run("dpkg -i /tmp/%s || "
108
                        % os.path.basename(deb) + apt_get + "-f")
109
                try_run("rm /tmp/%s" % os.path.basename(deb))
110
                return
111

    
112
    info = getattr(env.env, package)
113
    if info in \
114
            ["squeeze-backports", "squeeze", "stable",
115
             "testing", "unstable", "wheezy"]:
116
        apt_get += " -t %s %s " % (info, package)
117
    elif info:
118
        apt_get += " %s=%s " % (package, info)
119
    else:
120
        apt_get += package
121

    
122
    try_run(apt_get)
123

    
124
    return
125

    
126

    
127
def customize_settings_from_tmpl(tmpl, replace):
128
    debug(env.host, " * Customizing template %s..." % tmpl)
129
    local = env.env.templates + tmpl
130
    _, custom = tempfile.mkstemp()
131
    shutil.copyfile(local, custom)
132
    for k, v in replace.iteritems():
133
        regex = "re.sub('%{0}%', '{1}', line)".format(k.upper(), v)
134
        massedit.edit_files([custom], [regex], dry_run=False)
135

    
136
    return custom
137

    
138

    
139
def get_node_info(ident):
140
    if ident in env.env.ips_info:
141
        return env.env.ips_info[ident]
142
    elif ident in env.env.hosts_info:
143
        return env.env.hosts_info[ident]
144
    elif ident in env.env.nodes_info:
145
        return env.env.nodes_info[ident]
146

    
147

    
148
def GetFromComponent(component, remote, local):
149
    c = GetSynnefoComponent(component)
150
    c.debug(" * Downloading: ", remote)
151
    with settings(host_string=c.node_info.ip):
152
        try_get(remote, local)
153

    
154

    
155
def PutToComponent(component, local, remote):
156
    c = GetSynnefoComponent(component)
157
    c.debug(" * Uploading: ", remote)
158
    with settings(host_string=c.node_info.ip):
159
        try_put(local, remote)
160

    
161

    
162
def RunComponentMethod(component, method, *args, **kwargs):
163
    c = GetSynnefoComponent(component)
164
    c.debug(" * Running method: ", method)
165
    with settings(host_string=c.node_info.ip):
166
        fn = getattr(c, method)
167
        ret = ""
168
        for cmd in fn(*args, **kwargs):
169
            ret += try_run(cmd)
170
        return ret
171

    
172

    
173
def GetSynnefoComponent(component):
174
    node_info = get_node_info(env.host)
175
    env.password = node_info.passwd
176
    return component(node_info, env)
177

    
178

    
179
def conflicting_exists(component):
180
    conflict = CONFLICTS.get(component, [])
181
    for c in conflict:
182
        cs = env.env.status.check_status(env.host, c)
183
        if cs:
184
            debug(env.host, "Conflicting component already exists", c.__name__)
185
            return True
186

    
187
    return False
188

    
189

    
190
def SetupSynnefoRole(role):
191
    debug("Setting up base configuration for: ", role)
192
    try:
193
        components = ROLES.get(role)
194
    except KeyError:
195
        debug(env.host, "Please give a valid role")
196
        return
197
    for c in components:
198
        if conflicting_exists(c):
199
            continue
200
        status = env.env.status.check_status(env.host, c)
201
        if status:
202
            debug(env.host, "Base configuration already exists", c.__name__)
203
        else:
204
            AddSynnefoComponent(c)
205
            env.env.status.update_status(env.host, c, "ok")
206
            env.env.status.write_status()
207

    
208

    
209
class AddSynnefoComponent(object):
210

    
211
    def _run(self, commands):
212
        for c in commands:
213
            try_run(c)
214

    
215
    def _install(self, packages):
216
        for p in packages:
217
            install_package(p)
218

    
219
    def _configure(self, templates):
220
        for tmpl, replace, opts in templates:
221
            mode = opts.get("mode", 0644)
222
            remote = opts.get("remote", tmpl)
223
            custom = customize_settings_from_tmpl(tmpl, replace)
224
            try_put(custom, remote, mode)
225
            os.remove(custom)
226

    
227
    def __init__(self, component):
228
        self.c = GetSynnefoComponent(component)
229
        self.c.debug("Adding component..")
230

    
231
        self.c.debug(" * Checking prerequisites..")
232
        self._run(self.c.check())
233

    
234
        self.c.debug(" * Installing packages..")
235
        self._install(self.c.install())
236

    
237
        self.c.debug(" * Preparing configuration..")
238
        self._run(self.c.prepare())
239

    
240
        self.c.debug(" * Setting up configuration files..")
241
        self._configure(self.c.configure())
242

    
243
        self.c.debug(" * Restarting services..")
244
        self._run(self.c.restart())
245

    
246
        self.c.debug(" * Initializing setup..")
247
        self._run(self.c.initialize())
248

    
249
        self.c.debug(" * Testing setup..")
250
        self._run(self.c.test())