예제 #1
0
    def test_create_script_linux(self):
        """this tests the create_script function.

        the function creates executable scripts from templates that exist
        in the template directory.
        """
        script_file = os.path.join(self.root, 'script')
        # Function we are testing
        utils.create_script(script_file,
                            's6.run',
                            user='******',
                            home='home',
                            shell='shell',
                            _alias={
                                's6_setuidgid': '/test/s6-setuidgid',
                            })

        # Read the output from the mock filesystem
        with io.open(script_file) as script:
            data = script.read()

        # Validate that data is what it should be
        self.assertTrue(data.index('/test/s6-setuidgid testproid') > 0)

        # Validate that the file is +x
        self.assertEqual(utils.os.stat(script_file).st_mode, 33261)
예제 #2
0
    def test_create_script(self):
        """this tests the create_script function.

        the function creates executable scripts from templates that exist
        in the template directory.
        """
        script_file = os.path.join(self.root, 'script')
        # Function we are testing
        utils.create_script(script_file,
                            'supervisor.run',
                            service='testservice',
                            user='******',
                            home='home',
                            shell='shell',
                            cmd='run',
                            as_root=True)

        # Read the output from the mock filesystem
        with open(script_file) as script:
            data = script.read()

        # Validate that data is what it should be
        self.assertTrue(
            data.index('${TREADMILL_S6}/bin/s6-setuidgid testproid') > 0)

        # Validate that the file is +x
        self.assertEqual(utils.os.stat(script_file).st_mode, 33261)
예제 #3
0
def _create_sysrun(sys_dir, name, command, down=False):
    """Create system script."""
    fs.mkdir_safe(os.path.join(sys_dir, name))
    utils.create_script(os.path.join(sys_dir, name, 'run'),
                        'supervisor.run_sys',
                        cmd=command)
    _create_logrun(os.path.join(sys_dir, name))
    if down:
        utils.touch(os.path.join(sys_dir, name, 'down'))
예제 #4
0
def create_service(app_root,
                   user,
                   home,
                   shell,
                   service,
                   runcmd,
                   env=None,
                   down=True,
                   envdirs=None,
                   as_root=True,
                   template=None):
    """Initializes service directory.

    Creates run, finish scripts as well as log directory with appropriate
    run script.
    """
    real_svc_dir = os.path.join(app_root, service)
    fs.mkdir_safe(real_svc_dir)

    with open(os.path.join(real_svc_dir, 'app_start'), 'w') as f:
        f.write(runcmd)

    if template is None:
        template = 'supervisor.run'

    cmd = '/services/{0}/app_start'.format(service)

    if envdirs is None:
        envdirs = []

    utils.create_script(os.path.join(real_svc_dir, 'run'),
                        template,
                        service=service,
                        user=user,
                        home=home,
                        shell=shell,
                        cmd=cmd,
                        env=env,
                        envdirs=envdirs,
                        as_root=as_root)

    utils.create_script(os.path.join(real_svc_dir, 'finish'),
                        'supervisor.finish',
                        service=service,
                        user=user,
                        cmds=[])

    if down:
        with open(os.path.join(real_svc_dir, 'down'), 'w'):
            pass
예제 #5
0
    def test_create_script_perms(self):
        """this tests the create_script function (permissions).
        """
        script_file = os.path.join(self.root, 'script')
        # Test non-default mode (+x)
        mode = (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)

        utils.create_script(script_file,
                            'supervisor.run',
                            mode,
                            service='testservice',
                            user='******',
                            cmd='run')

        self.assertEqual(utils.os.stat(script_file).st_mode, 33060)
예제 #6
0
    def _create_instance(self, path):
        """Create an spawn instance."""
        job, bucket, running = spawn_utils.get_instance_path(path, self.paths)

        _LOGGER.debug('Creating - (%r, %r)', job, running)

        if os.path.exists(running):
            _LOGGER.debug('Create %r failed - already exists', running)
            return

        inst = instance.Instance(path)
        data_dir = os.path.join(job, spawn.JOB_DATA_DIR)

        fs.mkdir_safe(job)
        fs.mkdir_safe(data_dir)

        utils.create_script(
            os.path.join(job, 'run'),
            'spawn.run',
            id=inst.id,
            name=inst.name,
            service_exit=inst.settings.get('service_exit', False),
            **subproc.get_aliases()
        )

        utils.create_script(
            os.path.join(job, 'finish'),
            'spawn.finish',
            id=inst.id,
            stop=inst.settings.get('stop', False),
            reconnect=inst.settings.get('reconnect', False),
            reconnect_timeout=inst.settings.get('reconnect_timeout', 0),
            **subproc.get_aliases()
        )

        with io.open(os.path.join(data_dir, 'manifest'), 'w') as f:
            f.writelines(
                utils.json_genencode(inst.manifest)
            )

        with io.open(os.path.join(job, 'timeout-finish'), 'w') as f:
            f.write(six.text_type(spawn.JOB_FINISH_TIMEOUT))

        fs.symlink_safe(running, job)

        self._scan(bucket)
예제 #7
0
    def test_create_script_perms_linux(self):
        """this tests the create_script function (permissions).
        """
        script_file = os.path.join(self.root, 'script')
        # Test non-default mode (+x)
        mode = (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)

        utils.create_script(script_file,
                            's6.run',
                            mode=mode,
                            user='******',
                            home='home',
                            shell='shell',
                            _alias={
                                's6_setuidgid': '/test/s6-setuidgid',
                            })

        self.assertEqual(utils.os.stat(script_file).st_mode, 33060)
예제 #8
0
    def _create_instance(self, path):
        """Create an spawn instance."""
        job, bucket, running = spawn_utils.get_instance_path(path, self.paths)

        _LOGGER.debug('Creating - (%r, %r)', job, running)

        if os.path.exists(running):
            _LOGGER.debug('Create %r failed - already exists', running)
            return

        inst = instance.Instance(path)
        data_dir = os.path.join(job, spawn.JOB_DATA_DIR)

        fs.mkdir_safe(job)
        fs.mkdir_safe(data_dir)

        utils.create_script(
            os.path.join(job, 'run'),
            'spawn.run',
            id=inst.id,
            name=inst.name,
            cellapi=self.paths.cellapi_sock,
            zk2fs=self.paths.zk_mirror_dir)

        utils.create_script(
            os.path.join(job, 'finish'),
            'spawn.finish',
            id=inst.id,
            cellapi=self.paths.cellapi_sock,
            cleanup=self.paths.cleanup_dir,
            stop=inst.settings['stop'],
            reconnect=inst.settings['reconnect'],
            reconnect_timeout=inst.settings['reconnect_timeout'])

        with open(os.path.join(data_dir, 'manifest'), 'w') as f:
            json.dump(inst.manifest, f)

        with open(os.path.join(job, 'timeout-finish'), 'w') as f:
            f.write(str(spawn.JOB_FINISH_TIMEOUT))

        fs.symlink_safe(running, job)

        self._scan(bucket)
예제 #9
0
    def create(self):
        """Create the directory structure for the tree."""
        env = {
            'TREADMILL_SPAWN_ZK2FS': self.paths.zk_mirror_dir,
            'TREADMILL_SPAWN_ZK2FS_SHARDS':
            str(zknamespace.TRACE_SHARDS_COUNT),
            'TREADMILL_SPAWN_ZK2FS_SOW': apptrace.TRACE_SOW_DIR,
            'TREADMILL_SPAWN_CELLAPI_SOCK': self.paths.cellapi_sock,
            'TREADMILL_SPAWN_CLEANUP': self.paths.cleanup_dir,
        }
        supervisor.create_environ_dir(self.paths.env_dir, env)

        dirs = set()
        for bucket in range(self.buckets):
            bucket_formatted = spawn_utils.format_bucket(bucket)
            dirs.add(bucket_formatted)

            _LOGGER.debug('Adding bucket %r.', bucket_formatted)

            app = os.path.join(self.paths.svscan_tree_dir, bucket_formatted)
            log = os.path.join(app, 'log')

            running = os.path.join(self.paths.running_dir, bucket_formatted)
            svscan = os.path.join(running, '.s6-svscan')

            fs.mkdir_safe(app)
            fs.mkdir_safe(log)
            fs.mkdir_safe(running)
            fs.mkdir_safe(svscan)

            utils.create_script(os.path.join(app, 'run'),
                                's6.svscan.run',
                                max=self.max_per_bucket,
                                service_dir=running,
                                _alias=subproc.get_aliases())

            utils.create_script(os.path.join(log, 'run'),
                                's6.logger.run',
                                logdir='.',
                                _alias=subproc.get_aliases())

            utils.create_script(os.path.join(svscan, 'finish'),
                                's6.svscan.finish',
                                timeout=4800,
                                _alias=subproc.get_aliases())

        for app_dir in os.listdir(self.paths.svscan_tree_dir):
            if not app_dir.startswith('.') and app_dir not in dirs:
                path = os.path.join(self.paths.svscan_tree_dir, app_dir)
                _LOGGER.debug('Removing bucket (%r) %r.',
                              spawn.SVSCAN_TREE_DIR, path)
                shutil.rmtree(path, ignore_errors=True)

        for run_dir in os.listdir(self.paths.running_dir):
            if not run_dir.startswith('.') and run_dir not in dirs:
                path = os.path.join(self.paths.running_dir, run_dir)
                _LOGGER.debug('Removing bucket (%r))  %r.', spawn.RUNNING_DIR,
                              path)
                shutil.rmtree(path, ignore_errors=True)
예제 #10
0
    def _create_instance(self, path):
        """Create an spawn instance."""
        instance_path = self._get_instance_path(path)

        _LOGGER.debug('Creating - %r', instance_path)

        if os.path.exists(instance_path):
            return

        fs.mkdir_safe(instance_path)
        fs.mkdir_safe(os.path.join(instance_path, 'log'))

        utils.create_script(os.path.join(instance_path, 'run'),
                            'spawn.run',
                            manifest_path=path)

        utils.create_script(os.path.join(instance_path, 'finish'),
                            'spawn.finish',
                            manifest_path=path)

        utils.create_script(os.path.join(instance_path, 'log', 'run'),
                            'spawn.log.run')

        self._scan()
예제 #11
0
def create_supervision_tree(container_dir, app):
    """Creates s6 supervision tree."""
    # Disable R0915: Too many statements
    # pylint: disable=R0915
    root_dir = os.path.join(container_dir, 'root')

    # Services and sys directories will be restored when container restarts
    # with data retention on existing volume.
    #
    # Sys directories will be removed. Services directory will stay, which
    # present a danger of accumulating restart counters in finished files.
    #
    # TODO:
    #
    # It is rather arbitrary how restart counts should work when data is
    # restored, but most likely services are "restart always" policy, so it
    # will not affect them.
    services_dir = os.path.join(container_dir, 'services')
    sys_dir = os.path.join(container_dir, 'sys')
    if os.path.exists(sys_dir):
        _LOGGER.info('Deleting existing sys dir: %s', sys_dir)
        shutil.rmtree(sys_dir)

    app_json = os.path.join(root_dir, 'app.json')

    # Create /services directory for the supervisor
    svcdir = os.path.join(root_dir, 'services')
    fs.mkdir_safe(svcdir)

    fs.mkdir_safe(services_dir)
    fs.mount_bind(root_dir, '/services', services_dir)

    root_pw = pwd.getpwnam('root')
    proid_pw = pwd.getpwnam(app.proid)

    # Create .s6-svscan directories for svscan finish
    sys_svscandir = os.path.join(sys_dir, '.s6-svscan')
    fs.mkdir_safe(sys_svscandir)

    svc_svscandir = os.path.join(services_dir, '.s6-svscan')
    fs.mkdir_safe(svc_svscandir)

    # svscan finish scripts to wait on all services
    utils.create_script(os.path.join(sys_svscandir, 'finish'),
                        'svscan.finish',
                        timeout=6000)

    utils.create_script(os.path.join(svc_svscandir, 'finish'),
                        'svscan.finish',
                        timeout=5000)

    for svc in app.services:
        if getattr(svc, 'root', False):
            svc_user = '******'
            svc_home = root_pw.pw_dir
            svc_shell = root_pw.pw_shell
        else:
            svc_user = app.proid
            svc_home = proid_pw.pw_dir
            svc_shell = proid_pw.pw_shell

        supervisor.create_service(
            services_dir,
            svc_user,
            svc_home,
            svc_shell,
            svc.name,
            svc.command,
            env=app.environment,
            down=True,
            envdirs=['/environ/app', '/environ/sys'],
            as_root=True,
        )
        _create_logrun(os.path.join(services_dir, svc.name))

    for svc in app.system_services:
        supervisor.create_service(
            services_dir,
            'root',
            root_pw.pw_dir,
            root_pw.pw_shell,
            svc.name,
            svc.command,
            env=app.environment,
            down=False,
            envdirs=['/environ/sys'],
            as_root=True,
        )
        _create_logrun(os.path.join(services_dir, svc.name))

    # Vring services
    for cell in app.vring.cells:
        fs.mkdir_safe(os.path.join(sys_dir, 'vring.%s' % cell))
        cmd = '%s sproc --zookeeper - --cell %s vring %s' % (
            treadmill.TREADMILL_BIN, cell, app_json)
        utils.create_script(os.path.join(sys_dir, 'vring.%s' % cell, 'run'),
                            'supervisor.run_sys',
                            cmd=cmd)
        _create_logrun(os.path.join(sys_dir, 'vring.%s' % cell))

    # Create endpoint presence service
    presence_monitor_cmd = '%s sproc presence monitor %s %s' % (
        treadmill.TREADMILL_BIN, app_json, container_dir)
    presence_register_cmd = '%s sproc presence register %s %s' % (
        treadmill.TREADMILL_BIN, app_json, container_dir)
    shadow_etc = os.path.join(container_dir, 'overlay', 'etc')
    host_aliases_cmd = '%s sproc host-aliases --aliases-dir %s %s %s' % (
        treadmill.TREADMILL_BIN,
        os.path.join(shadow_etc, 'host-aliases'),
        os.path.join(shadow_etc, 'hosts.original'),
        os.path.join(shadow_etc, 'hosts'),
    )

    _create_sysrun(sys_dir, 'monitor', presence_monitor_cmd)
    _create_sysrun(sys_dir, 'register', presence_register_cmd)
    _create_sysrun(sys_dir, 'hostaliases', host_aliases_cmd)

    cmd = None
    args = None

    if hasattr(app, 'command'):
        cmd = app.command

    if hasattr(app, 'args'):
        args = app.args

    if not cmd:
        cmd = subproc.resolve('s6_svscan')
        if not args:
            args = ['/services']

    _create_sysrun(sys_dir,
                   'start_container',
                   '%s %s %s -m -p -i %s %s' %
                   (subproc.resolve('chroot'), root_dir,
                    subproc.resolve('pid1'), cmd, ' '.join(args)),
                   down=True)
예제 #12
0
def _create_logrun(directory):
    """Creates log directory with run file to start s6 logger."""
    fs.mkdir_safe(os.path.join(directory, 'log'))
    utils.create_script(os.path.join(directory, 'log', 'run'), 'logger.run')
예제 #13
0
def configure(tm_env, event):
    """Creates directory necessary for starting the application.

    This operation is idem-potent (it can be repeated).

    The directory layout is::

        - (treadmill root)
          - apps
            - (app unique name)
              - app.yml
                run
                finish

    The 'run' script is responsible for creating container environment
    and starting svscan inside the container.

    The 'finish' script is invoked when container terminates and will
    deallocate any resources (NAT rules, etc) that were allocated for the
    container.
    """
    # R0915: Need to refactor long function into smaller pieces.
    #
    # pylint: disable=R0915

    # Load the app from the event
    try:
        manifest_data = app_manifest.load(tm_env, event)
    except IOError:
        # File is gone. Nothing to do.
        _LOGGER.exception("No event to load: %r", event)
        return

    # Freeze the app data into a namedtuple object
    app = utils.to_obj(manifest_data)

    # Check the identity we are going to run as. It needs to exists on the host
    # or we will fail later on as we try to seteuid.
    try:
        pwd.getpwnam(app.proid)

    except KeyError:
        _LOGGER.exception('Unable to find proid %r in passwd database.',
                          app.proid)
        raise

    # Generate a unique name for the app
    uniq_name = appmgr.app_unique_name(app)

    # Create the app's running directory
    container_dir = os.path.join(tm_env.apps_dir, uniq_name)

    # We assume it is a 'resume' if the container directory already exists.
    is_resume = False
    try:
        os.makedirs(container_dir)
    except OSError as err:
        if err.errno == errno.EEXIST:
            _LOGGER.info('Resuming container %r', uniq_name)
            is_resume = True
        else:
            raise

    # Copy the event as 'manifest.yml' in the container dir
    shutil.copyfile(
        event,
        os.path.join(container_dir, 'manifest.yml')
    )

    # Setup the service clients
    cgroup_client = tm_env.svc_cgroup.make_client(
        os.path.join(container_dir, 'cgroups')
    )
    localdisk_client = tm_env.svc_localdisk.make_client(
        os.path.join(container_dir, 'localdisk')
    )
    network_client = tm_env.svc_network.make_client(
        os.path.join(container_dir, 'network')
    )

    # Store the app int the container_dir
    app_yml = os.path.join(container_dir, _APP_YML)
    with open(app_yml, 'w') as f:
        yaml.dump(manifest_data, stream=f)

    # Generate resources requests

    # Cgroup
    cgroup_req = {
        'memory': app.memory,
        'cpu': app.cpu,
    }
    # Local Disk
    localdisk_req = {
        'size': app.disk,
    }
    # Network
    network_req = {
        'environment': app.environment,
    }

    if not is_resume:
        cgroup_client.create(uniq_name, cgroup_req)
        localdisk_client.create(uniq_name, localdisk_req)

    else:
        cgroup_client.update(uniq_name, cgroup_req)
        localdisk_client.update(uniq_name, localdisk_req)

    if not app.shared_network:
        if not is_resume:
            network_client.create(uniq_name, network_req)
        else:
            network_client.update(uniq_name, network_req)

    # Mark the container as defaulting to down state
    utils.touch(os.path.join(container_dir, 'down'))

    # Generate the supervisor's run script
    app_run_cmd = ' '.join([
        os.path.join(treadmill.TREADMILL, 'bin', 'treadmill'),
        'sproc', 'run', container_dir
    ])

    run_out_file = os.path.join(container_dir, 'run.out')

    utils.create_script(os.path.join(container_dir, 'run'),
                        'supervisor.run_no_log',
                        log_out=run_out_file,
                        cmd=app_run_cmd)

    _init_log_file(run_out_file,
                   os.path.join(tm_env.apps_dir, "%s.run.out" % uniq_name))

    # Unique name for the link, based on creation time.
    cleanup_link = os.path.join(tm_env.cleanup_dir, uniq_name)
    finish_cmd = '/bin/ln -snvf %s %s' % (container_dir, cleanup_link)

    utils.create_script(os.path.join(container_dir, 'finish'),
                        'supervisor.finish',
                        service=app.name, proid=None,
                        cmds=[finish_cmd])

    appevents.post(
        tm_env.app_events_dir,
        events.ConfiguredTraceEvent(
            instanceid=app.name,
            uniqueid=app.uniqueid
        )
    )
    return container_dir
예제 #14
0
def configure(tm_env, event):
    """Creates directory necessary for starting the application.

    This operation is idem-potent (it can be repeated).

    The directory layout is::

        - (treadmill root)
          - apps
            - (app unique name)
              - app.yml
                run
                finish
                log/run

    The 'run' script is responsible for creating container environment
    and starting svscan inside the container.

    The 'finish' script is invoked when container terminates and will
    deallocate any resources (NAT rules, etc) that were allocated for the
    container.
    """
    # R0915: Need to refactor long function into smaller pieces.
    #
    # pylint: disable=R0915

    # Load the app from the event
    try:
        manifest_data = app_manifest.load(tm_env, event)
    except IOError:
        # File is gone. Nothing to do.
        _LOGGER.exception("No event to load: %r", event)
        return

    # Freeze the app data into a namedtuple object
    app = utils.to_obj(manifest_data)

    # Check the identity we are going to run as
    _check_identity(app.proid)

    # Generate a unique name for the app
    uniq_name = appcfg.app_unique_name(app)

    # Create the app's running directory
    container_dir = os.path.join(tm_env.apps_dir, uniq_name)

    if not fs.mkdir_safe(container_dir):
        _LOGGER.info('Resuming container %r', uniq_name)

    # Copy the event as 'manifest.yml' in the container dir
    shutil.copyfile(event, os.path.join(container_dir, 'manifest.yml'))

    # Store the app int the container_dir
    app_yml = os.path.join(container_dir, _APP_YML)
    with open(app_yml, 'w') as f:
        yaml.dump(manifest_data, stream=f)

    # Mark the container as defaulting to down state
    utils.touch(os.path.join(container_dir, 'down'))

    # Generate the supervisor's run script
    app_run_cmd = ' '.join(
        [treadmill.TREADMILL_BIN, 'sproc', 'run', container_dir])

    utils.create_script(os.path.join(container_dir, 'run'),
                        'supervisor.run_no_log',
                        cmd=app_run_cmd)

    fs.mkdir_safe(os.path.join(container_dir, 'log'))
    utils.create_script(os.path.join(container_dir, 'log', 'run'),
                        'logger.run')

    # Unique name for the link, based on creation time.
    cleanup_link = os.path.join(tm_env.cleanup_dir, uniq_name)
    if os.name == 'nt':
        finish_cmd = '%%COMSPEC%% /C mklink /D %s %s' % \
                     (cleanup_link, container_dir)
    else:
        finish_cmd = '/bin/ln -snvf %s %s' % (container_dir, cleanup_link)

    utils.create_script(os.path.join(container_dir, 'finish'),
                        'supervisor.finish',
                        service=app.name,
                        proid=None,
                        cmds=[finish_cmd])

    appevents.post(
        tm_env.app_events_dir,
        events.ConfiguredTraceEvent(instanceid=app.name,
                                    uniqueid=app.uniqueid))
    return container_dir