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:
ShunliZhou
2017-06-29 15:29:35 +08:00
parent d8a2670b36
commit c27da4b593
5 changed files with 140 additions and 1 deletions

View File

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

View File

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

View File

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

View File

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

View File

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