def rename_container(self, container, name): # TODO(emilien) podman doesn't support rename, we'll handle it # in paunch itself for now configs = self.list_configs() config_id, config = self.discover_container_config( configs, container, name) # Get config_data dict by the discovered conf ID, # paunch needs it for maintaining idempotency within a conf ID filter_names = ("[] | [?(Name!='%s' && " "Config.Labels.config_id=='%s')]" ".Name" % (container, config_id)) filter_cdata = ("[] | [?(Name!='%s' && " "Config.Labels.config_id=='%s')]" ".Config.Labels.config_data" % (container, config_id)) names = None cdata = None try: names = jmespath.search(filter_names, configs[config_id]) cdata = jmespath.search(filter_cdata, configs[config_id]) except jmespath.exceptions.LexerError: self.log.error("Failed to rename a container %s into %s: " "used a bad search pattern" % (container, name)) return if not names or not cdata: self.log.error("Failed to rename a container %s into %s: " "no config_data was found" % (container, name)) return # Rename the wanted container in the config_data fetched from the # discovered config config_data = dict(zip(names, map(json.loads, cdata))) config_data[name] = json.loads( config.get('Config').get('Labels').get('config_data')) # Re-apply a container under its amended name using the fetched configs self.log.debug("Renaming a container known as %s into %s, " "via re-applying its original config" % (container, name)) self.log.debug("Removing the destination container %s" % name) self.stop_container(name) self.remove_container(name) self.log.debug("Removing a container known as %s" % container) self.stop_container(container) self.remove_container(container) builder = podman.PodmanBuilder( config_id=config_id, config=config_data, runner=self, labels=None, log=self.log, cont_log_path=self.cont_log_path, healthcheck_disabled=self.healthcheck_disabled) builder.apply()
def apply(config_id, config, managed_by, labels=None, cont_cmd='podman', default_runtime=None, log_level=None, log_file=None, cont_log_path=None, healthcheck_disabled=False): """Execute supplied container configuration. :param str config_id: Unique config ID, should not be re-used until any running containers with that config ID have been deleted. :param dict config: Configuration data describing container actions to apply. :param str managed_by: Name of the tool managing the containers. Only containers labelled with this will be modified. :param dict labels: Optional keys/values of labels to apply to containers created with this invocation. :param str cont_cmd: Optional override to the container command to run. :param str default_runtime: (deprecated) does nothing. :param int log_level: optional log level for loggers :param str log_file: optional log file for messages :param str cont_log_path: optional log path for containers. Works only for podman engine. Must be an absolute path. :param bool healthcheck_disabled: optional boolean to disable container healthcheck. :returns (list, list, int) lists of stdout and stderr for each execution, and a single return code representing the overall success of the apply. :rtype: tuple """ log = common.configure_logging(__name__, log_level, log_file) if default_runtime: log.warning("DEPRECATION: 'default_runtime' does nothing, " "use 'cont_cmd' instead") if cont_cmd == 'podman': r = runner.PodmanRunner(managed_by, cont_cmd=cont_cmd, log=log) builder = podman.PodmanBuilder( config_id=config_id, config=config, runner=r, labels=labels, log=log, cont_log_path=cont_log_path, healthcheck_disabled=healthcheck_disabled ) else: r = runner.DockerRunner(managed_by, cont_cmd=cont_cmd, log=log) builder = compose1.ComposeV1Builder( config_id=config_id, config=config, runner=r, labels=labels, log=log ) return builder.apply()
def rename_container(self, container, name): # TODO(emilien) podman doesn't support rename, we'll handle it # in paunch itself for now # Find the "container's" config & conf ID in the known configs configs = self.list_configs() config_id, config = self.discover_container_config( configs, container, name) try: # Get the neighbors' config_data by the discovered conf ID, # paunch needs it for maintaining idempotency within a conf ID jquerry=("[] | [?(Name!='%s' && " "Config.Labels.config_id=='%s')]" ".Name" % (container, config_id)) names = jmespath.search(jquerry, configs[config_id]) jquerry=("[] | [?(Name!='%s' && " "Config.Labels.config_id=='%s')]" ".Config.Labels.config_data" % (container, config_id)) values = jmespath.search(jquerry, configs[config_id]) config_data = dict(zip(names, map(json.loads, values))) # Rename the wanted container in the config_data fetched from the # discovered config config_data[name] = json.loads( config.get('Config').get('Labels').get('config_data')) except Exception: self.log.error("Failed to rename a container %s into %s: " "no config_data was found" % (container, name)) return # Re-apply a container under its amended name using the fetched configs self.log.debug("Renaming a container known as %s into %s, " "via re-applying its original config" % (container, name)) self.log.debug("Removing the destination container %s" % name) self.stop_container(name) self.remove_container(name) self.log.debug("Removing a container known as %s" % container) self.stop_container(container) self.remove_container(container) builder = podman.PodmanBuilder( config_id=config_id, config=config_data, runner=self, labels=None, log=self.log ) builder.apply()
def test_cont_run_args(self): config = { 'one': { 'image': 'centos:7', 'privileged': True, 'user': '******', 'net': 'host', 'ipc': 'host', 'pid': 'container:bar', 'uts': 'host', 'restart': 'always', 'env_file': '/tmp/foo.env', 'log_tag': '{{.ImageName}}/{{.Name}}/{{.ID}}', 'cpu_shares': 600, 'mem_limit': '1G', 'memswap_limit': '1G', 'mem_swappiness': '60', 'security_opt': 'label:disable', 'cap_add': ['SYS_ADMIN', 'SETUID'], 'cap_drop': ['NET_RAW'], 'hostname': 'foohostname', 'extra_hosts': ['foohost:127.0.0.1', 'barhost:127.0.0.2'] } } builder = podman.PodmanBuilder('foo', config, None) cmd = ['podman', 'run', '--name', 'one'] builder.container_run_args(cmd, 'one') self.assertEqual([ 'podman', 'run', '--name', 'one', '--conmon-pidfile=/var/run/one.pid', '--detach=true', '--env-file=/tmp/foo.env', '--net=host', '--ipc=host', '--pid=container:bar', '--uts=host', '--privileged=true', '--user=bar', '--log-opt=tag={{.ImageName}}/{{.Name}}/{{.ID}}', '--cpu-shares=600', '--memory=1G', '--memory-swap=1G', '--memory-swappiness=60', '--security-opt=label:disable', '--hostname=foohostname', '--add-host=foohost:127.0.0.1', '--add-host=barhost:127.0.0.2', '--cap-add=SYS_ADMIN', '--cap-add=SETUID', '--cap-drop=NET_RAW', 'centos:7' ], cmd)
def debug(config_id, container_name, action, config, managed_by, labels=None, cont_cmd='podman', default_runtime=None, log_level=None, log_file=None): """Execute supplied container configuration. :param str config_id: Unique config ID, should not be re-used until any running containers with that config ID have been deleted. :param str container_name: Name of the container in the config you wish to manipulate. :param str action: Action to take. :param dict config: Configuration data describing container actions to apply. :param str managed_by: Name of the tool managing the containers. Only containers labeled with this will be modified. :param dict labels: Optional keys/values of labels to apply to containers created with this invocation. :param str cont_cmd: Optional override to the container command to run. :param str default_runtime: (deprecated) does nothing. :param int log_level: optional log level for loggers :param int log_file: optional log file for messages :returns integer return value from running command or failure for any other reason. :rtype: int """ log = common.configure_logging(__name__, log_level, log_file) if default_runtime: log.warning("DEPRECATION: 'default_runtime' does nothing, " "use 'cont_cmd' instead") if cont_cmd == 'podman': r = runner.PodmanRunner(managed_by, cont_cmd=cont_cmd, log=log) builder = podman.PodmanBuilder( config_id=config_id, config=config, runner=r, labels=labels, log=log ) else: r = runner.DockerRunner(managed_by, cont_cmd=cont_cmd, log=log) builder = compose1.ComposeV1Builder( config_id=config_id, config=config, runner=r, labels=labels, log=log ) if action == 'print-cmd': cmd = [ r.cont_cmd, 'run', '--name', r.unique_container_name(container_name) ] builder.container_run_args(cmd, container_name) print(' '.join(cmd)) elif action == 'run': cmd = [ r.cont_cmd, 'run', '--name', r.unique_container_name(container_name) ] builder.container_run_args(cmd, container_name) return r.execute_interactive(cmd, log) elif action == 'dump-yaml': print(yaml.safe_dump(config, default_flow_style=False)) elif action == 'dump-json': print(json.dumps(config, indent=4)) else: raise ValueError('action should be one of: "dump-json", "dump-yaml"', '"print-cmd", or "run"')