Commit 560f5b94 authored by Antoine Catton's avatar Antoine Catton

Simplify and trim slapcontainer

parent 87c12a30
...@@ -41,7 +41,6 @@ setup(name=name, ...@@ -41,7 +41,6 @@ setup(name=name,
'slapos.core', # as it provides library for slap 'slapos.core', # as it provides library for slap
'xml_marshaller', # needed to dump information 'xml_marshaller', # needed to dump information
'GitPython', #needed for git manipulation into slaprunner 'GitPython', #needed for git manipulation into slaprunner
'lockfile', #needed for interprocess exclusion (in slapcontainer)
] + additional_install_requires, ] + additional_install_requires,
extras_require = { extras_require = {
'lampconfigure': ["mysql-python"], #needed for MySQL Database access 'lampconfigure': ["mysql-python"], #needed for MySQL Database access
......
...@@ -5,13 +5,19 @@ import argparse ...@@ -5,13 +5,19 @@ import argparse
import sys import sys
import os import os
import logging
from . import prepare from . import process
def main(): def main():
parser = argparse.ArgumentParser(description="Slapcontainer binary") parser = argparse.ArgumentParser(description="Slapcontainer binary")
parser.add_argument('configuration_file', type=str, parser.add_argument('configuration_file', type=str,
help="SlapOS configuration file.") help="SlapOS configuration file.")
log_lvls = [lvl for lvl in logging._levelNames.keys()
if isinstance(lvl, basestring)]
parser.add_argument('--log', nargs=1, default=['INFO'],
choices=log_lvls,
metavar='lvl')
args = parser.parse_args() args = parser.parse_args()
slapos_conf = ConfigParser.ConfigParser() slapos_conf = ConfigParser.ConfigParser()
...@@ -27,6 +33,7 @@ def main(): ...@@ -27,6 +33,7 @@ def main():
partition_base_path = os.path.join(instance_root, partition_base_name) partition_base_path = os.path.join(instance_root, partition_base_name)
partition_list = ['%s%d' % (partition_base_path, i) partition_list = ['%s%d' % (partition_base_path, i)
for i in range(partition_amount)] for i in range(partition_amount)]
bridge_name = slapos_conf.get('slapformat', 'interface_name')
prepare.main(sr_directory, partition_list, bridge_name) logging.basicConfig(level=logging.getLevelName(args.log[0]))
process.main(sr_directory, partition_list)
# -*- coding: utf-8 -*-
import collections
import StringIO
class LXCConfig(object):
"""LXC Configuration file parser
"""
class _Sub(object):
"""Subobject to go throught
LXC COnfiguration"""
def __init__(self, parent, namespace):
self._parent = parent
self._namespace = namespace
def __getattr__(self, name):
if name.startswith('_'):
return self.__dict__[name]
return self._parent._get('%s.%s' % (self._namespace,
name))
def __setattr__(self, name, value):
if name.startswith('_'):
self.__dict__[name] = value
else:
self._parent._set('%s.%s' % (self._namespace, name),
value)
def __init__(self, filename=None):
"""LXCConfig init method. filename should be a string
of the path to the filename.
"""
self._filename = filename
if filename is not None:
with open(filename, 'r') as lxcconf_file:
self._values = self._load(lxcconf_file.read())
else:
self._values = collections.OrderedDict()
def __getattr__(self, name):
return self._get(name)
def __setattr__(self, name, value):
if name.startswith('_'):
self.__dict__[name] = value
else:
self._set(name, value)
def _load(self, config_string):
result = collections.OrderedDict()
for line in config_string.split('\n'):
if not line.strip().startswith('#') and line.strip() != '':
if '=' not in line:
raise ValueError("Not a valid LXCFile")
key, value = [i.strip() for i in line.split('=', 1)]
if key in result:
if isinstance(result[key], basestring):
result[key] = [result[key], value]
else:
result[key].append(value)
else:
result[key] = value
return result
def _set(self, key, value):
self._values['lxc.%s' % key] = value
def _get(self, key):
try:
return self._values['lxc.%s' % key]
except KeyError:
return self._Sub(self, key)
def __str__(self):
result = StringIO.StringIO()
for key, value in self._values.iteritems():
if isinstance(value, basestring):
print >> result, key, '=', value
else:
for item in value:
print >> result, key, '=', item
return result.getvalue()
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import ConfigParser
import os import os
import subprocess import subprocess
import logging import logging
import lockfile
from .config import LXCConfig
class SlapContainerError(Exception): class SlapContainerError(Exception):
"""This exception is thrown, if there is """This exception is thrown, if there is
any failure during slapcontainer preparation, any failure during slapcontainer preparation,
...@@ -16,43 +11,41 @@ class SlapContainerError(Exception): ...@@ -16,43 +11,41 @@ class SlapContainerError(Exception):
def main(sr_directory, partition_list, bridge_name): def main(sr_directory, partition_list):
logger = logging.getLogger() logger = logging.getLogger('process')
to_start = set() to_start = set()
logger.debug('Processing partitions...')
for partition_path in partition_list: for partition_path in partition_list:
partition_logger = logger.getChild(
os.path.basename(partition_path)
)
partition_logger.debug('Processing...')
# XXX: Hardcoded path
slapcontainer_filename = os.path.join(partition_path, slapcontainer_filename = os.path.join(partition_path,
'.slapcontainer') '.slapcontainername')
if os.path.isfile(slapcontainer_filename): if os.path.isfile(slapcontainer_filename):
lock = lockfile.FileLock(slapcontainer_filename) partition_logger.debug('Container found...')
lock.acquire(timeout=0) with open(slapcontainer_filename, 'r') as slapcontainer_file:
slapcontainer_conf = ConfigParser.ConfigParser() name = slapcontainer_file.read().strip()
slapcontainer_conf.read(slapcontainer_filename)
try: # XXX: Hardcoded path
lxc_conf_path = os.path.join(partition_path,
requested_status = slapcontainer_conf.get('requested', 'etc/lxc.conf')
'status') with open(lxc_conf_path, 'r') as lxc_conf_file:
requested_status = lxc_conf_file.readline().strip(' \n\r\t#')
if requested_status == 'started':
create(sr_directory, partition_path,
slapcontainer_conf, bridge_name) if requested_status == 'started':
if status(sr_directory, partition_path,
slapcontainer_conf) == 'stopped': current_status = status(sr_directory, partition_path, name)
start(sr_directory, partition_path, to_start.add(name)
slapcontainer_conf)
to_start.add( if requested_status != current_status:
slapcontainer_conf.get('requested', 'name') start(sr_directory, partition_path, name, lxc_conf_path)
)
else:
if status(sr_directory, partition_path,
slapcontainer_conf) == 'started':
stop(sr_directory, partition_path)
except lockfile.LockTimeout:
# Can't do anything, we'll see on the next run
pass
finally:
lock.release()
logger.debug('Container to start %s.', ', '.join(to_start)) logger.debug('Container to start %s.', ', '.join(to_start))
try: try:
...@@ -81,67 +74,18 @@ def main(sr_directory, partition_list, bridge_name): ...@@ -81,67 +74,18 @@ def main(sr_directory, partition_list, bridge_name):
def start(sr_directory, partition_path, conf): def start(sr_directory, partition_path, name, lxc_conf_path):
lxc_start = os.path.join(sr_directory, lxc_start = os.path.join(sr_directory,
'parts/lxc/bin/lxc-start') 'parts/lxc/bin/lxc-start')
config_filename = conf.get('config', 'file') call([lxc_start, '-f', lxc_conf_path,
'-n', name,
call([lxc_start, '-f', config_filename,
'-n', conf.get('requested', 'name'),
'-d']) '-d'])
def status(sr_directory, partition_path, name):
logger = logging.getLogger('status')
def stop(sr_directory, partition_path): logger.debug('Check status of %s', name)
# TODO : Check if container is stopped
# Stop container
pass
def create(sr_directory, partition_path, conf, bridge_name):
lxc_filename = conf.get('config', 'file')
lxc = LXCConfig()
lxc.utsname = conf.get('requested', 'name')
lxc.network.type = 'veth'
lxc.network.link = bridge_name
lxc.network.veth.pair = 'lxc%s' % conf.get('network', 'interface')
lxc.network.name = 'eth0'
lxc.network.flags = 'up'
# 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',
]
# 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')
with open(lxc_filename, 'w') as lxc_file:
lxc_file.write(str(lxc))
def status(sr_directory, partition_path, conf):
lxc_info = call([os.path.join(sr_directory, 'parts/lxc/bin/lxc-info'), lxc_info = call([os.path.join(sr_directory, 'parts/lxc/bin/lxc-info'),
'-n', conf.get('requested', 'name')]) '-n', name])
if 'RUNNING' in lxc_info: if 'RUNNING' in lxc_info:
return 'started' return 'started'
else: else:
...@@ -150,7 +94,7 @@ def status(sr_directory, partition_path, conf): ...@@ -150,7 +94,7 @@ def status(sr_directory, partition_path, conf):
def call(command_line, override_environ={}): def call(command_line, override_environ={}):
logger = logging.getLogger() logger = logging.getLogger('commandline')
logger.debug('Call %s', ' '.join(command_line)) logger.debug('Call %s', ' '.join(command_line))
environ = dict(os.environ) environ = dict(os.environ)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment