Statistics
| Branch: | Tag: | Revision:

root / snf-deploy / fabfile.py @ 542d8129

History | View | Annotate | Download (37.3 kB)

1
from __future__ import with_statement
2
from fabric.api import *
3
from fabric.contrib.console import confirm
4
from random import choice
5
from fabric.operations import run, put
6
import re
7
import shutil, os
8
from functools import wraps
9
import imp
10
import ConfigParser
11
import sys
12
import tempfile
13
import ast
14
from snfdeploy.lib import *
15
from snfdeploy import massedit
16

    
17

    
18
def setup_env(confdir="conf", packages="packages",
19
              templates="files", cluster_name="ganeti1", autoconf=False, disable_colors=False):
20
    print("Loading configuration for synnefo...")
21
    print(" * Using config files under %s..." % confdir)
22
    print(" * Using %s and %s for packages and templates accordingly..." % (packages, templates))
23

    
24
    autoconf = ast.literal_eval(autoconf)
25
    disable_colors = ast.literal_eval(disable_colors)
26
    conf = Conf.configure(confdir=confdir, cluster_name=cluster_name, autoconf=autoconf)
27
    env.env = Env(conf)
28

    
29
    env.local = autoconf
30
    env.password = env.env.password
31
    env.user = env.env.user
32
    env.shell = "/bin/bash -c"
33

    
34
    if disable_colors:
35
        disable_color()
36

    
37
    if env.env.cms.hostname in [env.env.accounts.hostname, env.env.cyclades.hostname, env.env.pithos.hostname]:
38
      env.cms_pass = True
39
    else:
40
      env.cms_pass = False
41

    
42
    if env.env.accounts.hostname in [env.env.cyclades.hostname, env.env.pithos.hostname]:
43
      env.csrf_disable = True
44
    else:
45
      env.csrf_disable = False
46

    
47

    
48
    env.roledefs = {
49
        "nodes": env.env.ips,
50
        "ips": env.env.ips,
51
        "accounts": [env.env.accounts.ip],
52
        "cyclades": [env.env.cyclades.ip],
53
        "pithos": [env.env.pithos.ip],
54
        "cms": [env.env.cms.ip],
55
        "mq": [env.env.mq.ip],
56
        "db": [env.env.db.ip],
57
        "ns": [env.env.ns.ip],
58
        "client": [env.env.client.ip],
59
        "router": [env.env.router.ip],
60
    }
61

    
62
    env.enable_lvm = False
63
    env.enable_drbd = False
64
    if ast.literal_eval(env.env.create_extra_disk) and env.env.extra_disk:
65
        env.enable_lvm = True
66
        env.enable_drbd = True
67

    
68
    env.roledefs.update({
69
        "ganeti": env.env.cluster_ips,
70
        "master": [env.env.master.ip],
71
    })
72

    
73

    
74
def install_package(package):
75
    debug(env.host, " * Installing package %s..." % package)
76
    APT_GET = "export DEBIAN_FRONTEND=noninteractive ;apt-get install -y --force-yes "
77

    
78
    if ast.literal_eval(env.env.use_local_packages):
79
        with settings(warn_only=True):
80
            deb = local("ls %s/%s*deb" % (env.env.packages, package))
81
            if deb:
82
                debug(env.host, " * Package %s found in %s..." % (package, env.env.packages))
83
                put(deb, "/tmp/")
84
                try_run("dpkg -i /tmp/%s*deb || " % package + APT_GET + "-f")
85
                try_run("rm /tmp/%s*deb" % package)
86
                return
87

    
88
    info = getattr(env.env, package)
89
    if info in ["stable", "squeeze-backports", "testing", "unstable"]:
90
        APT_GET += " -t %s %s " % (info, package)
91
    elif info:
92
        APT_GET += " %s=%s " % (package, info)
93
    else:
94
        APT_GET += package
95

    
96
    try_run(APT_GET)
97

    
98
    return
99

    
100

    
101
@roles("ns")
102
def update_ns_for_ganeti():
103
    debug(env.host, "Updating name server entries for backend %s..." % env.env.cluster.fqdn)
104
    update_arecord(env.env.cluster)
105
    update_ptrrecord(env.env.cluster)
106
    try_run("/etc/init.d/bind9 restart")
107

    
108

    
109
@roles("ns")
110
def update_ns_for_node(node):
111
    info = env.env.nodes_info.get(node)
112
    update_arecord(info)
113
    update_ptrrecord(info)
114
    try_run("/etc/init.d/bind9 restart")
115

    
116

    
117
@roles("ns")
118
def update_arecord(host):
119
    filename = "/etc/bind/zones/" + env.env.domain
120
    cmd = """
121
    echo '{0}' >> {1}
122
    """.format(host.arecord, filename)
123
    try_run(cmd)
124

    
125

    
126
@roles("ns")
127
def update_cnamerecord(host):
128
    filename = "/etc/bind/zones/" + env.env.domain
129
    cmd = """
130
    echo '{0}' >> {1}
131
    """.format(host.cnamerecord, filename)
132
    try_run(cmd)
133

    
134

    
135
@roles("ns")
136
def update_ptrrecord(host):
137
    filename = "/etc/bind/rev/synnefo.in-addr.arpa.zone"
138
    cmd = """
139
    echo '{0}' >> {1}
140
    """.format(host.ptrrecord, filename)
141
    try_run(cmd)
142

    
143
@roles("nodes")
144
def apt_get_update():
145
    debug(env.host, "apt-get update....")
146
    try_run("apt-get update")
147

    
148
@roles("ns")
149
def setup_ns():
150
    debug(env.host, "Setting up name server..")
151
    #WARNING: this should be remove after we are done
152
    # because gevent does pick randomly nameservers and google does
153
    # not know our setup!!!!!
154
    apt_get_update()
155
    install_package("bind9")
156
    tmpl = "/etc/bind/named.conf.local"
157
    replace = {
158
      "domain": env.env.domain,
159
      }
160
    custom = customize_settings_from_tmpl(tmpl, replace)
161
    put(custom, tmpl)
162

    
163
    try_run("mkdir -p /etc/bind/zones")
164
    tmpl = "/etc/bind/zones/example.com"
165
    replace = {
166
      "domain": env.env.domain,
167
      "ns_node_ip": env.env.ns.ip,
168
      }
169
    custom = customize_settings_from_tmpl(tmpl, replace)
170
    remote = "/etc/bind/zones/" + env.env.domain
171
    put(custom, remote)
172

    
173
    try_run("mkdir -p /etc/bind/rev")
174
    tmpl = "/etc/bind/rev/synnefo.in-addr.arpa.zone"
175
    replace = {
176
      "domain": env.env.domain,
177
      }
178
    custom = customize_settings_from_tmpl(tmpl, replace)
179
    put(custom, tmpl)
180

    
181
    tmpl = "/etc/bind/named.conf.options"
182
    replace = {
183
      "NODE_IPS": ";".join(env.env.ips),
184
      }
185
    custom = customize_settings_from_tmpl(tmpl, replace)
186
    put(custom, tmpl, mode=0644)
187

    
188
    for role, info in env.env.roles.iteritems():
189
        if role == "ns":
190
            continue
191
        update_cnamerecord(info)
192
    for node, info in env.env.nodes_info.iteritems():
193
        update_arecord(info)
194
        update_ptrrecord(info)
195

    
196
    try_run("/etc/init.d/bind9 restart")
197

    
198

    
199
@roles("nodes")
200
def check_dhcp():
201
    debug(env.host, "Checking IPs for synnefo..")
202
    for n, info in env.env.nodes_info.iteritems():
203
        try_run("ping -c 1 " + info.ip)
204

    
205
@roles("nodes")
206
def check_dns():
207
    debug(env.host, "Checking fqdns for synnefo..")
208
    for n, info in env.env.nodes_info.iteritems():
209
        try_run("ping -c 1 " + info.fqdn)
210

    
211
    for n, info in env.env.roles.iteritems():
212
        try_run("ping -c 1 " + info.fqdn)
213

    
214
@roles("nodes")
215
def check_connectivity():
216
    debug(env.host, "Checking internet connectivity..")
217
    try_run("ping -c 1 www.google.com")
218

    
219

    
220
@roles("nodes")
221
def check_ssh():
222
    debug(env.host, "Checking password-less ssh..")
223
    for n, info in env.env.nodes_info.iteritems():
224
        try_run("ssh " + info.fqdn + "  date")
225

    
226

    
227
@roles("ips")
228
def add_keys():
229
    debug(env.host, "Adding rsa/dsa keys..")
230
    try_run("mkdir -p /root/.ssh")
231
    cmd = """
232
for f in $(ls /root/.ssh/*); do
233
  cp $f $f.bak
234
done
235
    """
236
    try_run(cmd)
237
    files = ["authorized_keys", "id_dsa", "id_dsa.pub",
238
             "id_rsa", "id_rsa.pub"]
239
    for f in files:
240
      tmpl = "/root/.ssh/" + f
241
      replace = {}
242
      custom = customize_settings_from_tmpl(tmpl, replace)
243
      put(custom, tmpl)
244

    
245
    cmd = """
246
if [ -e /root/.ssh/authorized_keys.bak ]; then
247
  cat /root/.ssh/authorized_keys.bak >> /root/.ssh/authorized_keys
248
fi
249
    """
250
    debug(env.host, "Updating exising authorized keys..")
251
    try_run(cmd)
252

    
253
@roles("ips")
254
def setup_resolv_conf():
255
    debug(env.host, "Tweak /etc/resolv.conf...")
256
    try_run("/etc/init.d/network-manager stop")
257
    tmpl = "/etc/dhcp/dhclient-enter-hooks.d/nodnsupdate"
258
    replace = {}
259
    custom = customize_settings_from_tmpl(tmpl, replace)
260
    put(custom, tmpl, mode=0644)
261
    try_run("cp /etc/resolv.conf /etc/resolv.conf.bak")
262
    tmpl = "/etc/resolv.conf"
263
    replace = {
264
      "domain": env.env.domain,
265
      "ns_node_ip": env.env.ns.ip,
266
      }
267
    custom = customize_settings_from_tmpl(tmpl, replace)
268
    put(custom, tmpl)
269
    try_run("chattr +i /etc/resolv.conf")
270

    
271

    
272
@roles("ips")
273
def setup_hosts():
274
    debug(env.host, "Tweaking /etc/hosts and ssh_config files...")
275
    try_run("echo StrictHostKeyChecking no >> /etc/ssh/ssh_config")
276
    cmd = " sed -i 's/^127.*/127.0.0.1 localhost/g' /etc/hosts "
277
    try_run(cmd)
278

    
279

    
280
def try_run(cmd):
281
    try:
282
      if env.local:
283
        return local(cmd, capture=True)
284
      else:
285
        return run(cmd)
286
    except:
287
      debug(env.host, "WARNING: command failed. Continuing anyway...")
288

    
289
def create_bridges():
290
    debug(env.host, " * Creating bridges...")
291
    install_package("bridge-utils")
292
    cmd = """
293
    brctl addbr {0} ; ip link set {0} up
294
    """.format(env.env.common_bridge)
295
    try_run(cmd)
296

    
297

    
298
def connect_bridges():
299
    debug(env.host, " * Connecting bridges...")
300
    cmd = """
301
    brctl addif {0} {1}
302
    """.format(env.env.common_bridge, env.env.public_iface)
303
    #try_run(cmd)
304

    
305

    
306
@roles("ganeti")
307
def setup_net_infra():
308
    debug(env.host, "Setup networking infrastracture..")
309
    create_bridges()
310
    connect_bridges()
311

    
312

    
313
@roles("ganeti")
314
def setup_lvm():
315
    debug(env.host, "create volume group %s for ganeti.." % env.env.vg)
316
    if env.enable_lvm:
317
        install_package("lvm2")
318
        cmd = """
319
        pvcreate {0}
320
        vgcreate {1} {0}
321
        """.format(env.env.extra_disk, env.env.vg)
322
        try_run(cmd)
323

    
324

    
325
def customize_settings_from_tmpl(tmpl, replace):
326
    debug(env.host, " * Customizing template %s..." % tmpl)
327
    local = env.env.templates + tmpl
328
    _, custom = tempfile.mkstemp()
329
    shutil.copyfile(local, custom)
330
    for k, v in replace.iteritems():
331
        regex = "re.sub('%{0}%', '{1}', line)".format(k.upper(), v)
332
        massedit.edit_files([custom], [regex], dry_run=False)
333

    
334
    return custom
335

    
336

    
337
@roles("nodes")
338
def setup_apt():
339
    debug(env.host, "Setting up apt sources...")
340
    install_package("curl")
341
    cmd = """
342
    echo 'APT::Install-Suggests "false";' >> /etc/apt/apt.conf
343
    curl -k https://dev.grnet.gr/files/apt-grnetdev.pub | apt-key add -
344
    """
345
    try_run(cmd)
346
    tmpl = "/etc/apt/sources.list.d/okeanos.list"
347
    replace = {}
348
    custom = customize_settings_from_tmpl(tmpl, replace)
349
    put(custom, tmpl)
350
    apt_get_update()
351

    
352

    
353
@roles("cyclades", "cms", "pithos", "accounts")
354
def restart_services():
355
    debug(env.host, " * Restarting apache2 and gunicorn...")
356
    try_run("/etc/init.d/gunicorn restart")
357
    try_run("/etc/init.d/apache2 restart")
358

    
359

    
360
def setup_gunicorn():
361
    debug(env.host, " * Setting up gunicorn...")
362
    install_package("gunicorn")
363
    tmpl = "/etc/gunicorn.d/synnefo"
364
    replace = {}
365
    custom = customize_settings_from_tmpl(tmpl, replace)
366
    put(custom, tmpl, mode=0644)
367
    try_run("/etc/init.d/gunicorn restart")
368

    
369

    
370
def setup_apache():
371
    debug(env.host, " * Setting up apache2...")
372
    host_info = env.env.ips_info[env.host]
373
    install_package("apache2")
374
    tmpl = "/etc/apache2/sites-available/synnefo"
375
    replace = {
376
        "HOST": host_info.fqdn,
377
    }
378
    custom = customize_settings_from_tmpl(tmpl, replace)
379
    put(custom, tmpl)
380
    tmpl = "/etc/apache2/sites-available/synnefo-ssl"
381
    custom = customize_settings_from_tmpl(tmpl, replace)
382
    put(custom, tmpl)
383
    cmd = """
384
    a2enmod ssl
385
    a2enmod rewrite
386
    a2dissite default
387
    a2ensite synnefo
388
    a2ensite synnefo-ssl
389
    a2enmod headers
390
    a2enmod proxy_http
391
    a2dismod autoindex
392
    """
393
    try_run(cmd)
394
    try_run("/etc/init.d/apache2 restart")
395

    
396

    
397
@roles("mq")
398
def setup_mq():
399
    debug(env.host, "Setting up RabbitMQ...")
400
    install_package("rabbitmq-server")
401
    cmd = """
402
    rabbitmqctl add_user {0} {1}
403
    rabbitmqctl set_permissions {0} ".*" ".*" ".*"
404
    rabbitmqctl delete_user guest
405
    rabbitmqctl set_user_tags {0} administrator
406
    """.format(env.env.synnefo_user, env.env.synnefo_rabbitmq_passwd)
407
    try_run(cmd)
408
    try_run("/etc/init.d/rabbitmq-server restart")
409

    
410

    
411
@roles("db")
412
def allow_access_in_db(ip):
413
    cmd = """
414
    echo host all all {0}/32 md5 >> /etc/postgresql/8.4/main/pg_hba.conf
415
    """.format(ip)
416
    try_run(cmd)
417
    try_run("/etc/init.d/postgresql restart")
418

    
419
@roles("db")
420
def setup_db():
421
    debug(env.host, "Setting up DataBase server...")
422
    install_package("postgresql")
423

    
424
    tmpl = "/tmp/db-init.psql"
425
    replace = {
426
        "synnefo_user": env.env.synnefo_user,
427
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
428
        }
429
    custom = customize_settings_from_tmpl(tmpl, replace)
430
    put(custom, tmpl)
431
    cmd = 'su - postgres -c "psql -w -f %s" ' % tmpl
432
    try_run(cmd)
433
    cmd = """
434
    echo "listen_addresses = '*'" >> /etc/postgresql/8.4/main/postgresql.conf
435
    """
436
    try_run(cmd)
437

    
438
    try_run("/etc/init.d/postgresql restart")
439

    
440

    
441
@roles("db")
442
def destroy_db():
443
    try_run("""su - postgres -c ' psql -w -c "drop database snf_apps" '""")
444
    try_run("""su - postgres -c ' psql -w -c "drop database snf_pithos" '""")
445

    
446

    
447
def setup_webproject():
448
    debug(env.host, " * Setting up snf-webproject...")
449
    with settings(hide("everything")):
450
        try_run("ping -c1 " + env.env.db.ip)
451
    setup_common()
452
    install_package("snf-webproject")
453
    install_package("python-psycopg2")
454
    install_package("python-gevent")
455
    tmpl = "/etc/synnefo/webproject.conf"
456
    replace = {
457
        "synnefo_user": env.env.synnefo_user,
458
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
459
        "db_node": env.env.db.ip,
460
        "domain": env.env.domain,
461
    }
462
    custom = customize_settings_from_tmpl(tmpl, replace)
463
    put(custom, tmpl, mode=0644)
464
    with settings(host_string=env.env.db.ip):
465
        host_info = env.env.ips_info[env.host]
466
        allow_access_in_db(host_info.ip)
467
    try_run("/etc/init.d/gunicorn restart")
468

    
469

    
470
def setup_common():
471
    debug(env.host, " * Setting up snf-common...")
472
    host_info = env.env.ips_info[env.host]
473
    install_package("python-objpool")
474
    install_package("snf-common")
475
    install_package("python-astakosclient")
476
    install_package("snf-django-lib")
477
    install_package("snf-branding")
478
    tmpl = "/etc/synnefo/common.conf"
479
    replace = {
480
        #FIXME:
481
        "EMAIL_SUBJECT_PREFIX": env.host,
482
        "domain": env.env.domain,
483
        "HOST": host_info.fqdn,
484
    }
485
    custom = customize_settings_from_tmpl(tmpl, replace)
486
    put(custom, tmpl, mode=0644)
487
    try_run("/etc/init.d/gunicorn restart")
488

    
489
@roles("accounts")
490
def astakos_loaddata():
491
    debug(env.host, " * Loading initial data to astakos...")
492
    cmd = """
493
    snf-manage loaddata groups
494
    """
495
    try_run(cmd)
496

    
497

    
498
@roles("accounts")
499
def astakos_register_services():
500
    debug(env.host, " * Register services in astakos...")
501
    cmd = """
502
    snf-manage component-add "home" https://{0} home-icon.png
503
    snf-manage component-add "cyclades" https://{1}/cyclades/ui/
504
    snf-manage component-add "pithos" https://{2}/pithos/ui/
505
    snf-manage component-add "astakos" https://{3}/astakos/ui/
506
    """.format(env.env.cms.fqdn, env.env.cyclades.fqdn, env.env.pithos.fqdn, env.env.accounts.fqdn)
507
    try_run(cmd)
508
    import_service("astakos")
509
    import_service("pithos")
510
    import_service("cyclades")
511
    tmpl = "/tmp/resources.json"
512
    replace = {}
513
    custom = customize_settings_from_tmpl(tmpl, replace)
514
    put(custom, tmpl)
515
    try_run("snf-manage resource-import --json %s" % tmpl)
516
    cmd = """
517
    snf-manage resource-modify --limit 40G pithos.diskspace
518
    snf-manage resource-modify --limit 2 astakos.pending_app
519
    snf-manage resource-modify --limit 4 cyclades.vm
520
    snf-manage resource-modify --limit 40G cyclades.disk
521
    snf-manage resource-modify --limit 8G cyclades.ram
522
    snf-manage resource-modify --limit 16 cyclades.cpu
523
    snf-manage resource-modify --limit 4 cyclades.network.private
524
    """
525
    try_run(cmd)
526

    
527

    
528
@roles("accounts")
529
def add_user():
530
    debug(env.host, " * adding user %s to astakos..." % env.env.user_email)
531
    email=env.env.user_email
532
    name=env.env.user_name
533
    lastname=env.env.user_lastname
534
    passwd=env.env.user_passwd
535
    cmd = """
536
    snf-manage user-add {0} {1} {2}
537
    """.format(email, name, lastname)
538
    try_run(cmd)
539
    with settings(host_string=env.env.db.ip):
540
        uid, user_auth_token, user_uuid = get_auth_token_from_db(email)
541
    cmd = """
542
    snf-manage user-modify --password {0} {1}
543
    """.format(passwd, uid)
544
    try_run(cmd)
545

    
546

    
547
@roles("accounts")
548
def activate_user(user_email=None):
549
    if not user_email:
550
      user_email = env.env.user_email
551
    debug(env.host, " * Activate user %s..." % user_email)
552
    with settings(host_string=env.env.db.ip):
553
        uid, user_auth_token, user_uuid = get_auth_token_from_db(user_email)
554

    
555
    cmd = """
556
    snf-manage user-modify --verify {0}
557
    snf-manage user-modify --accept {0}
558
    """.format(uid)
559
    try_run(cmd)
560

    
561
@roles("accounts")
562
def setup_astakos():
563
    debug(env.host, "Setting up snf-astakos-app...")
564
    setup_gunicorn()
565
    setup_apache()
566
    setup_webproject()
567
    install_package("python-django-south")
568
    install_package("snf-astakos-app")
569
    install_package("kamaki")
570

    
571
    tmpl = "/etc/synnefo/astakos.conf"
572
    replace = {
573
      "ACCOUNTS": env.env.accounts.fqdn,
574
      "domain": env.env.domain,
575
      "CYCLADES": env.env.cyclades.fqdn,
576
      "PITHOS": env.env.pithos.fqdn,
577
    }
578
    custom = customize_settings_from_tmpl(tmpl, replace)
579
    put(custom, tmpl, mode=0644)
580
    if env.csrf_disable:
581
      cmd = """
582
cat <<EOF >> /etc/synnefo/astakos.conf
583
try:
584
  MIDDLEWARE_CLASSES.remove('django.middleware.csrf.CsrfViewMiddleware')
585
except:
586
  pass
587
EOF
588
"""
589
      try_run(cmd)
590

    
591
    try_run("/etc/init.d/gunicorn restart")
592

    
593
    cmd = """
594
    snf-manage syncdb --noinput
595
    snf-manage migrate im --delete-ghost-migrations
596
    snf-manage migrate quotaholder_app
597
    """
598
    try_run(cmd)
599

    
600
def import_service(service):
601
    tmpl = "/tmp/%s.json" % service
602
    replace = {
603
      "DOMAIN": env.env.domain,
604
      }
605
    custom = customize_settings_from_tmpl(tmpl, replace)
606
    put(custom, tmpl)
607
    try_run("snf-manage service-import --json %s" % tmpl)
608

    
609
@roles("accounts")
610
def get_service_details(service="pithos"):
611
    debug(env.host, " * Getting registered details for %s service..." % service)
612
    result = try_run("snf-manage component-list")
613
    r = re.compile(r".*%s.*" % service, re.M)
614
    service_id, _, _, service_token = r.search(result).group().split()
615
    # print("%s: %s %s" % (service, service_id, service_token))
616
    return (service_id, service_token)
617

    
618

    
619
@roles("db")
620
def get_auth_token_from_db(user_email=None):
621
    if not user_email:
622
        user_email=env.env.user_email
623
    debug(env.host, " * Getting authentication token and uuid for user %s..." % user_email)
624
    cmd = """
625
    echo "select id, auth_token, uuid, email from auth_user, im_astakosuser where auth_user.id = im_astakosuser.user_ptr_id and auth_user.email = '{0}';" > /tmp/psqlcmd
626
    su - postgres -c  "psql -w -d snf_apps -f /tmp/psqlcmd"
627
    """.format(user_email)
628

    
629
    result = try_run(cmd)
630
    r = re.compile(r"(\d+)[ |]*(\S+)[ |]*(\S+)[ |]*" + user_email, re.M)
631
    match = r.search(result)
632
    uid, user_auth_token, user_uuid = match.groups()
633
    # print("%s: %s %s %s" % ( user_email, uid, user_auth_token, user_uuid))
634

    
635
    return (uid, user_auth_token, user_uuid)
636

    
637

    
638
@roles("cms")
639
def cms_loaddata():
640
    debug(env.host, " * Loading cms initial data...")
641
    if env.cms_pass:
642
      debug(env.host, "Aborting. Prerequisites not met.")
643
      return
644
    tmpl = "/tmp/sites.json"
645
    replace = {}
646
    custom = customize_settings_from_tmpl(tmpl, replace)
647
    put(custom, tmpl)
648

    
649
    tmpl = "/tmp/page.json"
650
    replace = {}
651
    custom = customize_settings_from_tmpl(tmpl, replace)
652
    put(custom, tmpl)
653

    
654
    cmd = """
655
    snf-manage loaddata /tmp/sites.json
656
    snf-manage loaddata /tmp/page.json
657
    snf-manage createsuperuser --username=admin --email=admin@{0} --noinput
658
    """.format(env.env.domain)
659
    try_run(cmd)
660

    
661

    
662
@roles("cms")
663
def setup_cms():
664
    debug(env.host, "Setting up cms...")
665
    if env.cms_pass:
666
      debug(env.host, "Aborting. Prerequisites not met.")
667
      return
668
    with settings(hide("everything")):
669
        try_run("ping -c1 accounts." + env.env.domain)
670
    setup_gunicorn()
671
    setup_apache()
672
    setup_webproject()
673
    install_package("snf-cloudcms")
674

    
675
    tmpl = "/etc/synnefo/cms.conf"
676
    replace = {
677
        "ACCOUNTS": env.env.accounts.fqdn,
678
        }
679
    custom = customize_settings_from_tmpl(tmpl, replace)
680
    put(custom, tmpl, mode=0644)
681
    try_run("/etc/init.d/gunicorn restart")
682

    
683

    
684
    cmd = """
685
    snf-manage syncdb
686
    snf-manage migrate --delete-ghost-migrations
687
    """.format(env.env.domain)
688
    try_run(cmd)
689

    
690

    
691
def setup_nfs_dirs():
692
    debug(env.host, " * Creating NFS mount point for pithos and ganeti...")
693
    cmd = """
694
    mkdir -p {0}
695
    cd {0}
696
    mkdir -p data
697
    chown www-data:www-data data
698
    chmod g+ws data
699
    mkdir -p /srv/okeanos
700
    """.format(env.env.pithos_dir)
701
    try_run(cmd)
702

    
703

    
704
@roles("nodes")
705
def setup_nfs_clients():
706
    if env.host == env.env.pithos.ip:
707
      return
708

    
709
    debug(env.host, " * Mounting pithos NFS mount point...")
710
    with settings(hide("everything")):
711
        try_run("ping -c1 " + env.env.pithos.hostname)
712
    install_package("nfs-common")
713
    for d in [env.env.pithos_dir, "/srv/okeanos"]:
714
      try_run("mkdir -p " + d)
715
      cmd = """
716
      echo "{0}:/{1} {2}  nfs4 defaults,rw,noatime,nodiratime,intr,rsize=1048576,wsize=1048576,noacl" >> /etc/fstab
717
      """.format(env.env.pithos.hostname, os.path.basename(d), d)
718
      try_run(cmd)
719
      try_run("mount " + d)
720

    
721

    
722
@roles("pithos")
723
def setup_nfs_server():
724
    debug(env.host, " * Setting up NFS server for pithos...")
725
    setup_nfs_dirs()
726
    install_package("nfs-kernel-server")
727
    tmpl = "/etc/exports"
728
    replace = {
729
      "pithos_dir": env.env.pithos_dir,
730
      "srv": os.path.dirname(env.env.pithos_dir),
731
      "subnet": env.env.subnet
732
      }
733
    custom = customize_settings_from_tmpl(tmpl, replace)
734
    put(custom, tmpl)
735
    try_run("/etc/init.d/nfs-kernel-server restart")
736

    
737

    
738
@roles("pithos")
739
def setup_pithos():
740
    debug(env.host, "Setting up snf-pithos-app...")
741
    with settings(hide("everything")):
742
        try_run("ping -c1 accounts." + env.env.domain)
743
        try_run("ping -c1 " + env.env.db.ip)
744
    setup_gunicorn()
745
    setup_apache()
746
    setup_webproject()
747

    
748
    with settings(host_string=env.env.accounts.ip):
749
        service_id, service_token = get_service_details("pithos")
750

    
751
    install_package("kamaki")
752
    install_package("snf-pithos-backend")
753
    install_package("snf-pithos-app")
754
    tmpl = "/etc/synnefo/pithos.conf"
755
    replace = {
756
        "ACCOUNTS": env.env.accounts.fqdn,
757
        "PITHOS": env.env.pithos.fqdn,
758
        "db_node": env.env.db.ip,
759
        "synnefo_user": env.env.synnefo_user,
760
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
761
        "pithos_dir": env.env.pithos_dir,
762
        "PITHOS_SERVICE_TOKEN": service_token,
763
        "proxy": env.env.pithos.hostname == env.env.accounts.hostname
764
        }
765
    custom = customize_settings_from_tmpl(tmpl, replace)
766
    put(custom, tmpl, mode=0644)
767
    try_run("/etc/init.d/gunicorn restart")
768

    
769
    install_package("snf-pithos-webclient")
770
    tmpl = "/etc/synnefo/webclient.conf"
771
    replace = {
772
        "ACCOUNTS": env.env.accounts.fqdn,
773
        "PITHOS_UI_CLOUDBAR_ACTIVE_SERVICE": service_id,
774
        }
775
    custom = customize_settings_from_tmpl(tmpl, replace)
776
    put(custom, tmpl, mode=0644)
777

    
778
    try_run("/etc/init.d/gunicorn restart")
779
    #TOFIX: the previous command lets pithos-backend create blocks and maps
780
    #       with root owner
781
    try_run("chown -R www-data:www-data %s/data " % env.env.pithos_dir)
782
    #try_run("pithos-migrate stamp 4c8ccdc58192")
783
    #try_run("pithos-migrate upgrade head")
784

    
785

    
786
def add_wheezy():
787
    tmpl = "/etc/apt/sources.list.d/wheezy.list"
788
    replace = {}
789
    custom = customize_settings_from_tmpl(tmpl, replace)
790
    put(custom, tmpl)
791
    apt_get_update()
792

    
793

    
794
def remove_wheezy():
795
    try_run("rm -f /etc/apt/sources.list.d/wheezy.list")
796
    apt_get_update()
797

    
798

    
799
@roles("ganeti")
800
def setup_ganeti():
801
    debug(env.host, "Setting up snf-ganeti...")
802
    node_info = env.env.ips_info[env.host]
803
    with settings(hide("everything")):
804
        #if env.enable_lvm:
805
        #    try_run("vgs " + env.env.vg)
806
        try_run("getent hosts " + env.env.cluster.fqdn)
807
        try_run("getent hosts %s | grep -v ^127" % env.host)
808
        try_run("hostname -f | grep " + node_info.fqdn)
809
        #try_run("ip link show " + env.env.common_bridge)
810
        #try_run("ip link show " + env.env.common_bridge)
811
        #try_run("apt-get update")
812
    install_package("qemu-kvm")
813
    install_package("python-bitarray")
814
    add_wheezy()
815
    install_package("ganeti-htools")
816
    remove_wheezy()
817
    install_package("snf-ganeti")
818
    try_run("mkdir -p /srv/ganeti/file-storage/")
819
    cmd = """
820
cat <<EOF > /etc/ganeti/file-storage-paths
821
/srv/ganeti/file-storage
822
/srv/ganeti/shared-file-storage
823
EOF
824
"""
825
    try_run(cmd)
826

    
827

    
828
@roles("master")
829
def add_rapi_user():
830
    debug(env.host, " * Adding RAPI user to Ganeti backend...")
831
    cmd = """
832
    echo -n "{0}:Ganeti Remote API:{1}" | openssl md5
833
    """.format(env.env.synnefo_user, env.env.synnefo_rapi_passwd)
834
    result = try_run(cmd)
835
    cmd = """
836
    echo "{0} {1}{2} write" >> /var/lib/ganeti/rapi/users
837
    """.format(env.env.synnefo_user, '{ha1}',result)
838
    try_run(cmd)
839
    try_run("/etc/init.d/ganeti restart")
840

    
841
@roles("master")
842
def add_nodes():
843
    nodes = env.env.cluster_nodes.split(",")
844
    nodes.remove(env.env.master_node)
845
    debug(env.host, " * Adding nodes to Ganeti backend...")
846
    for n in nodes:
847
        add_node(n)
848

    
849
@roles("master")
850
def add_node(node):
851
    node_info = env.env.nodes_info[node]
852
    debug(env.host, " * Adding node %s to Ganeti backend..." % node_info.fqdn)
853
    cmd = "gnt-node add --no-ssh-key-check --master-capable=yes --vm-capable=yes " + node_info.fqdn
854
    try_run(cmd)
855

    
856
@roles("ganeti")
857
def enable_drbd():
858
    if env.enable_drbd:
859
        debug(env.host, " * Enabling DRBD...")
860
        try_run("modprobe drbd minor_count=255 usermode_helper=/bin/true")
861
        try_run("echo drbd minor_count=255 usermode_helper=/bin/true >> /etc/modules")
862

    
863
@roles("master")
864
def setup_drbd_dparams():
865
    if env.enable_drbd:
866
        debug(env.host, " * Twicking drbd related disk parameters in Ganeti...")
867
        cmd = """
868
        gnt-cluster modify --disk-parameters=drbd:metavg={0}
869
        gnt-group modify --disk-parameters=drbd:metavg={0} default
870
        """.format(env.env.vg)
871
        try_run(cmd)
872

    
873
@roles("master")
874
def enable_lvm():
875
    if env.enable_lvm:
876
        debug(env.host, " * Enabling LVM...")
877
        cmd = """
878
        gnt-cluster modify --vg-name={0}
879
        """.format(env.env.vg)
880
        try_run(cmd)
881
    else:
882
        debug(env.host, " * Disabling LVM...")
883
        try_run("gnt-cluster modify --no-lvm-storage")
884

    
885
@roles("master")
886
def destroy_cluster():
887
    debug(env.host, " * Destroying Ganeti cluster...")
888
    #TODO: remove instances first
889
    allnodes = env.env.cluster_hostnames[:]
890
    allnodes.remove(env.host)
891
    for n in allnodes:
892
      host_info = env.env.ips_info[host]
893
      debug(env.host, " * Removing node %s..." % n)
894
      cmd = "gnt-node remove  " + host_info.fqdn
895
      try_run(cmd)
896
    try_run("gnt-cluster destroy --yes-do-it")
897

    
898

    
899
@roles("master")
900
def init_cluster():
901
    debug(env.host, " * Initializing Ganeti backend...")
902
    # extra = ""
903
    # if env.enable_lvm:
904
    #     extra += " --vg-name={0} ".format(env.env.vg)
905
    # else:
906
    #     extra += " --no-lvm-storage "
907
    # if not env.enable_drbd:
908
    #     extra += " --no-drbd-storage "
909
    extra = " --no-lvm-storage --no-drbd-storage "
910
    cmd = """
911
    gnt-cluster init --enabled-hypervisors=kvm \
912
                     {0} \
913
                     --nic-parameters link={1},mode=bridged \
914
                     --master-netdev {2} \
915
                     --default-iallocator hail \
916
                     --hypervisor-parameters kvm:kernel_path=,vnc_bind_address=0.0.0.0 \
917
                     --no-ssh-init --no-etc-hosts \
918
                    {3}
919

920
    """.format(extra, env.env.common_bridge,
921
               env.env.cluster_netdev, env.env.cluster.fqdn)
922
    try_run(cmd)
923

    
924

    
925
@roles("ganeti")
926
def debootstrap():
927
    install_package("ganeti-instance-debootstrap")
928

    
929

    
930
@roles("ganeti")
931
def setup_image_host():
932
    debug(env.host, "Setting up snf-image...")
933
    install_package("snf-pithos-backend")
934
    install_package("snf-image")
935
    try_run("mkdir -p /srv/okeanos")
936
    tmpl = "/etc/default/snf-image"
937
    replace = {
938
        "synnefo_user": env.env.synnefo_user,
939
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
940
        "pithos_dir": env.env.pithos_dir,
941
        "db_node": env.env.db.ip,
942
    }
943
    custom = customize_settings_from_tmpl(tmpl, replace)
944
    put(custom, tmpl)
945

    
946

    
947
@roles("ganeti")
948
def setup_image_helper():
949
    debug(env.host, " * Updating helper image...")
950
    cmd = """
951
    snf-image-update-helper -y
952
    """
953
    try_run(cmd)
954

    
955

    
956
@roles("ganeti")
957
def setup_gtools():
958
    debug(env.host, " * Setting up snf-cyclades-gtools...")
959
    with settings(hide("everything")):
960
        try_run("ping -c1 " + env.env.mq.ip)
961
    setup_common()
962
    install_package("snf-cyclades-gtools")
963
    tmpl = "/etc/synnefo/gtools.conf"
964
    replace = {
965
        "synnefo_user": env.env.synnefo_user,
966
        "synnefo_rabbitmq_passwd": env.env.synnefo_rabbitmq_passwd,
967
        "mq_node": env.env.mq.ip,
968
    }
969
    custom = customize_settings_from_tmpl(tmpl, replace)
970
    put(custom, tmpl)
971

    
972
    cmd = """
973
    sed -i 's/false/true/' /etc/default/snf-ganeti-eventd
974
    /etc/init.d/snf-ganeti-eventd start
975
    """
976
    try_run(cmd)
977

    
978

    
979
@roles("ganeti")
980
def setup_iptables():
981
    debug(env.host, " * Setting up iptables to mangle DHCP requests...")
982
    cmd = """
983
    iptables -t mangle -A PREROUTING -i br+ -p udp -m udp --dport 67 -j NFQUEUE --queue-num 42
984
    iptables -t mangle -A PREROUTING -i tap+ -p udp -m udp --dport 67 -j NFQUEUE --queue-num 42
985
    iptables -t mangle -A PREROUTING -i prv+ -p udp -m udp --dport 67 -j NFQUEUE --queue-num 42
986

987
    ip6tables -t mangle -A PREROUTING -i br+ -p ipv6-icmp -m icmp6 --icmpv6-type 133 -j NFQUEUE --queue-num 43
988
    ip6tables -t mangle -A PREROUTING -i br+ -p ipv6-icmp -m icmp6 --icmpv6-type 135 -j NFQUEUE --queue-num 44
989
    """
990
    try_run(cmd)
991

    
992
@roles("ganeti")
993
def setup_network():
994
    debug(env.host, "Setting up networking for Ganeti instances (nfdhcpd, etc.)...")
995
    install_package("nfqueue-bindings-python")
996
    install_package("nfdhcpd")
997
    tmpl = "/etc/nfdhcpd/nfdhcpd.conf"
998
    replace = {
999
      "ns_node_ip": env.env.ns.ip
1000
      }
1001
    custom = customize_settings_from_tmpl(tmpl, replace)
1002
    put(custom, tmpl)
1003
    try_run("/etc/init.d/nfdhcpd restart")
1004

    
1005
    install_package("snf-network")
1006
    cmd = """
1007
    sed -i 's/MAC_MASK.*/MAC_MASK = ff:ff:f0:00:00:00/' /etc/default/snf-network
1008
    """
1009
    try_run(cmd)
1010

    
1011

    
1012
@roles("router")
1013
def setup_router():
1014
    debug(env.host, " * Setting up internal router for NAT...")
1015
    cmd = """
1016
    echo 1 > /proc/sys/net/ipv4/ip_forward
1017
    iptables -t nat -A POSTROUTING -s {0} -o {3} -j MASQUERADE
1018
    ip addr add {1} dev {2}
1019
    ip route add {0} dev {2} src {1}
1020
    """.format(env.env.synnefo_public_network_subnet,
1021
               env.env.synnefo_public_network_gateway,
1022
               env.env.common_bridge, env.env.public_iface)
1023
    try_run(cmd)
1024

    
1025
@roles("cyclades")
1026
def cyclades_loaddata():
1027
    debug(env.host, " * Loading initial data for cyclades...")
1028
    tmpl = "/tmp/flavor.json"
1029
    replace = {}
1030
    custom = customize_settings_from_tmpl(tmpl, replace)
1031
    put(custom, tmpl)
1032
    try_run("snf-manage loaddata " + tmpl)
1033
    #run("snf-manage loaddata flavors")
1034

    
1035

    
1036
@roles("cyclades")
1037
def setup_cyclades():
1038
    debug(env.host, "Setting up snf-cyclades-app...")
1039
    with settings(hide("everything")):
1040
        try_run("ping -c1 accounts." + env.env.domain)
1041
        try_run("ping -c1 " + env.env.db.ip)
1042
        try_run("ping -c1 " + env.env.mq.ip)
1043
    setup_gunicorn()
1044
    setup_apache()
1045
    setup_webproject()
1046
    install_package("memcached")
1047
    install_package("python-memcache")
1048
    install_package("snf-pithos-backend")
1049
    install_package("kamaki")
1050
    install_package("snf-cyclades-app")
1051
    install_package("python-django-south")
1052
    tmpl = "/etc/synnefo/cyclades.conf"
1053

    
1054
    with settings(host_string=env.env.accounts.ip):
1055
        service_id, service_token = get_service_details("cyclades")
1056

    
1057
    replace = {
1058
        "ACCOUNTS": env.env.accounts.fqdn,
1059
        "CYCLADES": env.env.cyclades.fqdn,
1060
        "mq_node": env.env.mq.ip,
1061
        "db_node": env.env.db.ip,
1062
        "synnefo_user": env.env.synnefo_user,
1063
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
1064
        "synnefo_rabbitmq_passwd": env.env.synnefo_rabbitmq_passwd,
1065
        "pithos_dir": env.env.pithos_dir,
1066
        "common_bridge": env.env.common_bridge,
1067
        "HOST": env.env.cyclades.ip,
1068
        "domain": env.env.domain,
1069
        "CYCLADES_SERVICE_TOKEN": service_token,
1070
        "proxy": env.env.cyclades.hostname == env.env.accounts.hostname
1071
        }
1072
    custom = customize_settings_from_tmpl(tmpl, replace)
1073
    put(custom, tmpl, mode=0644)
1074
    try_run("/etc/init.d/gunicorn restart")
1075

    
1076
    cmd = """
1077
    sed -i 's/false/true/' /etc/default/snf-dispatcher
1078
    /etc/init.d/snf-dispatcher start
1079
    """
1080
    try_run(cmd)
1081

    
1082
    try_run("snf-manage syncdb")
1083
    try_run("snf-manage migrate --delete-ghost-migrations")
1084

    
1085

    
1086
@roles("cyclades")
1087
def get_backend_id(cluster_name="ganeti1.synnefo.deploy.local"):
1088
    backend_id = try_run("snf-manage backend-list 2>/dev/null | grep %s | awk '{print $1}'" % cluster_name)
1089
    return backend_id
1090

    
1091

    
1092
@roles("cyclades")
1093
def add_backend():
1094
    debug(env.host, "adding %s ganeti backend to cyclades..." % env.env.cluster.fqdn)
1095
    with settings(hide("everything")):
1096
        try_run("ping -c1 " + env.env.cluster.fqdn)
1097
    cmd = """
1098
    snf-manage backend-add --clustername={0} --user={1} --pass={2}
1099
    """.format(env.env.cluster.fqdn, env.env.synnefo_user,
1100
               env.env.synnefo_rapi_passwd)
1101
    try_run(cmd)
1102
    backend_id = get_backend_id(env.env.cluster.fqdn)
1103
    try_run("snf-manage backend-modify --drained=False " + backend_id)
1104

    
1105
@roles("cyclades")
1106
def pin_user_to_backend(user_email):
1107
    backend_id = get_backend_id(env.env.cluster.fqdn)
1108
    # pin user to backend
1109
    cmd = """
1110
cat <<EOF >> /etc/synnefo/cyclades.conf
1111

1112
BACKEND_PER_USER = {
1113
  '%s': %s,
1114
}
1115

1116
EOF
1117
/etc/init.d/gunicorn restart
1118
    """  % (user_email, backend_id)
1119
    try_run(cmd)
1120

    
1121
@roles("cyclades")
1122
def add_pools():
1123
    debug(env.host, " * Creating pools of resources (brigdes, mac prefixes) in cyclades...")
1124
    try_run("snf-manage pool-create --type=mac-prefix --base=aa:00:0 --size=65536")
1125
    try_run("snf-manage pool-create --type=bridge --base=prv --size=20")
1126

    
1127

    
1128
@roles("cyclades")
1129
def add_network():
1130
    debug(env.host, " * Adding public network in cyclades...")
1131
    backend_id = get_backend_id(env.env.cluster.fqdn)
1132
    cmd = """
1133
    snf-manage network-create --subnet={0} --gateway={1} --public --dhcp --flavor={2} --mode=bridged --link={3} --name=Internet --backend-id={4}
1134
    """.format(env.env.synnefo_public_network_subnet,
1135
               env.env.synnefo_public_network_gateway,
1136
               env.env.synnefo_public_network_type,
1137
               env.env.common_bridge, backend_id)
1138
    try_run(cmd)
1139

    
1140

    
1141
@roles("cyclades")
1142
def setup_vncauthproxy():
1143
    debug(env.host, " * Setting up vncauthproxy...")
1144
    install_package("snf-vncauthproxy")
1145
    cmd = """
1146
    echo CHUID="www-data:nogroup" >> /etc/default/vncauthproxy
1147
    rm /var/log/vncauthproxy/vncauthproxy.log
1148
    """
1149
    try_run(cmd)
1150
    try_run("/etc/init.d/vncauthproxy restart")
1151

    
1152
@roles("client")
1153
def setup_kamaki():
1154
    debug(env.host, "Setting up kamaki client...")
1155
    with settings(hide("everything")):
1156
        try_run("ping -c1 accounts." + env.env.domain)
1157
        try_run("ping -c1 cyclades." + env.env.domain)
1158
        try_run("ping -c1 pithos." + env.env.domain)
1159

    
1160
    with settings(host_string=env.env.db.ip):
1161
        uid, user_auth_token, user_uuid = get_auth_token_from_db(env.env.user_email)
1162

    
1163
    install_package("python-progress")
1164
    install_package("kamaki")
1165
    cmd = """
1166
    kamaki config set cloud.default.url "https://{0}/astakos/identity/v2.0/"
1167
    kamaki config set cloud.default.token {1}
1168
    """.format(env.env.accounts.fqdn, user_auth_token)
1169
    try_run(cmd)
1170
    try_run("kamaki file create images")
1171

    
1172
@roles("client")
1173
def upload_image(image="debian_base.diskdump"):
1174
    debug(env.host, " * Uploading initial image to pithos...")
1175
    image = "debian_base.diskdump"
1176
    try_run("wget {0} -O /tmp/{1}".format(env.env.debian_base_url, image))
1177
    try_run("kamaki file upload --container images /tmp/{0} {0}".format(image))
1178

    
1179
@roles("client")
1180
def register_image(image="debian_base.diskdump"):
1181
    debug(env.host, " * Register image to plankton...")
1182
    with settings(host_string=env.env.db.ip):
1183
        uid, user_auth_token, user_uuid = get_auth_token_from_db(env.env.user_email)
1184

    
1185
    pithos_url = "pithos://{0}/images/{1}".format(user_uuid, image)
1186
    cmd = """
1187
    sleep 5
1188
    kamaki image register "Debian Base" {0} --public --disk-format=diskdump --property OSFAMILY=linux --property ROOT_PARTITION=1 --property description="Debian Squeeze Base System" --property size=450M --property kernel=2.6.32 --property GUI="No GUI" --property sortorder=1 --property USERS=root --property OS=debian
1189
    """.format(pithos_url)
1190
    try_run(cmd)
1191

    
1192
@roles("client")
1193
def setup_burnin():
1194
    debug(env.host, "Setting up burnin testing tool...")
1195
    install_package("kamaki")
1196
    install_package("snf-tools")
1197

    
1198
@roles("pithos")
1199
def add_image_locally():
1200
    debug(env.host, " * Getting image locally in order snf-image to use it directly..")
1201
    image = "debian_base.diskdump"
1202
    try_run("wget {0} -O /srv/okeanos/{1}".format(env.env.debian_base_url, image))
1203

    
1204

    
1205
@roles("master")
1206
def gnt_instance_add(name="test"):
1207
    debug(env.host, " * Adding test instance to Ganeti...")
1208
    osp="""img_passwd=gamwtosecurity,img_format=diskdump,img_id=debian_base,img_properties='{"OSFAMILY":"linux"\,"ROOT_PARTITION":"1"}'"""
1209
    cmd = """
1210
    gnt-instance add  -o snf-image+default --os-parameters {0} -t plain --disk 0:size=1G --no-name-check --no-ip-check --net 0:ip=pool,network=test --no-install --hypervisor-parameters kvm:machine_version=pc-1.0 {1}
1211
    """.format(osp, name)
1212
    try_run(cmd)
1213

    
1214
@roles("master")
1215
def gnt_network_add(name="test", subnet="10.0.0.0/26", gw="10.0.0.1", mode="bridged", link="br0"):
1216
    debug(env.host, " * Adding test network to Ganeti...")
1217
    cmd = """
1218
    gnt-network add --network={1} --gateway={2} {0}
1219
    gnt-network connect {0} {3} {4}
1220
    """.format(name, subnet, gw, mode, link)
1221
    try_run(cmd)
1222

    
1223
@roles("ips")
1224
def test():
1225
    debug(env.host, "Testing...")
1226
    try_run("hostname && date")