Statistics
| Branch: | Tag: | Revision:

root / snf-deploy / fabfile.py @ 8780d2fa

History | View | Annotate | Download (37.7 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, key_inject=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
    env.key_inject = ast.literal_eval(key_inject)
27
    conf = Conf.configure(confdir=confdir, cluster_name=cluster_name, autoconf=autoconf)
28
    env.env = Env(conf)
29

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

    
35
    if disable_colors:
36
        disable_color()
37

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

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

    
48

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

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

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

    
74

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

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

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

    
97
    try_run(APT_GET)
98

    
99
    return
100

    
101

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

    
109

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

    
117

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

    
126

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

    
135

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

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

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

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

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

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

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

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

    
199

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

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

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

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

    
220

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

    
227

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

    
250
    cmd = """
251
if [ -e /root/.ssh/authorized_keys.bak ]; then
252
  cat /root/.ssh/authorized_keys.bak >> /root/.ssh/authorized_keys
253
fi
254
    """
255
    debug(env.host, "Updating exising authorized keys..")
256
    try_run(cmd)
257

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

    
276

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

    
284

    
285
def try_run(cmd, abort=False):
286
    try:
287
      if env.local:
288
        return local(cmd, capture=True)
289
      else:
290
        return run(cmd)
291
    except:
292
      debug(env.host, "WARNING: command failed. Continuing anyway...")
293
      if abort:
294
        raise
295

    
296
def create_bridges():
297
    debug(env.host, " * Creating bridges...")
298
    install_package("bridge-utils")
299
    cmd = """
300
    brctl addbr {0} ; ip link set {0} up
301
    """.format(env.env.common_bridge)
302
    try_run(cmd)
303

    
304

    
305
def connect_bridges():
306
    debug(env.host, " * Connecting bridges...")
307
    cmd = """
308
    brctl addif {0} {1}
309
    """.format(env.env.common_bridge, env.env.public_iface)
310
    #try_run(cmd)
311

    
312

    
313
@roles("ganeti")
314
def setup_net_infra():
315
    debug(env.host, "Setup networking infrastracture..")
316
    create_bridges()
317
    connect_bridges()
318

    
319

    
320
@roles("ganeti")
321
def setup_lvm():
322
    debug(env.host, "create volume group %s for ganeti.." % env.env.vg)
323
    if env.enable_lvm:
324
        install_package("lvm2")
325
        cmd = """
326
        pvcreate {0}
327
        vgcreate {1} {0}
328
        """.format(env.env.extra_disk, env.env.vg)
329
        try_run(cmd)
330

    
331

    
332
def customize_settings_from_tmpl(tmpl, replace):
333
    debug(env.host, " * Customizing template %s..." % tmpl)
334
    local = env.env.templates + tmpl
335
    _, custom = tempfile.mkstemp()
336
    shutil.copyfile(local, custom)
337
    for k, v in replace.iteritems():
338
        regex = "re.sub('%{0}%', '{1}', line)".format(k.upper(), v)
339
        massedit.edit_files([custom], [regex], dry_run=False)
340

    
341
    return custom
342

    
343

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

    
359

    
360
@roles("cyclades", "cms", "pithos", "accounts")
361
def restart_services():
362
    debug(env.host, " * Restarting apache2 and gunicorn...")
363
    try_run("/etc/init.d/gunicorn restart")
364
    try_run("/etc/init.d/apache2 restart")
365

    
366

    
367
def setup_gunicorn():
368
    debug(env.host, " * Setting up gunicorn...")
369
    install_package("gunicorn")
370
    tmpl = "/etc/gunicorn.d/synnefo"
371
    replace = {}
372
    custom = customize_settings_from_tmpl(tmpl, replace)
373
    put(custom, tmpl, mode=0644)
374
    try_run("/etc/init.d/gunicorn restart")
375

    
376

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

    
403

    
404
@roles("mq")
405
def setup_mq():
406
    debug(env.host, "Setting up RabbitMQ...")
407
    install_package("rabbitmq-server")
408
    cmd = """
409
    rabbitmqctl add_user {0} {1}
410
    rabbitmqctl set_permissions {0} ".*" ".*" ".*"
411
    rabbitmqctl delete_user guest
412
    rabbitmqctl set_user_tags {0} administrator
413
    """.format(env.env.synnefo_user, env.env.synnefo_rabbitmq_passwd)
414
    try_run(cmd)
415
    try_run("/etc/init.d/rabbitmq-server restart")
416

    
417

    
418
@roles("db")
419
def allow_access_in_db(ip, user="all", trust=""):
420
    cmd = """
421
    echo host all {0} {1}/32 md5 {2} >> /etc/postgresql/8.4/main/pg_hba.conf
422
    """.format(user, ip, trust)
423
    try_run(cmd)
424
    try_run("/etc/init.d/postgresql restart")
425

    
426
@roles("db")
427
def setup_db():
428
    debug(env.host, "Setting up DataBase server...")
429
    install_package("postgresql")
430

    
431
    tmpl = "/tmp/db-init.psql"
432
    replace = {
433
        "synnefo_user": env.env.synnefo_user,
434
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
435
        }
436
    custom = customize_settings_from_tmpl(tmpl, replace)
437
    put(custom, tmpl)
438
    cmd = 'su - postgres -c "psql -w -f %s" ' % tmpl
439
    try_run(cmd)
440
    cmd = """
441
    echo "listen_addresses = '*'" >> /etc/postgresql/8.4/main/postgresql.conf
442
    """
443
    try_run(cmd)
444

    
445
    try_run("/etc/init.d/postgresql restart")
446
    allow_access_in_db("127.0.0.1", "postgres", "trust")
447

    
448

    
449
@roles("db")
450
def destroy_db():
451
    try_run("""su - postgres -c ' psql -w -c "drop database snf_apps" '""")
452
    try_run("""su - postgres -c ' psql -w -c "drop database snf_pithos" '""")
453

    
454

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

    
477

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

    
497
@roles("accounts")
498
def astakos_loaddata():
499
    debug(env.host, " * Loading initial data to astakos...")
500
    cmd = """
501
    snf-manage loaddata groups
502
    """
503
    try_run(cmd)
504

    
505

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

    
535

    
536
@roles("accounts")
537
def add_user():
538
    debug(env.host, " * adding user %s to astakos..." % env.env.user_email)
539
    email=env.env.user_email
540
    name=env.env.user_name
541
    lastname=env.env.user_lastname
542
    passwd=env.env.user_passwd
543
    cmd = """
544
    snf-manage user-add {0} {1} {2}
545
    """.format(email, name, lastname)
546
    try_run(cmd)
547
    with settings(host_string=env.env.db.ip):
548
        uid, user_auth_token, user_uuid = get_auth_token_from_db(email)
549
    cmd = """
550
    snf-manage user-modify --password {0} {1}
551
    """.format(passwd, uid)
552
    try_run(cmd)
553

    
554

    
555
@roles("accounts")
556
def activate_user(user_email=None):
557
    if not user_email:
558
      user_email = env.env.user_email
559
    debug(env.host, " * Activate user %s..." % user_email)
560
    with settings(host_string=env.env.db.ip):
561
        uid, user_auth_token, user_uuid = get_auth_token_from_db(user_email)
562

    
563
    cmd = """
564
    snf-manage user-modify --verify {0}
565
    snf-manage user-modify --accept {0}
566
    """.format(uid)
567
    try_run(cmd)
568

    
569
@roles("accounts")
570
def setup_astakos():
571
    debug(env.host, "Setting up snf-astakos-app...")
572
    setup_gunicorn()
573
    setup_apache()
574
    setup_webproject()
575
    install_package("python-django-south")
576
    install_package("snf-astakos-app")
577
    install_package("kamaki")
578

    
579
    tmpl = "/etc/synnefo/astakos.conf"
580
    replace = {
581
      "ACCOUNTS": env.env.accounts.fqdn,
582
      "domain": env.env.domain,
583
      "CYCLADES": env.env.cyclades.fqdn,
584
      "PITHOS": env.env.pithos.fqdn,
585
    }
586
    custom = customize_settings_from_tmpl(tmpl, replace)
587
    put(custom, tmpl, mode=0644)
588
    if env.csrf_disable:
589
      cmd = """
590
cat <<EOF >> /etc/synnefo/astakos.conf
591
try:
592
  MIDDLEWARE_CLASSES.remove('django.middleware.csrf.CsrfViewMiddleware')
593
except:
594
  pass
595
EOF
596
"""
597
      try_run(cmd)
598

    
599
    try_run("/etc/init.d/gunicorn restart")
600

    
601
    cmd = """
602
    snf-manage syncdb --noinput
603
    snf-manage migrate im --delete-ghost-migrations
604
    snf-manage migrate quotaholder_app
605
    """
606
    try_run(cmd)
607

    
608
def import_service(service):
609
    tmpl = "/tmp/%s.json" % service
610
    replace = {
611
      "DOMAIN": env.env.domain,
612
      }
613
    custom = customize_settings_from_tmpl(tmpl, replace)
614
    put(custom, tmpl)
615
    try_run("snf-manage service-import --json %s" % tmpl)
616

    
617
@roles("accounts")
618
def get_service_details(service="pithos"):
619
    debug(env.host, " * Getting registered details for %s service..." % service)
620
    result = try_run("snf-manage component-list")
621
    r = re.compile(r".*%s.*" % service, re.M)
622
    service_id, _, _, service_token = r.search(result).group().split()
623
    # print("%s: %s %s" % (service, service_id, service_token))
624
    return (service_id, service_token)
625

    
626

    
627
@roles("db")
628
def get_auth_token_from_db(user_email=None):
629
    if not user_email:
630
        user_email=env.env.user_email
631
    debug(env.host, " * Getting authentication token and uuid for user %s..." % user_email)
632
    cmd = """
633
    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
634
    su - postgres -c  "psql -w -d snf_apps -f /tmp/psqlcmd"
635
    """.format(user_email)
636

    
637
    result = try_run(cmd)
638
    r = re.compile(r"(\d+)[ |]*(\S+)[ |]*(\S+)[ |]*" + user_email, re.M)
639
    match = r.search(result)
640
    uid, user_auth_token, user_uuid = match.groups()
641
    # print("%s: %s %s %s" % ( user_email, uid, user_auth_token, user_uuid))
642

    
643
    return (uid, user_auth_token, user_uuid)
644

    
645

    
646
@roles("cms")
647
def cms_loaddata():
648
    debug(env.host, " * Loading cms initial data...")
649
    if env.cms_pass:
650
      debug(env.host, "Aborting. Prerequisites not met.")
651
      return
652
    tmpl = "/tmp/sites.json"
653
    replace = {}
654
    custom = customize_settings_from_tmpl(tmpl, replace)
655
    put(custom, tmpl)
656

    
657
    tmpl = "/tmp/page.json"
658
    replace = {}
659
    custom = customize_settings_from_tmpl(tmpl, replace)
660
    put(custom, tmpl)
661

    
662
    cmd = """
663
    snf-manage loaddata /tmp/sites.json
664
    snf-manage loaddata /tmp/page.json
665
    snf-manage createsuperuser --username=admin --email=admin@{0} --noinput
666
    """.format(env.env.domain)
667
    try_run(cmd)
668

    
669

    
670
@roles("cms")
671
def setup_cms():
672
    debug(env.host, "Setting up cms...")
673
    if env.cms_pass:
674
      debug(env.host, "Aborting. Prerequisites not met.")
675
      return
676
    with settings(hide("everything")):
677
        try_run("ping -c1 accounts." + env.env.domain)
678
    setup_gunicorn()
679
    setup_apache()
680
    setup_webproject()
681
    install_package("snf-cloudcms")
682

    
683
    tmpl = "/etc/synnefo/cms.conf"
684
    replace = {
685
        "ACCOUNTS": env.env.accounts.fqdn,
686
        }
687
    custom = customize_settings_from_tmpl(tmpl, replace)
688
    put(custom, tmpl, mode=0644)
689
    try_run("/etc/init.d/gunicorn restart")
690

    
691

    
692
    cmd = """
693
    snf-manage syncdb
694
    snf-manage migrate --delete-ghost-migrations
695
    """.format(env.env.domain)
696
    try_run(cmd)
697

    
698

    
699
def setup_nfs_dirs():
700
    debug(env.host, " * Creating NFS mount point for pithos and ganeti...")
701
    cmd = """
702
    mkdir -p {0}
703
    cd {0}
704
    mkdir -p data
705
    chown www-data:www-data data
706
    chmod g+ws data
707
    mkdir -p /srv/okeanos
708
    """.format(env.env.pithos_dir)
709
    try_run(cmd)
710

    
711

    
712
@roles("nodes")
713
def setup_nfs_clients():
714
    if env.host == env.env.pithos.ip:
715
      return
716

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

    
729

    
730
@roles("pithos")
731
def setup_nfs_server():
732
    debug(env.host, " * Setting up NFS server for pithos...")
733
    setup_nfs_dirs()
734
    install_package("nfs-kernel-server")
735
    tmpl = "/etc/exports"
736
    replace = {
737
      "pithos_dir": env.env.pithos_dir,
738
      "srv": os.path.dirname(env.env.pithos_dir),
739
      "subnet": env.env.subnet
740
      }
741
    custom = customize_settings_from_tmpl(tmpl, replace)
742
    put(custom, tmpl)
743
    try_run("/etc/init.d/nfs-kernel-server restart")
744

    
745

    
746
@roles("pithos")
747
def setup_pithos():
748
    debug(env.host, "Setting up snf-pithos-app...")
749
    with settings(hide("everything")):
750
        try_run("ping -c1 accounts." + env.env.domain)
751
        try_run("ping -c1 " + env.env.db.ip)
752
    setup_gunicorn()
753
    setup_apache()
754
    setup_webproject()
755

    
756
    with settings(host_string=env.env.accounts.ip):
757
        service_id, service_token = get_service_details("pithos")
758

    
759
    install_package("kamaki")
760
    install_package("snf-pithos-backend")
761
    install_package("snf-pithos-app")
762
    tmpl = "/etc/synnefo/pithos.conf"
763
    replace = {
764
        "ACCOUNTS": env.env.accounts.fqdn,
765
        "PITHOS": env.env.pithos.fqdn,
766
        "db_node": env.env.db.ip,
767
        "synnefo_user": env.env.synnefo_user,
768
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
769
        "pithos_dir": env.env.pithos_dir,
770
        "PITHOS_SERVICE_TOKEN": service_token,
771
        "proxy": env.env.pithos.hostname == env.env.accounts.hostname
772
        }
773
    custom = customize_settings_from_tmpl(tmpl, replace)
774
    put(custom, tmpl, mode=0644)
775
    try_run("/etc/init.d/gunicorn restart")
776

    
777
    install_package("snf-pithos-webclient")
778
    tmpl = "/etc/synnefo/webclient.conf"
779
    replace = {
780
        "ACCOUNTS": env.env.accounts.fqdn,
781
        "PITHOS_UI_CLOUDBAR_ACTIVE_SERVICE": service_id,
782
        }
783
    custom = customize_settings_from_tmpl(tmpl, replace)
784
    put(custom, tmpl, mode=0644)
785

    
786
    try_run("/etc/init.d/gunicorn restart")
787
    #TOFIX: the previous command lets pithos-backend create blocks and maps
788
    #       with root owner
789
    try_run("chown -R www-data:www-data %s/data " % env.env.pithos_dir)
790
    #try_run("pithos-migrate stamp 4c8ccdc58192")
791
    #try_run("pithos-migrate upgrade head")
792

    
793

    
794
def add_wheezy():
795
    tmpl = "/etc/apt/sources.list.d/wheezy.list"
796
    replace = {}
797
    custom = customize_settings_from_tmpl(tmpl, replace)
798
    put(custom, tmpl)
799
    apt_get_update()
800

    
801

    
802
def remove_wheezy():
803
    try_run("rm -f /etc/apt/sources.list.d/wheezy.list")
804
    apt_get_update()
805

    
806

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

    
835

    
836
@roles("master")
837
def add_rapi_user():
838
    debug(env.host, " * Adding RAPI user to Ganeti backend...")
839
    cmd = """
840
    echo -n "{0}:Ganeti Remote API:{1}" | openssl md5
841
    """.format(env.env.synnefo_user, env.env.synnefo_rapi_passwd)
842
    result = try_run(cmd)
843
    cmd = """
844
    echo "{0} {1}{2} write" >> /var/lib/ganeti/rapi/users
845
    """.format(env.env.synnefo_user, '{ha1}',result)
846
    try_run(cmd)
847
    try_run("/etc/init.d/ganeti restart")
848

    
849
@roles("master")
850
def add_nodes():
851
    nodes = env.env.cluster_nodes.split(",")
852
    nodes.remove(env.env.master_node)
853
    debug(env.host, " * Adding nodes to Ganeti backend...")
854
    for n in nodes:
855
        add_node(n)
856

    
857
@roles("master")
858
def add_node(node):
859
    node_info = env.env.nodes_info[node]
860
    debug(env.host, " * Adding node %s to Ganeti backend..." % node_info.fqdn)
861
    cmd = "gnt-node add --no-ssh-key-check --master-capable=yes --vm-capable=yes " + node_info.fqdn
862
    try_run(cmd)
863

    
864
@roles("ganeti")
865
def enable_drbd():
866
    if env.enable_drbd:
867
        debug(env.host, " * Enabling DRBD...")
868
        try_run("modprobe drbd minor_count=255 usermode_helper=/bin/true")
869
        try_run("echo drbd minor_count=255 usermode_helper=/bin/true >> /etc/modules")
870

    
871
@roles("master")
872
def setup_drbd_dparams():
873
    if env.enable_drbd:
874
        debug(env.host, " * Twicking drbd related disk parameters in Ganeti...")
875
        cmd = """
876
        gnt-cluster modify --disk-parameters=drbd:metavg={0}
877
        gnt-group modify --disk-parameters=drbd:metavg={0} default
878
        """.format(env.env.vg)
879
        try_run(cmd)
880

    
881
@roles("master")
882
def enable_lvm():
883
    if env.enable_lvm:
884
        debug(env.host, " * Enabling LVM...")
885
        cmd = """
886
        gnt-cluster modify --vg-name={0}
887
        """.format(env.env.vg)
888
        try_run(cmd)
889
    else:
890
        debug(env.host, " * Disabling LVM...")
891
        try_run("gnt-cluster modify --no-lvm-storage")
892

    
893
@roles("master")
894
def destroy_cluster():
895
    debug(env.host, " * Destroying Ganeti cluster...")
896
    #TODO: remove instances first
897
    allnodes = env.env.cluster_hostnames[:]
898
    allnodes.remove(env.host)
899
    for n in allnodes:
900
      host_info = env.env.ips_info[host]
901
      debug(env.host, " * Removing node %s..." % n)
902
      cmd = "gnt-node remove  " + host_info.fqdn
903
      try_run(cmd)
904
    try_run("gnt-cluster destroy --yes-do-it")
905

    
906

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

928
    """.format(extra, env.env.common_bridge,
929
               env.env.cluster_netdev, env.env.cluster.fqdn)
930
    try_run(cmd)
931

    
932

    
933
@roles("ganeti")
934
def debootstrap():
935
    install_package("ganeti-instance-debootstrap")
936

    
937

    
938
@roles("ganeti")
939
def setup_image_host():
940
    debug(env.host, "Setting up snf-image...")
941
    install_package("snf-pithos-backend")
942
    install_package("snf-image")
943
    try_run("mkdir -p /srv/okeanos")
944
    tmpl = "/etc/default/snf-image"
945
    replace = {
946
        "synnefo_user": env.env.synnefo_user,
947
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
948
        "pithos_dir": env.env.pithos_dir,
949
        "db_node": env.env.db.ip,
950
    }
951
    custom = customize_settings_from_tmpl(tmpl, replace)
952
    put(custom, tmpl)
953

    
954

    
955
@roles("ganeti")
956
def setup_image_helper():
957
    debug(env.host, " * Updating helper image...")
958
    cmd = """
959
    snf-image-update-helper -y
960
    """
961
    try_run(cmd)
962

    
963

    
964
@roles("ganeti")
965
def setup_gtools():
966
    debug(env.host, " * Setting up snf-cyclades-gtools...")
967
    with settings(hide("everything")):
968
        try_run("ping -c1 " + env.env.mq.ip)
969
    setup_common()
970
    install_package("snf-cyclades-gtools")
971
    tmpl = "/etc/synnefo/gtools.conf"
972
    replace = {
973
        "synnefo_user": env.env.synnefo_user,
974
        "synnefo_rabbitmq_passwd": env.env.synnefo_rabbitmq_passwd,
975
        "mq_node": env.env.mq.ip,
976
    }
977
    custom = customize_settings_from_tmpl(tmpl, replace)
978
    put(custom, tmpl)
979

    
980
    cmd = """
981
    sed -i 's/false/true/' /etc/default/snf-ganeti-eventd
982
    /etc/init.d/snf-ganeti-eventd start
983
    """
984
    try_run(cmd)
985

    
986

    
987
@roles("ganeti")
988
def setup_iptables():
989
    debug(env.host, " * Setting up iptables to mangle DHCP requests...")
990
    cmd = """
991
    iptables -t mangle -A PREROUTING -i br+ -p udp -m udp --dport 67 -j NFQUEUE --queue-num 42
992
    iptables -t mangle -A PREROUTING -i tap+ -p udp -m udp --dport 67 -j NFQUEUE --queue-num 42
993
    iptables -t mangle -A PREROUTING -i prv+ -p udp -m udp --dport 67 -j NFQUEUE --queue-num 42
994

995
    ip6tables -t mangle -A PREROUTING -i br+ -p ipv6-icmp -m icmp6 --icmpv6-type 133 -j NFQUEUE --queue-num 43
996
    ip6tables -t mangle -A PREROUTING -i br+ -p ipv6-icmp -m icmp6 --icmpv6-type 135 -j NFQUEUE --queue-num 44
997
    """
998
    try_run(cmd)
999

    
1000
@roles("ganeti")
1001
def setup_network():
1002
    debug(env.host, "Setting up networking for Ganeti instances (nfdhcpd, etc.)...")
1003
    install_package("nfqueue-bindings-python")
1004
    install_package("nfdhcpd")
1005
    tmpl = "/etc/nfdhcpd/nfdhcpd.conf"
1006
    replace = {
1007
      "ns_node_ip": env.env.ns.ip
1008
      }
1009
    custom = customize_settings_from_tmpl(tmpl, replace)
1010
    put(custom, tmpl)
1011
    try_run("/etc/init.d/nfdhcpd restart")
1012

    
1013
    install_package("snf-network")
1014
    cmd = """
1015
    sed -i 's/MAC_MASK.*/MAC_MASK = ff:ff:f0:00:00:00/' /etc/default/snf-network
1016
    """
1017
    try_run(cmd)
1018

    
1019

    
1020
@roles("router")
1021
def setup_router():
1022
    debug(env.host, " * Setting up internal router for NAT...")
1023
    cmd = """
1024
    echo 1 > /proc/sys/net/ipv4/ip_forward
1025
    iptables -t nat -A POSTROUTING -s {0} -o {3} -j MASQUERADE
1026
    ip addr add {1} dev {2}
1027
    ip route add {0} dev {2} src {1}
1028
    """.format(env.env.synnefo_public_network_subnet,
1029
               env.env.synnefo_public_network_gateway,
1030
               env.env.common_bridge, env.env.public_iface)
1031
    try_run(cmd)
1032

    
1033
@roles("cyclades")
1034
def cyclades_loaddata():
1035
    debug(env.host, " * Loading initial data for cyclades...")
1036
    tmpl = "/tmp/flavor.json"
1037
    replace = {}
1038
    custom = customize_settings_from_tmpl(tmpl, replace)
1039
    put(custom, tmpl)
1040
    try_run("snf-manage loaddata " + tmpl)
1041
    #run("snf-manage loaddata flavors")
1042

    
1043

    
1044
@roles("cyclades")
1045
def setup_cyclades():
1046
    debug(env.host, "Setting up snf-cyclades-app...")
1047
    with settings(hide("everything")):
1048
        try_run("ping -c1 accounts." + env.env.domain)
1049
        try_run("ping -c1 " + env.env.db.ip)
1050
        try_run("ping -c1 " + env.env.mq.ip)
1051
    setup_gunicorn()
1052
    setup_apache()
1053
    setup_webproject()
1054
    install_package("memcached")
1055
    install_package("python-memcache")
1056
    install_package("snf-pithos-backend")
1057
    install_package("kamaki")
1058
    install_package("snf-cyclades-app")
1059
    install_package("python-django-south")
1060
    tmpl = "/etc/synnefo/cyclades.conf"
1061

    
1062
    with settings(host_string=env.env.accounts.ip):
1063
        service_id, service_token = get_service_details("cyclades")
1064

    
1065
    replace = {
1066
        "ACCOUNTS": env.env.accounts.fqdn,
1067
        "CYCLADES": env.env.cyclades.fqdn,
1068
        "mq_node": env.env.mq.ip,
1069
        "db_node": env.env.db.ip,
1070
        "synnefo_user": env.env.synnefo_user,
1071
        "synnefo_db_passwd": env.env.synnefo_db_passwd,
1072
        "synnefo_rabbitmq_passwd": env.env.synnefo_rabbitmq_passwd,
1073
        "pithos_dir": env.env.pithos_dir,
1074
        "common_bridge": env.env.common_bridge,
1075
        "HOST": env.env.cyclades.ip,
1076
        "domain": env.env.domain,
1077
        "CYCLADES_SERVICE_TOKEN": service_token,
1078
        "proxy": env.env.cyclades.hostname == env.env.accounts.hostname
1079
        }
1080
    custom = customize_settings_from_tmpl(tmpl, replace)
1081
    put(custom, tmpl, mode=0644)
1082
    try_run("/etc/init.d/gunicorn restart")
1083

    
1084
    cmd = """
1085
    sed -i 's/false/true/' /etc/default/snf-dispatcher
1086
    /etc/init.d/snf-dispatcher start
1087
    """
1088
    try_run(cmd)
1089

    
1090
    try_run("snf-manage syncdb")
1091
    try_run("snf-manage migrate --delete-ghost-migrations")
1092

    
1093

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

    
1099

    
1100
@roles("cyclades")
1101
def add_backend():
1102
    debug(env.host, "adding %s ganeti backend to cyclades..." % env.env.cluster.fqdn)
1103
    with settings(hide("everything")):
1104
        try_run("ping -c1 " + env.env.cluster.fqdn)
1105
    cmd = """
1106
    snf-manage backend-add --clustername={0} --user={1} --pass={2}
1107
    """.format(env.env.cluster.fqdn, env.env.synnefo_user,
1108
               env.env.synnefo_rapi_passwd)
1109
    try_run(cmd)
1110
    backend_id = get_backend_id(env.env.cluster.fqdn)
1111
    try_run("snf-manage backend-modify --drained=False " + backend_id)
1112

    
1113
@roles("cyclades")
1114
def pin_user_to_backend(user_email):
1115
    backend_id = get_backend_id(env.env.cluster.fqdn)
1116
    # pin user to backend
1117
    cmd = """
1118
cat <<EOF >> /etc/synnefo/cyclades.conf
1119

1120
BACKEND_PER_USER = {
1121
  '%s': %s,
1122
}
1123

1124
EOF
1125
/etc/init.d/gunicorn restart
1126
    """  % (user_email, backend_id)
1127
    try_run(cmd)
1128

    
1129
@roles("cyclades")
1130
def add_pools():
1131
    debug(env.host, " * Creating pools of resources (brigdes, mac prefixes) in cyclades...")
1132
    try_run("snf-manage pool-create --type=mac-prefix --base=aa:00:0 --size=65536")
1133
    try_run("snf-manage pool-create --type=bridge --base=prv --size=20")
1134

    
1135

    
1136
@roles("cyclades")
1137
def add_network():
1138
    debug(env.host, " * Adding public network in cyclades...")
1139
    backend_id = get_backend_id(env.env.cluster.fqdn)
1140
    cmd = """
1141
    snf-manage network-create --subnet={0} --gateway={1} --public --dhcp --flavor={2} --mode=bridged --link={3} --name=Internet --backend-id={4}
1142
    """.format(env.env.synnefo_public_network_subnet,
1143
               env.env.synnefo_public_network_gateway,
1144
               env.env.synnefo_public_network_type,
1145
               env.env.common_bridge, backend_id)
1146
    try_run(cmd)
1147

    
1148

    
1149
@roles("cyclades")
1150
def setup_vncauthproxy():
1151
    debug(env.host, " * Setting up vncauthproxy...")
1152
    install_package("snf-vncauthproxy")
1153
    cmd = """
1154
    echo CHUID="www-data:nogroup" >> /etc/default/vncauthproxy
1155
    rm /var/log/vncauthproxy/vncauthproxy.log
1156
    """
1157
    try_run(cmd)
1158
    try_run("/etc/init.d/vncauthproxy restart")
1159

    
1160
@roles("client")
1161
def setup_kamaki():
1162
    debug(env.host, "Setting up kamaki client...")
1163
    with settings(hide("everything")):
1164
        try_run("ping -c1 accounts." + env.env.domain)
1165
        try_run("ping -c1 cyclades." + env.env.domain)
1166
        try_run("ping -c1 pithos." + env.env.domain)
1167

    
1168
    with settings(host_string=env.env.db.ip):
1169
        uid, user_auth_token, user_uuid = get_auth_token_from_db(env.env.user_email)
1170

    
1171
    install_package("python-progress")
1172
    install_package("kamaki")
1173
    cmd = """
1174
    kamaki config set cloud.default.url "https://{0}/astakos/identity/v2.0/"
1175
    kamaki config set cloud.default.token {1}
1176
    """.format(env.env.accounts.fqdn, user_auth_token)
1177
    try_run(cmd)
1178
    try_run("kamaki file create images")
1179

    
1180
@roles("client")
1181
def upload_image(image="debian_base.diskdump"):
1182
    debug(env.host, " * Uploading initial image to pithos...")
1183
    image = "debian_base.diskdump"
1184
    try_run("wget {0} -O /tmp/{1}".format(env.env.debian_base_url, image))
1185
    try_run("kamaki file upload --container images /tmp/{0} {0}".format(image))
1186

    
1187
@roles("client")
1188
def register_image(image="debian_base.diskdump"):
1189
    debug(env.host, " * Register image to plankton...")
1190
    with settings(host_string=env.env.db.ip):
1191
        uid, user_auth_token, user_uuid = get_auth_token_from_db(env.env.user_email)
1192

    
1193
    pithos_url = "pithos://{0}/images/{1}".format(user_uuid, image)
1194
    cmd = """
1195
    sleep 5
1196
    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
1197
    """.format(pithos_url)
1198
    try_run(cmd)
1199

    
1200
@roles("client")
1201
def setup_burnin():
1202
    debug(env.host, "Setting up burnin testing tool...")
1203
    install_package("kamaki")
1204
    install_package("snf-tools")
1205

    
1206
@roles("pithos")
1207
def add_image_locally():
1208
    debug(env.host, " * Getting image locally in order snf-image to use it directly..")
1209
    image = "debian_base.diskdump"
1210
    try_run("wget {0} -O /srv/okeanos/{1}".format(env.env.debian_base_url, image))
1211

    
1212

    
1213
@roles("master")
1214
def gnt_instance_add(name="test"):
1215
    debug(env.host, " * Adding test instance to Ganeti...")
1216
    osp="""img_passwd=gamwtosecurity,img_format=diskdump,img_id=debian_base,img_properties='{"OSFAMILY":"linux"\,"ROOT_PARTITION":"1"}'"""
1217
    cmd = """
1218
    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}
1219
    """.format(osp, name)
1220
    try_run(cmd)
1221

    
1222
@roles("master")
1223
def gnt_network_add(name="test", subnet="10.0.0.0/26", gw="10.0.0.1", mode="bridged", link="br0"):
1224
    debug(env.host, " * Adding test network to Ganeti...")
1225
    cmd = """
1226
    gnt-network add --network={1} --gateway={2} {0}
1227
    gnt-network connect {0} {3} {4}
1228
    """.format(name, subnet, gw, mode, link)
1229
    try_run(cmd)
1230

    
1231
@roles("ips")
1232
def test():
1233
    debug(env.host, "Testing...")
1234
    try_run("hostname && date")