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 import json
from oslo_utils import netutils
from zunclient.common.apiclient import exceptions as apiexec
from zunclient.common import cliutils as utils from zunclient.common import cliutils as utils
from zunclient import exceptions as exc from zunclient import exceptions as exc
from zunclient.i18n import _ from zunclient.i18n import _
@@ -175,3 +178,41 @@ def parse_command(command):
c = '"' + c + '"' c = '"' + c + '"'
output.append(c) output.append(c)
return " ".join(output) 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. ' help='The key-value pair(s) for scheduler to select host. '
'The format of this parameter is "key=value[,key=value]". ' 'The format of this parameter is "key=value[,key=value]". '
'May be used multiple times.') '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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -149,6 +162,7 @@ class CreateContainer(command.ShowOne):
if parsed_args.interactive: if parsed_args.interactive:
opts['interactive'] = True opts['interactive'] = True
opts['hints'] = zun_utils.format_args(parsed_args.hint) 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) opts = zun_utils.remove_null_parms(**opts)
container = client.containers.create(**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. ' help='The key-value pair(s) for scheduler to select host. '
'The format of this parameter is "key=value[,key=value]". ' 'The format of this parameter is "key=value[,key=value]". '
'May be used multiple times.') '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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@@ -630,6 +663,7 @@ class RunContainer(command.ShowOne):
if parsed_args.interactive: if parsed_args.interactive:
opts['interactive'] = True opts['interactive'] = True
opts['hints'] = zun_utils.format_args(parsed_args.hint) 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) opts = zun_utils.remove_null_parms(**opts)
container = client.containers.run(**opts) container = client.containers.run(**opts)

View File

@@ -208,3 +208,39 @@ class CliUtilsTest(test_utils.BaseTestCase):
('c', dict_out['c'])]) ('c', dict_out['c'])])
self.assertEqual(six.text_type(dict_exp), six.text_type(dict_act)) 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', CREATION_ATTRIBUTES = ['name', 'image', 'command', 'cpu', 'memory',
'environment', 'workdir', 'labels', 'image_pull_policy', 'environment', 'workdir', 'labels', 'image_pull_policy',
'restart_policy', 'interactive', 'image_driver', 'restart_policy', 'interactive', 'image_driver',
'security_groups', 'hints'] 'security_groups', 'hints', 'nets']
class Container(base.Resource): 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. ' help='The key-value pair(s) for scheduler to select host. '
'The format of this parameter is "key=value[,key=value]". ' 'The format of this parameter is "key=value[,key=value]". '
'May be used multiple times.') '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): def do_create(cs, args):
"""Create a container.""" """Create a container."""
opts = {} opts = {}
@@ -110,6 +122,8 @@ def do_create(cs, args):
opts['image_pull_policy'] = args.image_pull_policy opts['image_pull_policy'] = args.image_pull_policy
opts['image_driver'] = args.image_driver opts['image_driver'] = args.image_driver
opts['hints'] = zun_utils.format_args(args.hint) opts['hints'] = zun_utils.format_args(args.hint)
nets = zun_utils.parse_nets(args.nets)
opts['nets'] = nets
if args.security_group: if args.security_group:
opts['security_groups'] = 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. ' help='The key-value pair(s) for scheduler to select host. '
'The format of this parameter is "key=value[,key=value]". ' 'The format of this parameter is "key=value[,key=value]". '
'May be used multiple times.') '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): def do_run(cs, args):
"""Run a command in a new container.""" """Run a command in a new container."""
opts = {} opts = {}
@@ -456,6 +482,8 @@ def do_run(cs, args):
opts['image_pull_policy'] = args.image_pull_policy opts['image_pull_policy'] = args.image_pull_policy
opts['image_driver'] = args.image_driver opts['image_driver'] = args.image_driver
opts['hints'] = zun_utils.format_args(args.hint) opts['hints'] = zun_utils.format_args(args.hint)
nets = zun_utils.parse_nets(args.nets)
opts['nets'] = nets
if args.security_group: if args.security_group:
opts['security_groups'] = args.security_group opts['security_groups'] = args.security_group