containers.py 5.33 KB
Newer Older
1 2 3
from __future__ import print_function

from aci import ImageManifest
4
from collections import namedtuple
5 6
import logging
import os
7
from subprograms import ChrtClient, NodeOSClient, resources
8

9
logger = logging.getLogger('nrm')
10
Container = namedtuple('Container', ['uuid', 'manifest', 'resources',
11
                                     'power', 'process'])
12

13 14 15 16 17 18

class ContainerManager(object):

    """Manages the creation, listing and deletion of containers, using a
    container runtime underneath."""

19
    def __init__(self, rm):
20
        self.containers = dict()
21 22 23 24
        self.pids = dict()
        self.resourcemanager = rm
        self.nodeos = NodeOSClient()
        self.chrt = ChrtClient()
25 26 27 28 29 30 31 32

    def create(self, request):
        """Create a container according to the request.

        Returns the pid of the container or a negative number for errors."""
        manifestfile = request['manifest']
        command = request['file']
        args = request['args']
33 34 35
        logger.info("run: manifest file: %s", manifestfile)
        logger.info("run: command:       %s", command)
        logger.info("run: args:          %r", args)
36 37
        manifest = ImageManifest()
        if not manifest.load(manifestfile):
38
            logger.error("Manifest is invalid")
39
            return None
40

41 42 43 44
        # ask the resource manager for resources
        req = resources(int(manifest.app.isolators.container.cpus.value),
                        int(manifest.app.isolators.container.mems.value))
        allocation = self.resourcemanager.schedule(request['uuid'], req)
45
        logger.info("run: allocation: %r", allocation)
46 47 48

        # build context to execute
        environ = os.environ
49 50
        # environ['PATH'] = ("/usr/local/sbin:"
        #                   "/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
51 52
        environ['AC_APP_NAME'] = manifest.name
        environ['AC_METADATA_URL'] = "localhost"
53
        logger.info("run: environ: %r", environ)
54 55 56

        # create container
        container_name = request['uuid']
57
        environ['ARGO_CONTAINER_UUID'] = container_name
58
        logger.info("creating container %s", container_name)
59
        self.nodeos.create(container_name, allocation)
60 61
        container_resources = dict()
        container_resources['cpus'], container_resources['mems'] = allocation
62

63 64 65 66 67 68 69
        # Container power settings
        container_power = dict()
        container_power['profile'] = None
        container_power['policy'] = None
        container_power['damper'] = None
        container_power['slowdown'] = None
        container_power['manager'] = None
70 71 72
        # TODO: Application library to load must be set during configuration
        applicationpreloadlibrary = ''

73 74 75 76
        # run my command
        if hasattr(manifest.app.isolators, 'scheduler'):
            sched = manifest.app.isolators.scheduler
            argv = self.chrt.getwrappedcmd(sched)
77
        else:
78 79
            argv = []

80 81 82 83 84 85 86 87
        # It would've been better if argo-perf-wrapper wrapped around
        # argo-nodeos-config and not the final command -- that way it would
        # be running outside of the container.  However, because
        # argo-nodeos-config is suid root, perf can't monitor it.
        if hasattr(manifest.app.isolators, 'perfwrapper'):
            if hasattr(manifest.app.isolators.perfwrapper, 'enabled'):
                if manifest.app.isolators.perfwrapper.enabled in ["1", "True"]:
                    argv.append('argo-perf-wrapper')
88

89 90 91
        if hasattr(manifest.app.isolators, 'power'):
            if hasattr(manifest.app.isolators.power, 'enabled'):
                    pp = manifest.app.isolators.power
92
                    if pp.enabled in ["1", "True"]:
93
                        if pp.profile in ["1", "True"]:
94 95 96
                            container_power['profile'] = dict()
                            container_power['profile']['start'] = dict()
                            container_power['profile']['end'] = dict()
97
                        if pp.policy != "NONE":
98 99 100
                            container_power['policy'] = pp.policy
                            container_power['damper'] = pp.damper
                            container_power['slowdown'] = pp.slowdown
101
                            environ['LD_PRELOAD'] = applicationpreloadlibrary
102

103 104 105
        argv.append(command)
        argv.extend(args)
        process = self.nodeos.execute(container_name, argv, environ)
106
        c = Container(container_name, manifest, container_resources,
107
                      container_power, process)
108 109
        self.pids[process.pid] = c
        self.containers[container_name] = c
110
        logger.info("Container %s created and running : %r", container_name, c)
111
        return c
112 113 114

    def delete(self, uuid):
        """Delete a container and kill all related processes."""
115
        self.nodeos.delete(uuid, kill=True)
116
        self.resourcemanager.update(uuid)
117 118
        c = self.containers[uuid]
        del self.containers[uuid]
119
        del self.pids[c.process.pid]
120

Swann Perarnau's avatar
Swann Perarnau committed
121 122 123 124
    def kill(self, uuid):
        """Kill all the processes of a container."""
        if uuid in self.containers:
            c = self.containers[uuid]
125
            logger.debug("killing %r:", c)
Swann Perarnau's avatar
Swann Perarnau committed
126
            try:
127
                c.process.proc.terminate()
Swann Perarnau's avatar
Swann Perarnau committed
128 129 130
            except OSError:
                pass

131 132
    def list(self):
        """List the containers in the system."""
133
        return [{'uuid': c.uuid, 'pid': c.process.pid} for c in
134
                self.containers.values()]