c27da4b593
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
219 lines
6.5 KiB
Python
219 lines
6.5 KiB
Python
#
|
|
# Copyright 2012 OpenStack LLC.
|
|
# 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 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 _
|
|
|
|
VALID_UNITS = (
|
|
K,
|
|
M,
|
|
G,
|
|
) = (
|
|
1024,
|
|
1024 * 1024,
|
|
1024 * 1024 * 1024,
|
|
)
|
|
|
|
|
|
def common_filters(marker=None, limit=None, sort_key=None,
|
|
sort_dir=None, all_tenants=False):
|
|
"""Generate common filters for any list request.
|
|
|
|
:param all_tenants: list containers in all tenants or not
|
|
:param marker: entity ID from which to start returning entities.
|
|
:param limit: maximum number of entities to return.
|
|
:param sort_key: field to use for sorting.
|
|
:param sort_dir: direction of sorting: 'asc' or 'desc'.
|
|
:returns: list of string filters.
|
|
"""
|
|
filters = []
|
|
if all_tenants is True:
|
|
filters.append('all_tenants=1')
|
|
if isinstance(limit, int):
|
|
filters.append('limit=%s' % limit)
|
|
if marker is not None:
|
|
filters.append('marker=%s' % marker)
|
|
if sort_key is not None:
|
|
filters.append('sort_key=%s' % sort_key)
|
|
if sort_dir is not None:
|
|
filters.append('sort_dir=%s' % sort_dir)
|
|
return filters
|
|
|
|
|
|
def split_and_deserialize(string):
|
|
"""Split and try to JSON deserialize a string.
|
|
|
|
Gets a string with the KEY=VALUE format, split it (using '=' as the
|
|
separator) and try to JSON deserialize the VALUE.
|
|
:returns: A tuple of (key, value).
|
|
"""
|
|
try:
|
|
key, value = string.split("=", 1)
|
|
except ValueError:
|
|
raise exc.CommandError(_('Attributes must be a list of '
|
|
'PATH=VALUE not "%s"') % string)
|
|
try:
|
|
value = json.loads(value)
|
|
except ValueError:
|
|
pass
|
|
|
|
return (key, value)
|
|
|
|
|
|
def args_array_to_patch(attributes):
|
|
patch = []
|
|
for attr in attributes:
|
|
path, value = split_and_deserialize(attr)
|
|
patch.append({path: value})
|
|
return patch
|
|
|
|
|
|
def format_args(args, parse_comma=True):
|
|
'''Reformat a list of key-value arguments into a dict.
|
|
|
|
Convert arguments into format expected by the API.
|
|
'''
|
|
if not args:
|
|
return {}
|
|
|
|
if parse_comma:
|
|
# expect multiple invocations of --label (or other arguments) but fall
|
|
# back to either , or ; delimited if only one --label is specified
|
|
if len(args) == 1:
|
|
args = args[0].replace(';', ',').split(',')
|
|
|
|
fmt_args = {}
|
|
for arg in args:
|
|
try:
|
|
(k, v) = arg.split(('='), 1)
|
|
except ValueError:
|
|
raise exc.CommandError(_('arguments must be a list of KEY=VALUE '
|
|
'not %s') % arg)
|
|
if k not in fmt_args:
|
|
fmt_args[k] = v
|
|
else:
|
|
if not isinstance(fmt_args[k], list):
|
|
fmt_args[k] = [fmt_args[k]]
|
|
fmt_args[k].append(v)
|
|
|
|
return fmt_args
|
|
|
|
|
|
def print_list_field(field):
|
|
return lambda obj: ', '.join(getattr(obj, field))
|
|
|
|
|
|
def check_restart_policy(policy):
|
|
if ":" in policy:
|
|
name, count = policy.split(":")
|
|
restart_policy = {"Name": name, "MaximumRetryCount": count}
|
|
else:
|
|
restart_policy = {"Name": policy,
|
|
"MaximumRetryCount": '0'}
|
|
return restart_policy
|
|
|
|
|
|
def remove_null_parms(**kwargs):
|
|
new = {}
|
|
for (key, value) in kwargs.items():
|
|
if value is not None:
|
|
new[key] = value
|
|
return new
|
|
|
|
|
|
def check_container_status(container, status):
|
|
if getattr(container, 'status', None) == status:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def format_container_addresses(container):
|
|
addresses = getattr(container, 'addresses', {})
|
|
output = []
|
|
try:
|
|
for address_name, address_list in addresses.items():
|
|
for a in address_list:
|
|
output.append(a['addr'])
|
|
except Exception:
|
|
pass
|
|
|
|
setattr(container, 'addresses', ', '.join(output))
|
|
container._info['addresses'] = ', '.join(output)
|
|
|
|
|
|
def list_containers(containers):
|
|
for c in containers:
|
|
format_container_addresses(c)
|
|
columns = ('uuid', 'name', 'image', 'status', 'task_state', 'addresses',
|
|
'ports')
|
|
utils.print_list(containers, columns,
|
|
{'versions': print_list_field('versions')},
|
|
sortby_index=None)
|
|
|
|
|
|
def parse_command(command):
|
|
output = []
|
|
if command:
|
|
for c in 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
|