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)
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
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
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
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)