prepare.py 4.76 KB
Newer Older
1 2 3 4
# -*- coding: utf-8 -*-

import ConfigParser
import os
5
import subprocess
6 7 8

import lockfile

9 10
from .config import LXCConfig

11 12 13 14 15 16 17
class SlapContainerError(Exception):
    """This exception is thrown, if there is
    any failure during slapcontainer preparation,
    starting or stopping process"""



18
def main(sr_directory, partition_list, bridge_name):
19

20
    started_containers = set()
21 22 23 24 25
    for partition_path in partition_list:
        slapcontainer_filename = os.path.join(partition_path,
                                              '.slapcontainer')
        if os.path.isfile(slapcontainer_filename):
            lock = lockfile.FileLock(slapcontainer_filename)
26 27 28
            lock.acquire(timeout=0)
            slapcontainer_conf = ConfigParser.ConfigParser()
            slapcontainer_conf.read(slapcontainer_filename)
29
            try:
30 31 32 33 34

                requested_status = slapcontainer_conf.get('requested',
                                                          'status')

                if requested_status == 'started':
Antoine Catton's avatar
Antoine Catton committed
35 36
                    create(sr_directory, partition_path,
                           slapcontainer_conf, bridge_name)
Antoine Catton's avatar
Antoine Catton committed
37 38 39 40
                    if status(sr_directory, partition_path,
                              slapcontainer_conf) == 'stopped':
                        start(sr_directory, partition_path,
                              slapcontainer_conf)
41 42 43
                        started_containers.add(
                            slapcontainer_conf.get('requested', 'name')
                        )
44
                else:
Antoine Catton's avatar
Antoine Catton committed
45 46
                    if status(sr_directory, partition_path,
                              slapcontainer_conf) == 'started':
47
                        stop(sr_directory, partition_path)
48 49 50 51 52 53
            except lockfile.LockTimeout:
                # Can't do anything, we'll see on the next run
                pass
            finally:
                lock.release()

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    try:
        active_containers = set(call(
            [os.path.join(sr_directory, 'parts/lxc/bin/lxc-ls'),
             '--active']
        ).split('\n'))
    except SlapContainerError:
        active_containers = set()

    to_stop = active_containers - started_containers

    for container in to_stop:
        try:
            call(
                [os.path.join(sr_directory, 'parts/lxc/bin/lxc-stop'),
                 '-n', container
                ]
            )
        except SlapContainerError:
            pass # TODO : put some log

74 75


Antoine Catton's avatar
Antoine Catton committed
76
def start(sr_directory, partition_path, conf):
Antoine Catton's avatar
Antoine Catton committed
77 78
    lxc_start = os.path.join(sr_directory,
                             'parts/lxc/bin/lxc-start')
Antoine Catton's avatar
Antoine Catton committed
79
    config_filename = conf.get('config', 'file')
Antoine Catton's avatar
Antoine Catton committed
80

81
    call([lxc_start, '-f', config_filename,
Antoine Catton's avatar
Antoine Catton committed
82
          '-n', conf.get('requested', 'name'),
83
          '-d'])
84 85 86



87
def stop(sr_directory, partition_path):
88 89 90

    # TODO : Check if container is stopped
    #        Stop container
91
    pass
92

93 94


95
def create(sr_directory, partition_path, conf, bridge_name):
Antoine Catton's avatar
Antoine Catton committed
96
    lxc_filename = conf.get('config', 'file')
97
    lxc = LXCConfig()
Antoine Catton's avatar
Antoine Catton committed
98
    lxc.utsname = conf.get('requested', 'name')
99 100 101
    lxc.network.type = 'veth'
    lxc.network.link = bridge_name
    lxc.network.veth.pair = 'lxc%s' % conf.get('network', 'interface')
102 103
    lxc.network.name = 'eth0'
    lxc.network.flags = 'up'
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    # XXX: Hardcoded stuff
    lxc.tty = '4'
    lxc.pts = '1024'
    lxc.cgroup.devices.deny = 'a'
    lxc.cgroup.devices.allow = [
        'c 1:3 rwm',
        'c 1:5 rwm',
        'c 5:1 rwm',
        'c 5:0 rwm',
        'c 4:0 rwm',
        'c 4:1 rwm',
        'c 1:9 rwm',
        'c 1:8 rwm',
        'c 136:* rwm',
        'c 5:2 rwm',
        'c 254:0 rwm',
    ]
Antoine Catton's avatar
Antoine Catton committed
121 122 123 124 125 126 127
    # XXX : This is a relic of previous code, even if it is versionned
    #       this could be usefull in future
    # lxc.mount.entry = [
    #     'proc %s proc nodev,noexec,nosuid 0 0' % os.path.join(rootfs_dir, 'proc'),
    #     'sysfs %s sysfs defaults 0 0' % os.path.join(rootfs_dir, 'sys'),
    # ]
    lxc.rootfs = conf.get('rootfs', 'image')
128 129 130

    with open(lxc_filename, 'w') as lxc_file:
        lxc_file.write(str(lxc))
131 132


133

Antoine Catton's avatar
Antoine Catton committed
134
def status(sr_directory, partition_path, conf):
135
    lxc_info = call([os.path.join(sr_directory, 'parts/lxc/bin/lxc-info'),
Antoine Catton's avatar
Antoine Catton committed
136
                     '-n', conf.get('requested', 'name')])
137 138 139 140 141 142 143
    if 'RUNNING' in lxc_info:
        return 'started'
    else:
        return 'stopped'



144
def call(command_line, override_environ={}):
145 146
    # for debug :
    # print ' '.join(command_line)
147 148
    environ = dict(os.environ)
    environ.update(override_environ)
149
    process = subprocess.Popen(command_line, stdin=subprocess.PIPE,
150
                               stdout=subprocess.PIPE, env=environ)
151 152
    process.stdin.flush()
    process.stdin.close()
153 154 155

    if process.wait() != 0:
        raise SlapContainerError("Subprocess call failed")
156 157 158 159 160

    out = process.stdout.read()
    # for debug :
    # print out
    return out