Add network options to zunclient
Add network options to zunclient to allow use specify the pre
created network to use to create container.
CLI format like 'zun create --nets
network=982a86dc1194,v4-fixed-ip=172.17.0.3 --nets
port=1234567,v6-fixed-ip=2001:db8::2 nginx bash'
Value passed to api like this ‘[{u'v4-fixed-ip': u'172.17.0.3',
u'network': u'982a86dc1194', u'v6-fixed-ip': u'', u'port': u''},
{u'v4-fixed-ip': u'', u'network': u'', u'v6-fixed-ip':
u'2001:db8::2', u'port': u'1234567'}]'’.
Change-Id: I6507d153e97564160308dabe90ce8693bc061863
			
			
This commit is contained in:
		@@ -16,6 +16,9 @@
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from oslo_utils import netutils
 | 
			
		||||
 | 
			
		||||
from zunclient.common.apiclient import exceptions as apiexec
 | 
			
		||||
from zunclient.common import cliutils as utils
 | 
			
		||||
from zunclient import exceptions as exc
 | 
			
		||||
from zunclient.i18n import _
 | 
			
		||||
@@ -175,3 +178,41 @@ def parse_command(command):
 | 
			
		||||
            c = '"' + c + '"'
 | 
			
		||||
            output.append(c)
 | 
			
		||||
    return " ".join(output)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_nets(ns):
 | 
			
		||||
    err_msg = ("Invalid nets argument '%s'. nets arguments must be of "
 | 
			
		||||
               "the form --nets <network=network, v4-fixed-ip=ip-addr,"
 | 
			
		||||
               "v6-fixed-ip=ip-addr, port=port-uuid>, "
 | 
			
		||||
               "with only one of network, or port specified.")
 | 
			
		||||
    nets = []
 | 
			
		||||
    for net_str in ns:
 | 
			
		||||
        net_info = {"network": "", "v4-fixed-ip": "", "v6-fixed-ip": "",
 | 
			
		||||
                    "port": ""}
 | 
			
		||||
        for kv_str in net_str.split(","):
 | 
			
		||||
            try:
 | 
			
		||||
                k, v = kv_str.split("=", 1)
 | 
			
		||||
                k = k.strip()
 | 
			
		||||
                v = v.strip()
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                raise apiexec.CommandError(err_msg % net_str)
 | 
			
		||||
            if k in net_info:
 | 
			
		||||
                if net_info[k]:
 | 
			
		||||
                    raise apiexec.CommandError(err_msg % net_str)
 | 
			
		||||
                net_info[k] = v
 | 
			
		||||
            else:
 | 
			
		||||
                raise apiexec.CommandError(err_msg % net_str)
 | 
			
		||||
 | 
			
		||||
        if net_info['v4-fixed-ip'] and not netutils.is_valid_ipv4(
 | 
			
		||||
                net_info['v4-fixed-ip']):
 | 
			
		||||
            raise apiexec.CommandError("Invalid ipv4 address.")
 | 
			
		||||
 | 
			
		||||
        if net_info['v6-fixed-ip'] and not netutils.is_valid_ipv6(
 | 
			
		||||
                net_info['v6-fixed-ip']):
 | 
			
		||||
            raise apiexec.CommandError("Invalid ipv6 address.")
 | 
			
		||||
 | 
			
		||||
        if bool(net_info['network']) == bool(net_info['port']):
 | 
			
		||||
            raise apiexec.CommandError(err_msg % net_str)
 | 
			
		||||
 | 
			
		||||
        nets.append(net_info)
 | 
			
		||||
    return nets
 | 
			
		||||
 
 | 
			
		||||
@@ -125,6 +125,19 @@ class CreateContainer(command.ShowOne):
 | 
			
		||||
            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.')
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--nets',
 | 
			
		||||
            metavar='<auto, networks=networks, port=port-uuid,'
 | 
			
		||||
                    'v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr>',
 | 
			
		||||
            action='append',
 | 
			
		||||
            default=[],
 | 
			
		||||
            help='Create network enpoints for the container. '
 | 
			
		||||
                 'auto: do not specify the network, zun will automatically'
 | 
			
		||||
                 'create one. '
 | 
			
		||||
                 '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.')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
@@ -149,6 +162,7 @@ class CreateContainer(command.ShowOne):
 | 
			
		||||
        if parsed_args.interactive:
 | 
			
		||||
            opts['interactive'] = True
 | 
			
		||||
        opts['hints'] = zun_utils.format_args(parsed_args.hint)
 | 
			
		||||
        opts['nets'] = zun_utils.parse_nets(parsed_args.nets)
 | 
			
		||||
 | 
			
		||||
        opts = zun_utils.remove_null_parms(**opts)
 | 
			
		||||
        container = client.containers.create(**opts)
 | 
			
		||||
@@ -606,6 +620,25 @@ class RunContainer(command.ShowOne):
 | 
			
		||||
            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.')
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--nets',
 | 
			
		||||
            metavar='[net]',
 | 
			
		||||
            action='append',
 | 
			
		||||
            default=[],
 | 
			
		||||
            help='Networks that container will connect to.')
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--nets',
 | 
			
		||||
            metavar='<auto, networks=networks, port=port-uuid,'
 | 
			
		||||
                    'v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr>',
 | 
			
		||||
            action='append',
 | 
			
		||||
            default=[],
 | 
			
		||||
            help='Create network enpoints for the container. '
 | 
			
		||||
                 'auto: do not specify the network, zun will automatically'
 | 
			
		||||
                 'create one. '
 | 
			
		||||
                 '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.')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
@@ -630,6 +663,7 @@ class RunContainer(command.ShowOne):
 | 
			
		||||
        if parsed_args.interactive:
 | 
			
		||||
            opts['interactive'] = True
 | 
			
		||||
        opts['hints'] = zun_utils.format_args(parsed_args.hint)
 | 
			
		||||
        opts['nets'] = zun_utils.parse_nets(parsed_args.nets)
 | 
			
		||||
 | 
			
		||||
        opts = zun_utils.remove_null_parms(**opts)
 | 
			
		||||
        container = client.containers.run(**opts)
 | 
			
		||||
 
 | 
			
		||||
@@ -208,3 +208,39 @@ class CliUtilsTest(test_utils.BaseTestCase):
 | 
			
		||||
            ('c', dict_out['c'])])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(six.text_type(dict_exp), six.text_type(dict_act))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParseNetsTest(test_utils.BaseTestCase):
 | 
			
		||||
 | 
			
		||||
    def test_no_nets(self):
 | 
			
		||||
        nets = []
 | 
			
		||||
        result = utils.parse_nets(nets)
 | 
			
		||||
        self.assertEqual([], result)
 | 
			
		||||
 | 
			
		||||
    def test_nets_with_network(self):
 | 
			
		||||
        nets = [' network = 1234567 , v4-fixed-ip = 172.17.0.3 ']
 | 
			
		||||
        result = utils.parse_nets(nets)
 | 
			
		||||
        self.assertEqual([{'network': '1234567', 'v4-fixed-ip': '172.17.0.3',
 | 
			
		||||
                           'port': '', 'v6-fixed-ip': ''}], result)
 | 
			
		||||
 | 
			
		||||
    def test_nets_with_port(self):
 | 
			
		||||
        nets = ['port=1234567, v6-fixed-ip=2001:db8::2']
 | 
			
		||||
        result = utils.parse_nets(nets)
 | 
			
		||||
        self.assertEqual([{'network': '', 'v4-fixed-ip': '',
 | 
			
		||||
                           'port': '1234567', 'v6-fixed-ip': '2001:db8::2'}],
 | 
			
		||||
                         result)
 | 
			
		||||
 | 
			
		||||
    def test_nets_with_only_ip(self):
 | 
			
		||||
        nets = ['v4-fixed-ip = 172.17.0.3']
 | 
			
		||||
        self.assertRaises(exc.CommandError,
 | 
			
		||||
                          utils.parse_nets, nets)
 | 
			
		||||
 | 
			
		||||
    def test_nets_with_both_network_port(self):
 | 
			
		||||
        nets = ['port=1234567, network=2345678, v4-fixed-ip=172.17.0.3']
 | 
			
		||||
        self.assertRaises(exc.CommandError,
 | 
			
		||||
                          utils.parse_nets, nets)
 | 
			
		||||
 | 
			
		||||
    def test_nets_with_invalid_ip(self):
 | 
			
		||||
        nets = ['network=1234567, v4-fixed-ip=23.555.567,789']
 | 
			
		||||
        self.assertRaises(exc.CommandError,
 | 
			
		||||
                          utils.parse_nets, nets)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ from zunclient import exceptions
 | 
			
		||||
CREATION_ATTRIBUTES = ['name', 'image', 'command', 'cpu', 'memory',
 | 
			
		||||
                       'environment', 'workdir', 'labels', 'image_pull_policy',
 | 
			
		||||
                       'restart_policy', 'interactive', 'image_driver',
 | 
			
		||||
                       'security_groups', 'hints']
 | 
			
		||||
                       'security_groups', 'hints', 'nets']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Container(base.Resource):
 | 
			
		||||
 
 | 
			
		||||
@@ -97,6 +97,18 @@ def _show_container(container):
 | 
			
		||||
           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('--nets',
 | 
			
		||||
           action='append',
 | 
			
		||||
           default=[],
 | 
			
		||||
           metavar='<auto, network=network, port=port-uuid,'
 | 
			
		||||
                   'v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr>',
 | 
			
		||||
           help='Create network enpoints for the container. '
 | 
			
		||||
                'auto: do not specify the network, zun will automatically'
 | 
			
		||||
                'create one. '
 | 
			
		||||
                '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.')
 | 
			
		||||
def do_create(cs, args):
 | 
			
		||||
    """Create a container."""
 | 
			
		||||
    opts = {}
 | 
			
		||||
@@ -110,6 +122,8 @@ def do_create(cs, args):
 | 
			
		||||
    opts['image_pull_policy'] = args.image_pull_policy
 | 
			
		||||
    opts['image_driver'] = args.image_driver
 | 
			
		||||
    opts['hints'] = zun_utils.format_args(args.hint)
 | 
			
		||||
    nets = zun_utils.parse_nets(args.nets)
 | 
			
		||||
    opts['nets'] = nets
 | 
			
		||||
 | 
			
		||||
    if args.security_group:
 | 
			
		||||
        opts['security_groups'] = args.security_group
 | 
			
		||||
@@ -443,6 +457,18 @@ def do_kill(cs, args):
 | 
			
		||||
           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('--nets',
 | 
			
		||||
           action='append',
 | 
			
		||||
           default=[],
 | 
			
		||||
           metavar='<auto, network=network, port=port-uuid,'
 | 
			
		||||
                   'v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr>',
 | 
			
		||||
           help='Create network enpoints for the container. '
 | 
			
		||||
                'auto: do not specify the network, zun will automatically'
 | 
			
		||||
                'create one. '
 | 
			
		||||
                '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.')
 | 
			
		||||
def do_run(cs, args):
 | 
			
		||||
    """Run a command in a new container."""
 | 
			
		||||
    opts = {}
 | 
			
		||||
@@ -456,6 +482,8 @@ def do_run(cs, args):
 | 
			
		||||
    opts['image_pull_policy'] = args.image_pull_policy
 | 
			
		||||
    opts['image_driver'] = args.image_driver
 | 
			
		||||
    opts['hints'] = zun_utils.format_args(args.hint)
 | 
			
		||||
    nets = zun_utils.parse_nets(args.nets)
 | 
			
		||||
    opts['nets'] = nets
 | 
			
		||||
 | 
			
		||||
    if args.security_group:
 | 
			
		||||
        opts['security_groups'] = args.security_group
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user