Example #1
0
def create_supervision_tree(tm_env, container_dir, root_dir, app,
                            cgroups_path):
    """Creates s6 supervision tree."""
    uniq_name = appcfg.app_unique_name(app)
    ctl_uds = os.path.join(os.sep, 'run', 'tm_ctl')
    tombstone_ctl_uds = os.path.join(ctl_uds, 'tombstone')

    sys_dir = os.path.join(container_dir, 'sys')

    try:
        old_system_services = [
            svc_name for svc_name in os.listdir(sys_dir)
            if (not svc_name.startswith('.')
                and os.path.isdir(os.path.join(sys_dir, svc_name)))
        ]
    except FileNotFoundError:
        old_system_services = []

    new_system_services = [svc_def.name for svc_def in app.system_services]

    for svc_name in set(old_system_services) - set(new_system_services):
        _LOGGER.info('Removing old system service: %s', svc_name)
        fs.rmtree_safe(os.path.join(sys_dir, svc_name))

    sys_scandir = supervisor.create_scan_dir(
        sys_dir,
        finish_timeout=6000,
        wait_cgroups=cgroups_path,
    )
    for svc_def in app.system_services:
        if svc_def.restart is not None:
            monitor_policy = {
                'limit': svc_def.restart.limit,
                'interval': svc_def.restart.interval,
                'tombstone': {
                    'uds': False,
                    'path': tm_env.services_tombstone_dir,
                    'id': '{},{}'.format(uniq_name, svc_def.name)
                }
            }
        else:
            monitor_policy = None

        supervisor.create_service(
            sys_scandir,
            name=svc_def.name,
            app_run_script=svc_def.command,
            userid='root',
            environ_dir=os.path.join(container_dir, _CONTAINER_ENV_DIR),
            environ={envvar.name: envvar.value
                     for envvar in svc_def.environ},
            environment=app.environment,
            downed=svc_def.downed,
            trace=None,
            monitor_policy=monitor_policy)
    sys_scandir.write()

    services_dir = os.path.join(container_dir, 'services')
    finish_commands = getattr(app, 'finish_commands', [])
    services_scandir = supervisor.create_scan_dir(
        services_dir, finish_timeout=5000, finish_commands=finish_commands)

    for svc_def in app.services:

        if svc_def.restart is not None:
            monitor_policy = {
                'limit': svc_def.restart.limit,
                'interval': svc_def.restart.interval,
                'tombstone': {
                    'uds': True,
                    'path': tombstone_ctl_uds,
                    'id': '{},{}'.format(uniq_name, svc_def.name)
                }
            }
        else:
            monitor_policy = None

        if svc_def.trace is not None:
            trace = {
                'instanceid': app.name,
                'uniqueid': app.uniqueid,
                'service': svc_def.name,
                'path': os.path.join(ctl_uds, 'appevents')
            }
        else:
            trace = None

        logger_template = getattr(svc_def, 'logger', 's6.app-logger.run')
        _LOGGER.info('Using logger: %s', logger_template)

        supervisor.create_service(
            services_scandir,
            name=svc_def.name,
            app_run_script=svc_def.command,
            userid=svc_def.proid,
            environ_dir='/' + _CONTAINER_ENV_DIR,
            environ={envvar.name: envvar.value
                     for envvar in svc_def.environ},
            environment=app.environment,
            downed=svc_def.downed,
            trace=trace if svc_def.trace else None,
            log_run_script=logger_template,
            monitor_policy=monitor_policy)
    services_scandir.write()

    # Create services startup script.
    boot_commands = getattr(app, 'boot_commands', [])
    templates.create_script(
        os.path.join(container_dir, 'services', supervisor.SVC_INIT_FILE),
        's6.init',
        boot_commands=boot_commands,
        _alias=subproc.get_aliases(),
    )

    # Bind the service directory in the container volume
    fs.mkdir_safe(os.path.join(root_dir, 'services'))
    fs_linux.mount_bind(root_dir,
                        os.path.join(os.sep, 'services'),
                        source=os.path.join(container_dir, 'services'),
                        recursive=False,
                        read_only=False)

    # Bind the ctrl directory in the container volume which has all the
    # unix domain sockets to communicate outside the container to treadmill
    fs.mkdir_safe(os.path.join(root_dir, 'run', 'tm_ctl'))
    fs_linux.mount_bind(root_dir,
                        os.path.join(os.sep, 'run', 'tm_ctl'),
                        source=tm_env.ctl_dir,
                        recursive=False,
                        read_only=False)
Example #2
0
def _create_service_winss(base_dir,
                          name,
                          app_run_script,
                          downed=False,
                          environ=None,
                          monitor_policy=None,
                          timeout_finish=None,
                          run_script='winss.run',
                          log_run_script='winss.logger.run',
                          finish_script='winss.finish',
                          **kwargs):
    """Initializes service directory.

    Creates run, finish scripts as well as log directory with appropriate
    run script.
    """
    if isinstance(base_dir, sup_impl.ScanDir):
        # We are given a scandir as base, use it.
        svc = base_dir.add_service(name, _service_base.ServiceType.LongRun)
    else:
        svc = LongrunService(base_dir, name)

    # Setup the environ
    if environ is None:
        svc_environ = {}
    else:
        svc_environ = environ.copy()

    svc.environ = svc_environ

    monitored = (monitor_policy is not None)

    # Setup the run script
    svc.run_script = utils.generate_template(run_script,
                                             app_run_script=app_run_script,
                                             _alias=subproc.get_aliases())
    # Setup the finish script
    svc.finish_script = utils.generate_template(finish_script,
                                                _alias=subproc.get_aliases())

    logdir = os.path.join(svc.data_dir, 'log')
    fs.mkdir_safe(logdir)

    if log_run_script is not None:
        # Setup the log run script
        svc.log_run_script = utils.generate_template(
            log_run_script,
            logdir=os.path.relpath(logdir, svc.logger_dir),
            _alias=subproc.get_aliases())

    svc.default_down = bool(downed)
    if monitored:
        svc.timeout_finish = 0
    else:
        svc.timeout_finish = timeout_finish

    svc.write()

    # Optionally write a monitor policy file
    if monitor_policy is not None:
        exits_dir = os.path.join(svc.data_dir, EXITS_DIR)
        fs.mkdir_safe(exits_dir)
        fs.rm_children_safe(exits_dir)

        supervisor_utils.data_write(os.path.join(svc.data_dir, POLICY_JSON),
                                    json.dumps(monitor_policy))

    return svc
Example #3
0
def _create_service_s6(base_dir,
                       name,
                       app_run_script,
                       userid='root',
                       downed=False,
                       environ_dir=None,
                       environ=None,
                       environment='prod',
                       monitor_policy=None,
                       trace=None,
                       timeout_finish=None,
                       notification_fd=None,
                       call_before_run=None,
                       call_before_finish=None,
                       run_script='s6.run',
                       log_run_script='s6.logger.run',
                       finish_script='s6.finish',
                       logger_args=None,
                       ionice_prio=None,
                       **kwargs):
    """Initializes service directory.

    Creates run, finish scripts as well as log directory with appropriate
    run script.
    """
    # Disable R0912: Too many branches
    # pylint: disable=R0912
    try:
        home_dir = utils.get_userhome(userid)
        shell = utils.get_usershell(userid)

    except KeyError:
        # 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.
        _LOGGER.exception('Unable to find userid %r in passwd database.',
                          userid)
        raise

    if isinstance(base_dir, sup_impl.ScanDir):
        # We are given a scandir as base, use it.
        svc = base_dir.add_service(name, _service_base.ServiceType.LongRun)
    else:
        svc = LongrunService(base_dir, name)

    # Setup the environ
    if environ is None:
        svc_environ = {}
    else:
        svc_environ = environ.copy()
    svc_environ['HOME'] = home_dir
    svc.environ = svc_environ

    if ionice_prio is None:
        if environment == 'prod':
            ionice_prio = 5
        else:
            ionice_prio = 6

    # Setup the run script
    svc.run_script = templates.generate_template(
        run_script,
        user=userid,
        shell=shell,
        environ_dir=environ_dir,
        trace=trace,
        ionice_prio=ionice_prio,
        call_before_run=call_before_run,
        _alias=subproc.get_aliases())

    if monitor_policy is not None or call_before_finish is not None:
        # Setup the finish script
        svc.finish_script = templates.generate_template(
            finish_script,
            monitor_policy=monitor_policy,
            trace=trace,
            call_before_finish=call_before_finish,
            _alias=subproc.get_aliases())

    if log_run_script is not None:
        if logger_args is None:
            logger_args = '-b -p T n20 s1000000'

        # Setup the log run script
        svc.log_run_script = templates.generate_template(
            log_run_script,
            logdir=os.path.relpath(os.path.join(svc.data_dir, 'log'),
                                   svc.logger_dir),
            logger_args=logger_args,
            _alias=subproc.get_aliases())

    svc.default_down = bool(downed)
    svc.notification_fd = notification_fd

    if monitor_policy is not None:
        svc.timeout_finish = 0
        if monitor_policy['limit'] > 0:
            exits_dir = os.path.join(svc.data_dir, EXITS_DIR)
            fs.mkdir_safe(exits_dir)
            fs.rm_children_safe(exits_dir)
    else:
        svc.timeout_finish = timeout_finish

    svc.write()

    # Write the app_start script
    supervisor_utils.script_write(os.path.join(svc.data_dir, 'app_start'),
                                  app_run_script)

    return svc
Example #4
0
def _create_service_s6(base_dir,
                       name,
                       app_run_script,
                       userid='root',
                       downed=False,
                       environ_dir=None,
                       environ=None,
                       environment='prod',
                       monitor_policy=None,
                       trace=None,
                       timeout_finish=None,
                       run_script='s6.run',
                       log_run_script='s6.logger.run',
                       finish_script='s6.finish',
                       **kwargs):
    """Initializes service directory.

    Creates run, finish scripts as well as log directory with appropriate
    run script.
    """
    try:
        user_pw = pwd.getpwnam(userid)

    except KeyError:
        # 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.
        _LOGGER.exception('Unable to find userid %r in passwd database.',
                          userid)
        raise

    if isinstance(base_dir, sup_impl.ScanDir):
        # We are given a scandir as base, use it.
        svc = base_dir.add_service(name, _service_base.ServiceType.LongRun)
    else:
        svc = LongrunService(base_dir, name)

    # Setup the environ
    if environ is None:
        svc_environ = {}
    else:
        svc_environ = environ.copy()
    svc_environ['HOME'] = user_pw.pw_dir
    svc.environ = svc_environ

    if environment == 'prod':
        ionice_prio = 5
    else:
        ionice_prio = 6

    monitored = (monitor_policy is not None)

    # Setup the run script
    svc.run_script = utils.generate_template(run_script,
                                             user=userid,
                                             shell=user_pw.pw_shell,
                                             environ_dir=environ_dir,
                                             monitored=monitored,
                                             ionice_prio=ionice_prio,
                                             _alias=subproc.get_aliases())
    # Setup the finish script
    svc.finish_script = utils.generate_template(finish_script,
                                                _alias=subproc.get_aliases())

    if log_run_script is not None:
        # Setup the log run script
        svc.log_run_script = utils.generate_template(
            log_run_script,
            logdir=os.path.relpath(os.path.join(svc.data_dir, 'log'),
                                   svc.logger_dir),
            _alias=subproc.get_aliases())

    svc.default_down = bool(downed)
    if monitored:
        svc.timeout_finish = 0
    else:
        svc.timeout_finish = timeout_finish

    svc.write()

    # Write the app_start script
    supervisor_utils.script_write(os.path.join(svc.data_dir, 'app_start'),
                                  app_run_script)
    # Optionally write a monitor policy file
    _LOGGER.info('monitor_policy, %r', monitor_policy)
    if monitor_policy is not None:
        exits_dir = os.path.join(svc.data_dir, EXITS_DIR)
        fs.mkdir_safe(exits_dir)
        fs.rm_children_safe(exits_dir)

        supervisor_utils.data_write(os.path.join(svc.data_dir, POLICY_JSON),
                                    json.dumps(monitor_policy))
    # Optionally write trace information file
    if trace is not None:
        supervisor_utils.data_write(os.path.join(svc.data_dir, TRACE_FILE),
                                    json.dumps(trace))

    return svc
Example #5
0
def install(package, dst_dir, params, run=None, profile=None):
    """Installs the services.
    """
    _LOGGER.info('install: %s - %s, profile: %s', package, dst_dir, profile)

    packages = [package]

    module = plugin_manager.load('treadmill.bootstrap', package)
    extension_module = None
    if profile:
        _LOGGER.info('Installing profile: %s', profile)
        extension_name = '{}.{}'.format(package, profile)
        packages.append(extension_name)

        try:
            extension_module = plugin_manager.load('treadmill.bootstrap',
                                                   extension_name)
        except KeyError:
            _LOGGER.info('Extension not defined: %s, profile: %s', package,
                         profile)

    subproc.load_packages(packages, lazy=False)

    # Store resolved aliases
    aliases_path = os.path.join(dst_dir, '.aliases.json')
    aliases = subproc.get_aliases()
    with io.open(aliases_path, 'w') as f_aliases:
        f_aliases.write(json.dumps(aliases))

    defaults = {}
    defaults.update(getattr(module, 'DEFAULTS', {}))

    if extension_module:
        defaults.update(getattr(extension_module, 'DEFAULTS', {}))

    # TODO: this is ugly, error prone and should go away.
    #       aliases should be in default scope, everything else in _args.
    defaults['_alias'] = aliases
    defaults.update(aliases)
    defaults.update(params)

    defaults['aliases_path'] = aliases_path
    os.environ['TREADMILL_ALIASES_PATH'] = defaults['aliases_path']

    interpolated = _interpolate(defaults, defaults)

    fs.mkdir_safe(dst_dir)
    with io.open(os.path.join(dst_dir, '.install'), 'w') as rec:

        _install(module, PLATFORM, dst_dir, interpolated, rec=rec)

        if extension_module:
            _install(extension_module,
                     '.'.join([profile, PLATFORM]),
                     dst_dir,
                     interpolated,
                     rec=rec)

    # Extract logging configuration.
    logconf_dir = os.path.join(dst_dir, 'logging')
    fs.mkdir_safe(logconf_dir)
    tm_logging.write_configs(logconf_dir)

    # Write entry-point cache
    distributions = pkg_resources.AvailableDistributions()

    plugin_manager.dump_cache(os.path.join(dst_dir, 'plugins.json'),
                              distributions)

    if run:
        _run(run)