# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import argparse from contextlib import closing import io import os import tarfile import time import yaml from oslo_serialization import jsonutils from zunclient.common import cliutils as utils from zunclient.common import utils as zun_utils from zunclient.common.websocketclient import exceptions from zunclient.common.websocketclient import websocketclient from zunclient import exceptions as exc RENAME_DEPRECATION_MESSAGE = ( 'WARNING: Rename container command deprecated and will be removed ' 'in a future release.\nUse Update container command to avoid ' 'seeing this message.') SG_DEPRECATION_MESSAGE = ( 'WARNING: Security group related commands deprecated and will be removed ' 'in a future release.\nUse Neutron commands to manage security groups ' 'instead.') def _show_container(container): zun_utils.format_container_addresses(container) utils.print_dict(container._info) @utils.exclusive_arg( 'restart_auto_remove', '--auto-remove', required=False, action='store_true', help='Automatically remove the container when it exits') @utils.exclusive_arg( 'restart_auto_remove', '--restart', required=False, metavar='', help='Restart policy to apply when a container exits' '(no, on-failure[:max-retry], always, unless-stopped)') @utils.exclusive_arg( 'secgroup_expose_port', '--security-group', metavar='', action='append', default=[], help='The name of security group for the container. ' 'May be used multiple times.') @utils.exclusive_arg( 'secgroup_expose_port', '-p', '--expose-port', action='append', default=[], metavar='', help='Expose container port(s) to outside (format: [/])') @utils.arg('-n', '--name', metavar='', help='name of the container') @utils.arg('--cpu', metavar='', help='The number of virtual cpus.') @utils.arg('-m', '--memory', metavar='', help='The container memory size in MiB') @utils.arg('-e', '--environment', metavar='', action='append', default=[], help='The environment variables') @utils.arg('--workdir', metavar='', help='The working directory for commands to run in') @utils.arg('--label', metavar='', action='append', default=[], help='Adds a map of labels to a container. ' 'May be used multiple times.') @utils.arg('--image-pull-policy', dest='image_pull_policy', metavar='', choices=['never', 'always', 'ifnotpresent'], help='The policy which determines if the image should ' 'be pulled prior to starting the container. ' 'It can have following values: ' '"ifnotpresent": only pull the image if it does not ' 'already exist on the node. ' '"always": Always pull the image from repository.' '"never": never pull the image') @utils.arg('image', metavar='', help='name or ID or repo of the image ' '(e.g. cirros:latest)') @utils.arg('-i', '--interactive', dest='interactive', action='store_true', default=False, help='Keep STDIN open even if not attached, allocate a pseudo-TTY') @utils.arg('--image-driver', metavar='', help='The image driver to use to pull container image. ' 'It can have following values: ' '"docker": pull the image from Docker Hub. ' '"glance": pull the image from Glance. ') @utils.arg('command', metavar='', nargs=argparse.REMAINDER, help='Send command to the container') @utils.arg('--hint', action='append', default=[], metavar='', help='The key-value pair(s) for scheduler to select host. ' 'The format of this parameter is "key=value[,key=value]". ' 'May be used multiple times.') @utils.arg('--net', action='append', default=[], metavar='', help='Create network enpoints for the container. ' 'network: attach container to the specified neturon networks. ' 'port: attach container to the neutron port with this UUID. ' 'v4-fixed-ip: IPv4 fixed address for container. ' 'v6-fixed-ip: IPv6 fixed address for container.') @utils.arg('--mount', action='append', default=[], metavar='', help='A dictionary to configure volumes mounted inside the ' 'container.') @utils.arg('--runtime', metavar='', help='The runtime to use for this container. ' 'It can have value "runc" or any other custom runtime.') @utils.arg('--hostname', metavar='', default=None, help='Container host name') @utils.arg('--disk', metavar='', type=int, default=None, help='The disk size in GiB for per container.') @utils.arg('--availability-zone', metavar='', default=None, help='The availability zone of the container.') @utils.arg('--auto-heal', action='store_true', default=False, help='The flag of healing non-existent container in docker.') @utils.arg('--privileged', dest='privileged', action='store_true', default=False, help='Give extended privileges to this container') @utils.arg('--healthcheck', action='append', default=[], metavar='', help='Specify a test cmd to perform to check that the container' 'is healthy. ' 'cmd: Command to run to check health. ' 'interval: Time between running the check (s|m|h)' ' (default 0s). ' 'retries: Consecutive failures needed to report unhealthy. ' 'timeout: Maximum time to allow one check to run (s|m|h)' ' (default 0s).') @utils.arg('--registry', metavar='', help='The container image registry ID or name') @utils.arg('--host', metavar='', help='Requested host to create containers. Admin only by default.' '(Supported by API versions 1.39 or above)') @utils.arg('--entrypoint', metavar='', help='The entrypoint which overwrites the default ENTRYPOINT ' 'of the image. (Supported by API versions 1.40 or above)') def do_create(cs, args): """Create a container.""" opts = {} opts['name'] = args.name opts['image'] = args.image opts['memory'] = args.memory opts['cpu'] = args.cpu opts['environment'] = zun_utils.format_args(args.environment) opts['auto_remove'] = args.auto_remove opts['workdir'] = args.workdir opts['labels'] = zun_utils.format_args(args.label) opts['image_pull_policy'] = args.image_pull_policy opts['image_driver'] = args.image_driver opts['hints'] = zun_utils.format_args(args.hint) opts['nets'] = zun_utils.parse_nets(args.net) opts['mounts'] = zun_utils.parse_mounts(args.mount) opts['runtime'] = args.runtime opts['hostname'] = args.hostname opts['disk'] = args.disk opts['availability_zone'] = args.availability_zone opts['command'] = args.command opts['registry'] = args.registry opts['host'] = args.host opts['entrypoint'] = zun_utils.parse_entrypoint(args.entrypoint) if args.healthcheck: opts['healthcheck'] = zun_utils.parse_health(args.healthcheck) if args.auto_heal: opts['auto_heal'] = args.auto_heal if args.security_group: opts['security_groups'] = args.security_group if args.expose_port: opts['exposed_ports'] = zun_utils.parse_exposed_ports(args.expose_port) if args.restart: opts['restart_policy'] = zun_utils.check_restart_policy(args.restart) if args.interactive: opts['interactive'] = True if args.privileged: opts['privileged'] = True opts = zun_utils.remove_null_parms(**opts) _show_container(cs.containers.create(**opts)) @utils.arg('--all-projects', action="store_true", default=False, help='List containers in all projects') @utils.arg('--marker', metavar='', default=None, help='The last container UUID of the previous page; ' 'displays list of containers after "marker".') @utils.arg('--limit', metavar='', type=int, help='Maximum number of containers to return') @utils.arg('--sort-key', metavar='', help='Column to sort results by') @utils.arg('--sort-dir', metavar='', choices=['desc', 'asc'], help='Direction to sort. "asc" or "desc".') @utils.arg('--name', metavar='', help='List containers according to their name.') @utils.arg('--image', metavar='', help='List containers according to their image.') @utils.arg('--project-id', metavar='', help='List containers according to their Project_id') @utils.arg('--user-id', metavar='', help='List containers according to their user_id') @utils.arg('--task-state', metavar='', help='List containers according to their task-state') @utils.arg('--status', metavar='', help='List containers according to their status') @utils.arg('--memory', metavar='', help='List containers according to their memory size in MiB') @utils.arg('--host', metavar='', help='List containers according to their hostname') @utils.arg('--auto-remove', metavar='', help='List containers according to whether they are ' 'auto-removed on exiting') def do_list(cs, args): """Print a list of available containers.""" opts = {} opts['all_projects'] = args.all_projects opts['marker'] = args.marker opts['limit'] = args.limit opts['sort_key'] = args.sort_key opts['sort_dir'] = args.sort_dir opts['image'] = args.image opts['name'] = args.name opts['project_id'] = args.project_id opts['user_id'] = args.user_id opts['host'] = args.host opts['task_state'] = args.task_state opts['memory'] = args.memory opts['auto_remove'] = args.auto_remove opts['status'] = args.status opts = zun_utils.remove_null_parms(**opts) containers = cs.containers.list(**opts) zun_utils.list_containers(containers) @utils.arg('containers', metavar='', nargs='+', help='ID or name of the (container)s to delete.') @utils.arg('-f', '--force', action='store_true', help='Force delete the container.') @utils.arg('-s', '--stop', action='store_true', help='Stop the running container first before delete.') @utils.arg('--all-projects', action="store_true", default=False, help='Delete container(s) in all projects by name.') def do_delete(cs, args): """Delete specified containers.""" for container in args.containers: opts = {} opts['id'] = container opts['force'] = args.force opts['stop'] = args.stop opts['all_projects'] = args.all_projects opts = zun_utils.remove_null_parms(**opts) try: cs.containers.delete(**opts) print("Request to delete container %s has been accepted." % container) except Exception as e: print("Delete for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('container', metavar='', help='ID or name of the container to show.') @utils.arg('-f', '--format', metavar='', action='store', choices=['json', 'yaml', 'table'], default='table', help='Print representation of the container.' 'The choices of the output format is json,table,yaml.' 'Defaults to table.') @utils.arg('--all-projects', action="store_true", default=False, help='Show container(s) in all projects by name.') def do_show(cs, args): """Show details of a container.""" opts = {} opts['id'] = args.container opts['all_projects'] = args.all_projects opts = zun_utils.remove_null_parms(**opts) container = cs.containers.get(**opts) if args.format == 'json': print(jsonutils.dumps(container._info, indent=4, sort_keys=True)) elif args.format == 'yaml': print(yaml.safe_dump(container._info, default_flow_style=False)) elif args.format == 'table': _show_container(container) @utils.arg('containers', metavar='', nargs='+', help='ID of the (container)s to rebuild.') @utils.arg('--image', metavar='', help='The image for specified container to update.') @utils.arg('--image-driver', metavar='', help='The image driver to use to pull container image. ' 'It can have following values: ' '"docker": pull the image from Docker Hub. ' '"glance": pull the image from Glance. ' 'The default value is source container\'s image driver ') def do_rebuild(cs, args): """Rebuild specified containers.""" for container in args.containers: opts = {} opts['id'] = container if args.image: opts['image'] = args.image if args.image_driver: opts['image_driver'] = args.image_driver try: cs.containers.rebuild(**opts) print("Request to rebuild container %s has been accepted." % container) except Exception as e: print("Rebuild for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('containers', metavar='', nargs='+', help='ID or name of the (container)s to restart.') @utils.arg('-t', '--timeout', metavar='', default=10, help='Seconds to wait for stop before restarting (container)s') def do_restart(cs, args): """Restart specified containers.""" for container in args.containers: try: cs.containers.restart(container, args.timeout) print("Request to restart container %s has been accepted." % container) except Exception as e: print("Restart for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('containers', metavar='', nargs='+', help='ID or name of the (container)s to stop.') @utils.arg('-t', '--timeout', metavar='', default=10, help='Seconds to wait for stop before killing (container)s') def do_stop(cs, args): """Stop specified containers.""" for container in args.containers: try: cs.containers.stop(container, args.timeout) print("Request to stop container %s has been accepted." % container) except Exception as e: print("Stop for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('containers', metavar='', nargs='+', help='ID of the (container)s to start.') def do_start(cs, args): """Start specified containers.""" for container in args.containers: try: cs.containers.start(container) print("Request to start container %s has been accepted." % container) except Exception as e: print("Start for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('containers', metavar='', nargs='+', help='ID or name of the (container)s to pause.') def do_pause(cs, args): """Pause specified containers.""" for container in args.containers: try: cs.containers.pause(container) print("Request to pause container %s has been accepted." % container) except Exception as e: print("Pause for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('containers', metavar='', nargs='+', help='ID or name of the (container)s to unpause.') def do_unpause(cs, args): """Unpause specified containers.""" for container in args.containers: try: cs.containers.unpause(container) print("Request to unpause container %s has been accepted." % container) except Exception as e: print("Unpause for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.arg('container', metavar='', help='ID or name of the container to get logs for.') @utils.arg('--stdout', action='store_true', help='Only stdout logs of container.') @utils.arg('--stderr', action='store_true', help='Only stderr logs of container.') @utils.arg('--since', metavar='', default=None, help='Show logs since a given datetime or integer ' 'epoch (in seconds).') @utils.arg('-t', '--timestamps', dest='timestamps', action='store_true', default=False, help='Show timestamps.') @utils.arg('--tail', metavar='', default='all', help='Number of lines to show from the end of the logs.') def do_logs(cs, args): """Get logs of a container.""" opts = {} opts['id'] = args.container opts['stdout'] = args.stdout opts['stderr'] = args.stderr opts['since'] = args.since opts['timestamps'] = args.timestamps opts['tail'] = args.tail opts = zun_utils.remove_null_parms(**opts) logs = cs.containers.logs(**opts) print(logs) @utils.arg('container', metavar='', help='ID or name of the container to execute command in.') @utils.arg('command', metavar='', nargs=argparse.REMAINDER, help='The command to execute in a container') @utils.arg('-i', '--interactive', dest='interactive', action='store_true', default=False, help='Keep STDIN open and allocate a pseudo-TTY for interactive') def do_exec(cs, args): """Execute command in a running container.""" opts = {} opts['command'] = zun_utils.parse_command(args.command) if args.interactive: opts['interactive'] = True opts['run'] = False response = cs.containers.execute(args.container, **opts) if args.interactive: exec_id = response['exec_id'] url = response['proxy_url'] websocketclient.do_exec(cs, url, args.container, exec_id, "~", 0.5) else: output = response['output'] exit_code = response['exit_code'] print(output) return exit_code @utils.arg('containers', metavar='', nargs='+', help='ID or name of the (container)s to kill signal to.') @utils.arg('-s', '--signal', metavar='', default=None, help='The signal to kill') def do_kill(cs, args): """Kill one or more running container(s).""" for container in args.containers: opts = {} opts['id'] = container opts['signal'] = args.signal opts = zun_utils.remove_null_parms(**opts) try: cs.containers.kill(**opts) print( "Request to kill signal to container %s has been accepted." % container) except Exception as e: print( "kill signal for container %(container)s failed: %(e)s" % {'container': container, 'e': e}) @utils.exclusive_arg( 'restart_auto_remove', '--auto-remove', required=False, action='store_true', help='Automatically remove the container when it exits') @utils.exclusive_arg( 'restart_auto_remove', '--restart', required=False, metavar='', help='Restart policy to apply when a container exits' '(no, on-failure[:max-retry], always, unless-stopped)') @utils.exclusive_arg( 'secgroup_expose_port', '--security-group', metavar='', action='append', default=[], help='The name of security group for the container. ' 'May be used multiple times.') @utils.exclusive_arg( 'secgroup_expose_port', '-p', '--expose-port', action='append', default=[], metavar='', help='Expose container port(s) to outside (format: [/])') @utils.arg('-n', '--name', metavar='', help='name of the container') @utils.arg('--cpu', metavar='', help='The number of virtual cpus.') @utils.arg('-m', '--memory', metavar='', help='The container memory size in MiB') @utils.arg('-e', '--environment', metavar='', action='append', default=[], help='The environment variables') @utils.arg('--workdir', metavar='', help='The working directory for commands to run in') @utils.arg('--label', metavar='', action='append', default=[], help='Adds a map of labels to a container. ' 'May be used multiple times.') @utils.arg('--image-pull-policy', dest='image_pull_policy', metavar='', choices=['never', 'always', 'ifnotpresent'], help='The policy which determines if the image should ' 'be pulled prior to starting the container. ' 'It can have following values: ' '"ifnotpresent": only pull the image if it does not ' 'already exist on the node. ' '"always": Always pull the image from repository.' '"never": never pull the image') @utils.arg('image', metavar='', help='name or ID of the image') @utils.arg('-i', '--interactive', dest='interactive', action='store_true', default=False, help='Keep STDIN open even if not attached, allocate a pseudo-TTY') @utils.arg('--image-driver', metavar='', help='The image driver to use to pull container image. ' 'It can have following values: ' '"docker": pull the image from Docker Hub. ' '"glance": pull the image from Glance. ') @utils.arg('command', metavar='', nargs=argparse.REMAINDER, help='Send command to the container') @utils.arg('--hint', action='append', default=[], metavar='', help='The key-value pair(s) for scheduler to select host. ' 'The format of this parameter is "key=value[,key=value]". ' 'May be used multiple times.') @utils.arg('--net', action='append', default=[], metavar='', help='Create network enpoints for the container. ' 'network: attach container to the specified neutron networks. ' 'port: attach container to the neutron port with this UUID. ' 'v4-fixed-ip: IPv4 fixed address for container. ' 'v6-fixed-ip: IPv6 fixed address for container.') @utils.arg('--mount', action='append', default=[], metavar='', help='A dictionary to configure volumes mounted inside the ' 'container.') @utils.arg('--runtime', metavar='', help='The runtime to use for this container. ' 'It can have value "runc" or any other custom runtime.') @utils.arg('--hostname', metavar='', default=None, help='Container hostname') @utils.arg('--disk', metavar='', type=int, default=None, help='The disk size in GiB for per container.') @utils.arg('--availability-zone', metavar='', default=None, help='The availability zone of the container.') @utils.arg('--auto-heal', action='store_true', default=False, help='The flag of healing non-existent container in docker.') @utils.arg('--privileged', dest='privileged', action='store_true', default=False, help='Give extended privileges to this container') @utils.arg('--healthcheck', action='append', default=[], metavar='', help='Specify a test cmd to perform to check that the container' 'is healthy. ' 'cmd: Command to run to check health. ' 'interval: Time between running the check (s|m|h)' ' (default 0s). ' 'retries: Consecutive failures needed to report unhealthy. ' 'timeout: Maximum time to allow one check to run (s|m|h)' ' (default 0s).') @utils.arg('--registry', metavar='', help='The container image registry ID or name') @utils.arg('--host', metavar='', help='Requested host to run containers. Admin only by default.' '(Supported by API versions 1.39 or above)') @utils.arg('--entrypoint', metavar='', help='The entrypoint which overwrites the default ENTRYPOINT ' 'of the image. (Supported by API versions 1.40 or above)') def do_run(cs, args): """Run a command in a new container.""" opts = {} opts['name'] = args.name opts['image'] = args.image opts['memory'] = args.memory opts['cpu'] = args.cpu opts['environment'] = zun_utils.format_args(args.environment) opts['workdir'] = args.workdir opts['auto_remove'] = args.auto_remove opts['labels'] = zun_utils.format_args(args.label) opts['image_pull_policy'] = args.image_pull_policy opts['image_driver'] = args.image_driver opts['hints'] = zun_utils.format_args(args.hint) opts['nets'] = zun_utils.parse_nets(args.net) opts['mounts'] = zun_utils.parse_mounts(args.mount) opts['runtime'] = args.runtime opts['hostname'] = args.hostname opts['disk'] = args.disk opts['availability_zone'] = args.availability_zone opts['command'] = args.command opts['registry'] = args.registry opts['host'] = args.host opts['entrypoint'] = zun_utils.parse_entrypoint(args.entrypoint) if args.healthcheck: opts['healthcheck'] = zun_utils.parse_health(args.healthcheck) if args.auto_heal: opts['auto_heal'] = args.auto_heal if args.security_group: opts['security_groups'] = args.security_group if args.expose_port: opts['exposed_ports'] = zun_utils.parse_exposed_ports(args.expose_port) if args.restart: opts['restart_policy'] = zun_utils.check_restart_policy(args.restart) if args.interactive: opts['interactive'] = True if args.privileged: opts['privileged'] = True opts = zun_utils.remove_null_parms(**opts) container = cs.containers.run(**opts) _show_container(container) container_uuid = getattr(container, 'uuid', None) if args.interactive: ready_for_attach = False while True: container = cs.containers.get(container_uuid) if zun_utils.check_container_status(container, 'Running'): ready_for_attach = True break if zun_utils.check_container_status(container, 'Error'): raise exceptions.ContainerStateError(container_uuid) print("Waiting for container start") time.sleep(1) if ready_for_attach is True: response = cs.containers.attach(container_uuid) websocketclient.do_attach(cs, response, container_uuid, "~", 0.5) else: raise exceptions.InvalidWebSocketLink(container_uuid) @utils.arg('container', metavar='', help="ID or name of the container to update.") @utils.arg('--cpu', metavar='', help='The number of virtual cpus.') @utils.arg('-m', '--memory', metavar='', help='The container memory size in MiB') @utils.arg('--name', metavar='', help='The new name for the container') @utils.exclusive_arg( 'auto_heal_value', '--auto-heal', required=False, action='store_true', help='Automatic recovery the status of contaier') @utils.exclusive_arg( 'auto_heal_value', '--no-auto-heal', required=False, action='store_true', help='Needless recovery the status of contaier') def do_update(cs, args): """Update one or more attributes of the container.""" opts = {} opts['memory'] = args.memory opts['cpu'] = args.cpu opts['name'] = args.name if 'auto_heal' in args and args.auto_heal: opts['auto_heal'] = True if 'no_auto_heal' in args and args.no_auto_heal: opts['auto_heal'] = False opts = zun_utils.remove_null_parms(**opts) if not opts: raise exc.CommandError("You must update at least one property") container = cs.containers.update(args.container, **opts) _show_container(container) @utils.deprecated(RENAME_DEPRECATION_MESSAGE) @utils.arg('container', metavar='', help='ID or name of the container to rename.') @utils.arg('name', metavar='', help='The new name for the container') def do_rename(cs, args): """Rename a container.""" cs.containers.rename(args.container, args.name) @utils.arg('container', metavar='', help='ID or name of the container to be attached to.') def do_attach(cs, args): """Attach to a running container.""" response = cs.containers.attach(args.container) websocketclient.do_attach(cs, response, args.container, "~", 0.5) @utils.arg('container', metavar='', help='ID or name of the container to display processes.') @utils.arg('--pid', metavar='', action='append', default=[], help='The args of the ps id.') def do_top(cs, args): """Display the running processes inside the container.""" if args.pid: # List container single ps id top result output = cs.containers.top(args.container, ' '.join(args.pid)) else: # List container all processes top result output = cs.containers.top(args.container) for titles in output['Titles']: print("%-20s") % titles, if output['Processes']: for process in output['Processes']: print("") for info in process: print("%-20s") % info, else: print("") @utils.arg('source', metavar='', help='The source should be copied to the container or localhost. ' 'The format of this parameter is [container:]src_path.') @utils.arg('destination', metavar='', help='The directory destination where save the source. ' 'The format of this parameter is [container:]dest_path.') def do_cp(cs, args): """Copy files/tars between a container and the local filesystem.""" if ':' in args.source: source_parts = args.source.split(':', 1) container_id = source_parts[0] container_path = source_parts[1] opts = {} opts['id'] = container_id opts['path'] = container_path res = cs.containers.get_archive(**opts) dest_path = args.destination tardata = io.BytesIO(res['data']) with closing(tarfile.open(fileobj=tardata)) as tar: tar.extractall(dest_path) elif ':' in args.destination: dest_parts = args.destination.split(':', 1) container_id = dest_parts[0] container_path = dest_parts[1] filename = os.path.split(args.source)[1] opts = {} opts['id'] = container_id opts['path'] = container_path tardata = io.BytesIO() with closing(tarfile.open(fileobj=tardata, mode='w')) as tar: tar.add(args.source, arcname=filename) opts['data'] = tardata.getvalue() cs.containers.put_archive(**opts) else: print("Please check the parameters for zun copy!") print("Usage:") print("zun cp container:src_path dest_path|-") print("zun cp src_path|- container:dest_path") @utils.arg('container', metavar='', help='ID or name of the container to display stats.') def do_stats(cs, args): """Display stats of the container.""" stats_info = cs.containers.stats(args.container) utils.print_dict(stats_info) @utils.arg('container', metavar='', help='ID or name of the container to commit.') @utils.arg('repository', metavar='[:]', help='The repository and tag of the image.') def do_commit(cs, args): """Create a new image from a container's changes.""" opts = zun_utils.check_commit_container_args(args) opts = zun_utils.remove_null_parms(**opts) try: image = cs.containers.commit(args.container, **opts) print("Request to commit container %s has been accepted. " "The image is %s." % (args.container, image['uuid'])) except Exception as e: print("Commit for container %(container)s failed: %(e)s" % {'container': args.container, 'e': e}) @utils.deprecated(SG_DEPRECATION_MESSAGE) @utils.arg('container', metavar='', help='ID or name of the container to add security group.') @utils.arg('security_group', metavar='', help='Security group ID or name for specified container.') def do_add_security_group(cs, args): """Add security group for specified container.""" opts = {} opts['id'] = args.container opts['security_group'] = args.security_group opts = zun_utils.remove_null_parms(**opts) try: cs.containers.add_security_group(**opts) print("Request to add security group for container %s " "has been accepted." % args.container) except Exception as e: print("Add security group for container %(container)s " "failed: %(e)s" % {'container': args.container, 'e': e}) @utils.exclusive_arg( 'detach_network_port', '--network', metavar='', help='The neutron network that container will detach from.') @utils.exclusive_arg( 'detach_network_port', '--port', metavar='', help='The neutron port that container will detach from.') @utils.arg('container', metavar='', help='ID or name of the container to detach the network.') def do_network_detach(cs, args): """Detach a network from the container.""" opts = {} opts['container'] = args.container opts['network'] = args.network opts['port'] = args.port opts = zun_utils.remove_null_parms(**opts) try: cs.containers.network_detach(**opts) print("Request to detach network from container %s " "has been accepted." % args.container) except Exception as e: print("Detach network from container %(container)s " "failed: %(e)s" % {'container': args.container, 'e': e}) @utils.arg('container', metavar='', help='ID or name of the container to attach network.') @utils.arg('--network', metavar='', help='The neutron network that container will attach to.') @utils.arg('--port', metavar='', help='The neutron port that container will attach to.') @utils.arg('--fixed-ip', metavar='', help='The fixed-ip that container will attach to.') def do_network_attach(cs, args): """Attach a network to the container.""" opts = {} opts['container'] = args.container opts['network'] = args.network opts['port'] = args.port opts['fixed_ip'] = args.fixed_ip opts = zun_utils.remove_null_parms(**opts) try: cs.containers.network_attach(**opts) print("Request to attach network to container %s " "has been accepted." % args.container) except Exception as e: print("Attach network to container %(container)s " "failed: %(e)s" % {'container': args.container, 'e': e}) @utils.arg('container', metavar='', help='ID or name of the container to display network info.') def do_network_list(cs, args): """List networks on a container""" opts = {} opts['container'] = args.container opts = zun_utils.remove_null_parms(**opts) networks = cs.containers.network_list(**opts) zun_utils.list_container_networks(networks) @utils.deprecated(SG_DEPRECATION_MESSAGE) @utils.arg('container', metavar='', help='ID or name of the container to remove security group.') @utils.arg('security_group', metavar='', help='The security group to remove from specified container.') def do_remove_security_group(cs, args): """Remove security group for specified container.""" opts = {} opts['id'] = args.container opts['security_group'] = args.security_group opts = zun_utils.remove_null_parms(**opts) try: cs.containers.remove_security_group(**opts) print("Request to remove security group for container %s " "has been accepted." % args.container) except Exception as e: print("Remove security group for container %(container)s " "failed: %(e)s" % {'container': args.container, 'e': e})