summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/network/common.py74
-rw-r--r--openstackclient/network/utils.py42
-rw-r--r--openstackclient/network/v2/address_group.py11
-rw-r--r--openstackclient/network/v2/address_scope.py9
-rw-r--r--openstackclient/network/v2/floating_ip.py15
-rw-r--r--openstackclient/network/v2/floating_ip_port_forwarding.py12
-rw-r--r--openstackclient/network/v2/network.py17
-rw-r--r--openstackclient/network/v2/network_flavor.py9
-rw-r--r--openstackclient/network/v2/network_flavor_profile.py10
-rw-r--r--openstackclient/network/v2/network_meter.py5
-rw-r--r--openstackclient/network/v2/network_meter_rule.py5
-rw-r--r--openstackclient/network/v2/network_qos_policy.py10
-rw-r--r--openstackclient/network/v2/network_qos_rule.py10
-rw-r--r--openstackclient/network/v2/network_rbac.py9
-rw-r--r--openstackclient/network/v2/network_segment.py10
-rw-r--r--openstackclient/network/v2/network_segment_range.py12
-rw-r--r--openstackclient/network/v2/port.py15
-rw-r--r--openstackclient/network/v2/router.py18
-rw-r--r--openstackclient/network/v2/security_group.py10
-rw-r--r--openstackclient/network/v2/security_group_rule.py6
-rw-r--r--openstackclient/network/v2/subnet.py14
-rw-r--r--openstackclient/network/v2/subnet_pool.py10
-rw-r--r--openstackclient/tests/unit/network/test_common.py139
-rw-r--r--openstackclient/tests/unit/network/test_utils.py59
24 files changed, 484 insertions, 47 deletions
diff --git a/openstackclient/network/common.py b/openstackclient/network/common.py
index 47ffbe77..b1902a6c 100644
--- a/openstackclient/network/common.py
+++ b/openstackclient/network/common.py
@@ -16,10 +16,12 @@ import contextlib
import logging
import openstack.exceptions
+from osc_lib.cli import parseractions
from osc_lib.command import command
from osc_lib import exceptions
from openstackclient.i18n import _
+from openstackclient.network import utils
LOG = logging.getLogger(__name__)
@@ -75,7 +77,6 @@ class NetDetectionMixin(metaclass=abc.ABCMeta):
"""
# Have we set it up yet for this command?
if not hasattr(self, '_net_type'):
- # import pdb; pdb.set_trace()
try:
if self.app.client_manager.is_network_endpoint_enabled():
net_type = _NET_TYPE_NEUTRON
@@ -255,3 +256,74 @@ class NetworkAndComputeShowOne(NetDetectionMixin, command.ShowOne,
if exc.details:
msg += ", " + str(exc.details)
raise exceptions.CommandError(msg)
+
+
+class NeutronCommandWithExtraArgs(command.Command):
+ """Create and Update commands with additional extra properties.
+
+ Extra properties can be passed to the command and are then send to the
+ Neutron as given to the command.
+ """
+
+ # dict of allowed types
+ _allowed_types_dict = {
+ 'bool': utils.str2bool,
+ 'dict': utils.str2dict,
+ 'list': utils.str2list,
+ 'int': int,
+ 'str': str,
+ }
+
+ def _get_property_converter(self, _property):
+ if 'type' not in _property:
+ converter = str
+ else:
+ converter = self._allowed_types_dict.get(_property['type'])
+
+ if not converter:
+ raise exceptions.CommandError(
+ _("Type {property_type} of property {name} "
+ "is not supported").format(
+ property_type=_property['type'],
+ name=_property['name']))
+ return converter
+
+ def _parse_extra_properties(self, extra_properties):
+ result = {}
+ if extra_properties:
+ for _property in extra_properties:
+ converter = self._get_property_converter(_property)
+ result[_property['name']] = converter(_property['value'])
+ return result
+
+ def get_parser(self, prog_name):
+ parser = super(NeutronCommandWithExtraArgs, self).get_parser(prog_name)
+ parser.add_argument(
+ '--extra-property',
+ metavar='type=<property_type>,name=<property_name>,'
+ 'value=<property_value>',
+ dest='extra_properties',
+ action=parseractions.MultiKeyValueAction,
+ required_keys=['name', 'value'],
+ optional_keys=['type'],
+ help=_("Additional parameters can be passed using this property. "
+ "Default type of the extra property is string ('str'), but "
+ "other types can be used as well. Available types are: "
+ "'dict', 'list', 'str', 'bool', 'int'. "
+ "In case of 'list' type, 'value' can be "
+ "semicolon-separated list of values. "
+ "For 'dict' value is semicolon-separated list of the "
+ "key:value pairs.")
+ )
+ return parser
+
+
+class NeutronUnsetCommandWithExtraArgs(NeutronCommandWithExtraArgs):
+
+ def _parse_extra_properties(self, extra_properties):
+ result = {}
+ if extra_properties:
+ for _property in extra_properties:
+ result[_property['name']] = None
+
+ return result
diff --git a/openstackclient/network/utils.py b/openstackclient/network/utils.py
index 287f0271..4d4d18e4 100644
--- a/openstackclient/network/utils.py
+++ b/openstackclient/network/utils.py
@@ -11,6 +11,10 @@
# under the License.
#
+from osc_lib import exceptions
+
+from openstackclient.i18n import _
+
# Transform compute security group rule for display.
def transform_compute_security_group_rule(sg_rule):
@@ -39,3 +43,41 @@ def transform_compute_security_group_rule(sg_rule):
else:
info['remote_security_group'] = ''
return info
+
+
+def str2bool(strbool):
+ if strbool is None:
+ return None
+ return strbool.lower() == 'true'
+
+
+def str2list(strlist):
+ result = []
+ if strlist:
+ result = strlist.split(';')
+ return result
+
+
+def str2dict(strdict):
+ """Convert key1:value1;key2:value2;... string into dictionary.
+
+ :param strdict: string in the form of key1:value1;key2:value2
+ """
+ result = {}
+ if not strdict:
+ return result
+ i = 0
+ kvlist = []
+ for kv in strdict.split(';'):
+ if ':' in kv:
+ kvlist.append(kv)
+ i += 1
+ elif i == 0:
+ msg = _("missing value for key '%s'")
+ raise exceptions.CommandError(msg % kv)
+ else:
+ kvlist[i - 1] = "%s;%s" % (kvlist[i - 1], kv)
+ for kv in kvlist:
+ key, sep, value = kv.partition(':')
+ result[key] = value
+ return result
diff --git a/openstackclient/network/v2/address_group.py b/openstackclient/network/v2/address_group.py
index c5b2f126..fc834700 100644
--- a/openstackclient/network/v2/address_group.py
+++ b/openstackclient/network/v2/address_group.py
@@ -22,6 +22,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -57,7 +58,7 @@ def _get_attrs(client_manager, parsed_args):
return attrs
-class CreateAddressGroup(command.ShowOne):
+class CreateAddressGroup(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create a new Address Group")
def get_parser(self, prog_name):
@@ -93,6 +94,9 @@ class CreateAddressGroup(command.ShowOne):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
obj = client.create_address_group(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
@@ -191,7 +195,7 @@ class ListAddressGroup(command.Lister):
) for s in data))
-class SetAddressGroup(command.Command):
+class SetAddressGroup(common.NeutronCommandWithExtraArgs):
_description = _("Set address group properties")
def get_parser(self, prog_name):
@@ -231,6 +235,9 @@ class SetAddressGroup(command.Command):
attrs['name'] = parsed_args.name
if parsed_args.description is not None:
attrs['description'] = parsed_args.description
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_address_group(obj, **attrs)
if parsed_args.address:
diff --git a/openstackclient/network/v2/address_scope.py b/openstackclient/network/v2/address_scope.py
index 71c1a9af..cd27678e 100644
--- a/openstackclient/network/v2/address_scope.py
+++ b/openstackclient/network/v2/address_scope.py
@@ -21,6 +21,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -57,7 +58,7 @@ def _get_attrs(client_manager, parsed_args):
# TODO(rtheis): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateAddressScope(command.ShowOne):
+class CreateAddressScope(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create a new Address Scope")
def get_parser(self, prog_name):
@@ -98,6 +99,8 @@ class CreateAddressScope(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_address_scope(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
@@ -226,7 +229,7 @@ class ListAddressScope(command.Lister):
# TODO(rtheis): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetAddressScope(command.Command):
+class SetAddressScope(common.NeutronCommandWithExtraArgs):
_description = _("Set address scope properties")
def get_parser(self, prog_name):
@@ -267,6 +270,8 @@ class SetAddressScope(command.Command):
attrs['shared'] = True
if parsed_args.no_share:
attrs['shared'] = False
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
client.update_address_scope(obj, **attrs)
diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py
index a2765cd1..25b2a1ba 100644
--- a/openstackclient/network/v2/floating_ip.py
+++ b/openstackclient/network/v2/floating_ip.py
@@ -13,7 +13,6 @@
"""IP Floating action implementations"""
-from osc_lib.command import command
from osc_lib import utils
from osc_lib.utils import tags as _tag
@@ -94,7 +93,8 @@ def _get_attrs(client_manager, parsed_args):
return attrs
-class CreateFloatingIP(common.NetworkAndComputeShowOne):
+class CreateFloatingIP(common.NetworkAndComputeShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create floating IP")
def update_parser_common(self, parser):
@@ -175,6 +175,8 @@ class CreateFloatingIP(common.NetworkAndComputeShowOne):
def take_action_network(self, client, parsed_args):
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
with common.check_missing_extension_if_error(
self.app.client_manager.network, attrs):
obj = client.create_ip(**attrs)
@@ -390,7 +392,7 @@ class ListFloatingIP(common.NetworkAndComputeLister):
) for s in data))
-class SetFloatingIP(command.Command):
+class SetFloatingIP(common.NeutronCommandWithExtraArgs):
_description = _("Set floating IP Properties")
def get_parser(self, prog_name):
@@ -456,6 +458,9 @@ class SetFloatingIP(command.Command):
if 'no_qos_policy' in parsed_args and parsed_args.no_qos_policy:
attrs['qos_policy_id'] = None
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_ip(obj, **attrs)
@@ -490,7 +495,7 @@ class ShowFloatingIP(common.NetworkAndComputeShowOne):
return (columns, data)
-class UnsetFloatingIP(command.Command):
+class UnsetFloatingIP(common.NeutronCommandWithExtraArgs):
_description = _("Unset floating IP Properties")
def get_parser(self, prog_name):
@@ -526,6 +531,8 @@ class UnsetFloatingIP(command.Command):
attrs['port_id'] = None
if parsed_args.qos_policy:
attrs['qos_policy_id'] = None
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
if attrs:
client.update_ip(obj, **attrs)
diff --git a/openstackclient/network/v2/floating_ip_port_forwarding.py b/openstackclient/network/v2/floating_ip_port_forwarding.py
index 06b3df8b..71b0b7da 100644
--- a/openstackclient/network/v2/floating_ip_port_forwarding.py
+++ b/openstackclient/network/v2/floating_ip_port_forwarding.py
@@ -19,6 +19,7 @@ from osc_lib import exceptions
from osc_lib import utils
from openstackclient.i18n import _
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -32,7 +33,8 @@ def _get_columns(item):
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
-class CreateFloatingIPPortForwarding(command.ShowOne):
+class CreateFloatingIPPortForwarding(command.ShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create floating IP port forwarding")
def get_parser(self, prog_name):
@@ -122,6 +124,9 @@ class CreateFloatingIPPortForwarding(command.ShowOne):
if parsed_args.description is not None:
attrs['description'] = parsed_args.description
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
obj = client.create_floating_ip_port_forwarding(
floating_ip.id,
**attrs
@@ -258,7 +263,7 @@ class ListFloatingIPPortForwarding(command.Lister):
) for s in data))
-class SetFloatingIPPortForwarding(command.Command):
+class SetFloatingIPPortForwarding(common.NeutronCommandWithExtraArgs):
_description = _("Set floating IP Port Forwarding Properties")
def get_parser(self, prog_name):
@@ -352,6 +357,9 @@ class SetFloatingIPPortForwarding(command.Command):
if parsed_args.description is not None:
attrs['description'] = parsed_args.description
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
client.update_floating_ip_port_forwarding(
floating_ip.id, parsed_args.port_forwarding_id, **attrs)
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index 7a12d523..b8eb9f01 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -15,7 +15,6 @@
from cliff import columns as cliff_columns
from osc_lib.cli import format_columns
-from osc_lib.command import command
from osc_lib import utils
from osc_lib.utils import tags as _tag
@@ -189,7 +188,8 @@ def _add_additional_network_options(parser):
# TODO(sindhu): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateNetwork(common.NetworkAndComputeShowOne):
+class CreateNetwork(common.NetworkAndComputeShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create new network")
def update_parser_common(self, parser):
@@ -334,6 +334,8 @@ class CreateNetwork(common.NetworkAndComputeShowOne):
attrs['vlan_transparent'] = True
if parsed_args.no_transparent_vlan:
attrs['vlan_transparent'] = False
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
with common.check_missing_extension_if_error(
self.app.client_manager.network, attrs):
obj = client.create_network(**attrs)
@@ -623,7 +625,7 @@ class ListNetwork(common.NetworkAndComputeLister):
# TODO(sindhu): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetNetwork(command.Command):
+class SetNetwork(common.NeutronCommandWithExtraArgs):
_description = _("Set network properties")
def get_parser(self, prog_name):
@@ -728,6 +730,8 @@ class SetNetwork(command.Command):
obj = client.find_network(parsed_args.network, ignore_missing=False)
attrs = _get_attrs_network(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
if attrs:
with common.check_missing_extension_if_error(
self.app.client_manager.network, attrs):
@@ -761,7 +765,7 @@ class ShowNetwork(common.NetworkAndComputeShowOne):
return (display_columns, data)
-class UnsetNetwork(command.Command):
+class UnsetNetwork(common.NeutronUnsetCommandWithExtraArgs):
_description = _("Unset network properties")
def get_parser(self, prog_name):
@@ -778,8 +782,9 @@ class UnsetNetwork(command.Command):
client = self.app.client_manager.network
obj = client.find_network(parsed_args.network, ignore_missing=False)
- # NOTE: As of now, UnsetNetwork has no attributes which need
- # to be updated by update_network().
+ attrs = self._parse_extra_properties(parsed_args.extra_properties)
+ if attrs:
+ client.update_network(obj, **attrs)
# tags is a subresource and it needs to be updated separately.
_tag.update_tags_for_unset(client, obj, parsed_args)
diff --git a/openstackclient/network/v2/network_flavor.py b/openstackclient/network/v2/network_flavor.py
index c9d368bf..9e758ae2 100644
--- a/openstackclient/network/v2/network_flavor.py
+++ b/openstackclient/network/v2/network_flavor.py
@@ -21,6 +21,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -88,7 +89,7 @@ class AddNetworkFlavorToProfile(command.Command):
# TODO(dasanind): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateNetworkFlavor(command.ShowOne):
+class CreateNetworkFlavor(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create new network flavor")
def get_parser(self, prog_name):
@@ -134,6 +135,8 @@ class CreateNetworkFlavor(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_flavor(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
@@ -234,7 +237,7 @@ class RemoveNetworkFlavorFromProfile(command.Command):
# TODO(dasanind): Use only the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetNetworkFlavor(command.Command):
+class SetNetworkFlavor(common.NeutronCommandWithExtraArgs):
_description = _("Set network flavor properties")
def get_parser(self, prog_name):
@@ -281,6 +284,8 @@ class SetNetworkFlavor(command.Command):
attrs['enabled'] = True
if parsed_args.disable:
attrs['enabled'] = False
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
client.update_flavor(obj, **attrs)
diff --git a/openstackclient/network/v2/network_flavor_profile.py b/openstackclient/network/v2/network_flavor_profile.py
index 6cf0c412..0212e0d9 100644
--- a/openstackclient/network/v2/network_flavor_profile.py
+++ b/openstackclient/network/v2/network_flavor_profile.py
@@ -19,6 +19,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -60,7 +61,8 @@ def _get_attrs(client_manager, parsed_args):
# TODO(ndahiwade): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateNetworkFlavorProfile(command.ShowOne):
+class CreateNetworkFlavorProfile(command.ShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create new network flavor profile")
def get_parser(self, prog_name):
@@ -103,6 +105,8 @@ class CreateNetworkFlavorProfile(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
if parsed_args.driver is None and parsed_args.metainfo is None:
msg = _("Either --driver or --metainfo or both are required")
@@ -180,7 +184,7 @@ class ListNetworkFlavorProfile(command.Lister):
# TODO(ndahiwade): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetNetworkFlavorProfile(command.Command):
+class SetNetworkFlavorProfile(common.NeutronCommandWithExtraArgs):
_description = _("Set network flavor profile properties")
def get_parser(self, prog_name):
@@ -225,6 +229,8 @@ class SetNetworkFlavorProfile(command.Command):
obj = client.find_service_profile(parsed_args.flavor_profile,
ignore_missing=False)
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
client.update_service_profile(obj, **attrs)
diff --git a/openstackclient/network/v2/network_meter.py b/openstackclient/network/v2/network_meter.py
index df0e1da1..f8f188a8 100644
--- a/openstackclient/network/v2/network_meter.py
+++ b/openstackclient/network/v2/network_meter.py
@@ -21,6 +21,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
LOG = logging.getLogger(__name__)
@@ -59,7 +60,7 @@ def _get_attrs(client_manager, parsed_args):
# TODO(ankur-gupta-f): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateMeter(command.ShowOne):
+class CreateMeter(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create network meter")
def get_parser(self, prog_name):
@@ -100,6 +101,8 @@ class CreateMeter(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_metering_label(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
diff --git a/openstackclient/network/v2/network_meter_rule.py b/openstackclient/network/v2/network_meter_rule.py
index 1cf0395f..06362fa1 100644
--- a/openstackclient/network/v2/network_meter_rule.py
+++ b/openstackclient/network/v2/network_meter_rule.py
@@ -21,6 +21,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
LOG = logging.getLogger(__name__)
@@ -64,7 +65,7 @@ def _get_attrs(client_manager, parsed_args):
return attrs
-class CreateMeterRule(command.ShowOne):
+class CreateMeterRule(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create a new meter rule")
def get_parser(self, prog_name):
@@ -130,6 +131,8 @@ class CreateMeterRule(command.ShowOne):
ignore_missing=False)
parsed_args.meter = _meter.id
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_metering_label_rule(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
diff --git a/openstackclient/network/v2/network_qos_policy.py b/openstackclient/network/v2/network_qos_policy.py
index fd5ff937..7300a5c0 100644
--- a/openstackclient/network/v2/network_qos_policy.py
+++ b/openstackclient/network/v2/network_qos_policy.py
@@ -21,6 +21,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -67,7 +68,8 @@ def _get_attrs(client_manager, parsed_args):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateNetworkQosPolicy(command.ShowOne):
+class CreateNetworkQosPolicy(command.ShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create a QoS policy")
def get_parser(self, prog_name):
@@ -117,6 +119,8 @@ class CreateNetworkQosPolicy(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_qos_policy(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
@@ -209,7 +213,7 @@ class ListNetworkQosPolicy(command.Lister):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetNetworkQosPolicy(command.Command):
+class SetNetworkQosPolicy(common.NeutronCommandWithExtraArgs):
_description = _("Set QoS policy properties")
def get_parser(self, prog_name):
@@ -259,6 +263,8 @@ class SetNetworkQosPolicy(command.Command):
parsed_args.policy,
ignore_missing=False)
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
client.update_qos_policy(obj, **attrs)
diff --git a/openstackclient/network/v2/network_qos_rule.py b/openstackclient/network/v2/network_qos_rule.py
index 2e4b385d..f30a5aeb 100644
--- a/openstackclient/network/v2/network_qos_rule.py
+++ b/openstackclient/network/v2/network_qos_rule.py
@@ -20,6 +20,7 @@ from osc_lib import exceptions
from osc_lib import utils
from openstackclient.i18n import _
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -171,7 +172,8 @@ def _add_rule_arguments(parser):
)
-class CreateNetworkQosRule(command.ShowOne):
+class CreateNetworkQosRule(command.ShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create new Network QoS rule")
def get_parser(self, prog_name):
@@ -198,6 +200,8 @@ class CreateNetworkQosRule(command.ShowOne):
def take_action(self, parsed_args):
network_client = self.app.client_manager.network
attrs = _get_attrs(network_client, parsed_args, is_create=True)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
try:
obj = _rule_action_call(
network_client, ACTION_CREATE, parsed_args.type)(
@@ -285,7 +289,7 @@ class ListNetworkQosRule(command.Lister):
(_get_item_properties(s, columns) for s in data))
-class SetNetworkQosRule(command.Command):
+class SetNetworkQosRule(common.NeutronCommandWithExtraArgs):
_description = _("Set Network QoS rule properties")
def get_parser(self, prog_name):
@@ -312,6 +316,8 @@ class SetNetworkQosRule(command.Command):
if not rule_type:
raise Exception('Rule not found')
attrs = _get_attrs(network_client, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
qos_id = attrs.pop('qos_policy_id')
qos_rule = _rule_action_call(network_client, ACTION_FIND,
rule_type)(attrs.pop('id'), qos_id)
diff --git a/openstackclient/network/v2/network_rbac.py b/openstackclient/network/v2/network_rbac.py
index 4984e89d..692a4385 100644
--- a/openstackclient/network/v2/network_rbac.py
+++ b/openstackclient/network/v2/network_rbac.py
@@ -21,6 +21,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -90,7 +91,7 @@ def _get_attrs(client_manager, parsed_args):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateNetworkRBAC(command.ShowOne):
+class CreateNetworkRBAC(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create network RBAC policy")
def get_parser(self, prog_name):
@@ -150,6 +151,8 @@ class CreateNetworkRBAC(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_rbac_policy(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns)
@@ -253,7 +256,7 @@ class ListNetworkRBAC(command.Lister):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetNetworkRBAC(command.Command):
+class SetNetworkRBAC(common.NeutronCommandWithExtraArgs):
_description = _("Set network RBAC policy properties")
def get_parser(self, prog_name):
@@ -291,6 +294,8 @@ class SetNetworkRBAC(command.Command):
parsed_args.target_project_domain,
).id
attrs['target_tenant'] = project_id
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
client.update_rbac_policy(obj, **attrs)
diff --git a/openstackclient/network/v2/network_segment.py b/openstackclient/network/v2/network_segment.py
index c1a672e2..14a8edab 100644
--- a/openstackclient/network/v2/network_segment.py
+++ b/openstackclient/network/v2/network_segment.py
@@ -20,6 +20,7 @@ from osc_lib import exceptions
from osc_lib import utils
from openstackclient.i18n import _
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -30,7 +31,8 @@ def _get_columns(item):
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, {})
-class CreateNetworkSegment(command.ShowOne):
+class CreateNetworkSegment(command.ShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create new network segment")
def get_parser(self, prog_name):
@@ -88,6 +90,8 @@ class CreateNetworkSegment(command.ShowOne):
attrs['physical_network'] = parsed_args.physical_network
if parsed_args.segment is not None:
attrs['segmentation_id'] = parsed_args.segment
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_segment(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns)
@@ -189,7 +193,7 @@ class ListNetworkSegment(command.Lister):
) for s in data))
-class SetNetworkSegment(command.Command):
+class SetNetworkSegment(common.NeutronCommandWithExtraArgs):
_description = _("Set network segment properties")
def get_parser(self, prog_name):
@@ -220,6 +224,8 @@ class SetNetworkSegment(command.Command):
attrs['description'] = parsed_args.description
if parsed_args.name is not None:
attrs['name'] = parsed_args.name
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
client.update_segment(obj, **attrs)
diff --git a/openstackclient/network/v2/network_segment_range.py b/openstackclient/network/v2/network_segment_range.py
index 6229995a..ee414407 100644
--- a/openstackclient/network/v2/network_segment_range.py
+++ b/openstackclient/network/v2/network_segment_range.py
@@ -25,6 +25,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -87,7 +88,8 @@ def _update_additional_fields_from_props(columns, props):
return props
-class CreateNetworkSegmentRange(command.ShowOne):
+class CreateNetworkSegmentRange(command.ShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create new network segment range")
def get_parser(self, prog_name):
@@ -209,6 +211,10 @@ class CreateNetworkSegmentRange(command.ShowOne):
if parsed_args.physical_network:
attrs['physical_network'] = parsed_args.physical_network
+
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
obj = network_client.create_network_segment_range(**attrs)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns)
@@ -365,7 +371,7 @@ class ListNetworkSegmentRange(command.Lister):
return headers, display_props
-class SetNetworkSegmentRange(command.Command):
+class SetNetworkSegmentRange(common.NeutronCommandWithExtraArgs):
_description = _("Set network segment range properties")
def get_parser(self, prog_name):
@@ -419,6 +425,8 @@ class SetNetworkSegmentRange(command.Command):
attrs['minimum'] = parsed_args.minimum
if parsed_args.maximum:
attrs['maximum'] = parsed_args.maximum
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
network_client.update_network_segment_range(obj, **attrs)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 4feffc1d..ecb2382a 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -326,7 +326,7 @@ def _convert_extra_dhcp_options(parsed_args):
return dhcp_options
-class CreatePort(command.ShowOne):
+class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create a new port")
def get_parser(self, prog_name):
@@ -501,6 +501,9 @@ class CreatePort(command.ShowOne):
if parsed_args.tags:
attrs['tags'] = list(set(parsed_args.tags))
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
with common.check_missing_extension_if_error(
self.app.client_manager.network, attrs):
obj = client.create_port(**attrs)
@@ -697,7 +700,7 @@ class ListPort(command.Lister):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetPort(command.Command):
+class SetPort(common.NeutronCommandWithExtraArgs):
_description = _("Set port properties")
def get_parser(self, prog_name):
@@ -871,6 +874,9 @@ class SetPort(command.Command):
if parsed_args.data_plane_status:
attrs['data_plane_status'] = parsed_args.data_plane_status
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
with common.check_missing_extension_if_error(
self.app.client_manager.network, attrs):
@@ -902,7 +908,7 @@ class ShowPort(command.ShowOne):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class UnsetPort(command.Command):
+class UnsetPort(common.NeutronUnsetCommandWithExtraArgs):
_description = _("Unset port properties")
def get_parser(self, prog_name):
@@ -1023,6 +1029,9 @@ class UnsetPort(command.Command):
if parsed_args.numa_policy:
attrs['numa_affinity_policy'] = None
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_port(obj, **attrs)
diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py
index e3e8accd..d15300a0 100644
--- a/openstackclient/network/v2/router.py
+++ b/openstackclient/network/v2/router.py
@@ -27,6 +27,7 @@ from osc_lib.utils import tags as _tag
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -256,7 +257,7 @@ class RemoveExtraRoutesFromRouter(command.ShowOne):
# TODO(yanxing'an): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateRouter(command.ShowOne):
+class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create a new router")
def get_parser(self, prog_name):
@@ -332,6 +333,9 @@ class CreateRouter(command.ShowOne):
attrs['ha'] = True
if parsed_args.no_ha:
attrs['ha'] = False
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
obj = client.create_router(**attrs)
# tags cannot be set when created, so tags need to be set later.
_tag.update_tags_for_set(client, obj, parsed_args)
@@ -576,7 +580,7 @@ class RemoveSubnetFromRouter(command.Command):
# TODO(yanxing'an): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetRouter(command.Command):
+class SetRouter(common.NeutronCommandWithExtraArgs):
_description = _("Set router properties")
def get_parser(self, prog_name):
@@ -767,6 +771,10 @@ class SetRouter(command.Command):
if 'no_qos_policy' in parsed_args and parsed_args.no_qos_policy:
attrs['external_gateway_info']['qos_policy_id'] = None
+
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_router(obj, **attrs)
# tags is a subresource and it needs to be updated separately.
@@ -809,7 +817,7 @@ class ShowRouter(command.ShowOne):
return (display_columns, data)
-class UnsetRouter(command.Command):
+class UnsetRouter(common.NeutronUnsetCommandWithExtraArgs):
_description = _("Unset router properties")
def get_parser(self, prog_name):
@@ -875,6 +883,10 @@ class UnsetRouter(command.Command):
if parsed_args.external_gateway:
attrs['external_gateway_info'] = {}
+
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_router(obj, **attrs)
# tags is a subresource and it needs to be updated separately.
diff --git a/openstackclient/network/v2/security_group.py b/openstackclient/network/v2/security_group.py
index 0732c23e..49dc14e4 100644
--- a/openstackclient/network/v2/security_group.py
+++ b/openstackclient/network/v2/security_group.py
@@ -95,7 +95,8 @@ def _get_columns(item):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateSecurityGroup(common.NetworkAndComputeShowOne):
+class CreateSecurityGroup(common.NetworkAndComputeShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create a new security group")
def update_parser_common(self, parser):
@@ -160,6 +161,8 @@ class CreateSecurityGroup(common.NetworkAndComputeShowOne):
parsed_args.project_domain,
).id
attrs['tenant_id'] = project_id
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
# Create the security group and display the results.
obj = client.create_security_group(**attrs)
@@ -310,7 +313,8 @@ class ListSecurityGroup(common.NetworkAndComputeLister):
) for s in data))
-class SetSecurityGroup(common.NetworkAndComputeCommand):
+class SetSecurityGroup(common.NetworkAndComputeCommand,
+ common.NeutronCommandWithExtraArgs):
_description = _("Set security group properties")
def update_parser_common(self, parser):
@@ -362,6 +366,8 @@ class SetSecurityGroup(common.NetworkAndComputeCommand):
attrs['stateful'] = True
if parsed_args.stateless:
attrs['stateful'] = False
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
# NOTE(rtheis): Previous behavior did not raise a CommandError
# if there were no updates. Maintain this behavior and issue
# the update.
diff --git a/openstackclient/network/v2/security_group_rule.py b/openstackclient/network/v2/security_group_rule.py
index 17241ed2..e273ded3 100644
--- a/openstackclient/network/v2/security_group_rule.py
+++ b/openstackclient/network/v2/security_group_rule.py
@@ -104,7 +104,8 @@ def _is_icmp_protocol(protocol):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateSecurityGroupRule(common.NetworkAndComputeShowOne):
+class CreateSecurityGroupRule(common.NetworkAndComputeShowOne,
+ common.NeutronCommandWithExtraArgs):
_description = _("Create a new security group rule")
def update_parser_common(self, parser):
@@ -355,6 +356,9 @@ class CreateSecurityGroupRule(common.NetworkAndComputeShowOne):
).id
attrs['tenant_id'] = project_id
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
# Create and show the security group rule.
obj = client.create_security_group_rule(**attrs)
display_columns, columns = _get_columns(obj)
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index eccdd4e4..09fd7c7c 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -26,6 +26,7 @@ from osc_lib.utils import tags as _tag
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -250,7 +251,7 @@ def _get_attrs(client_manager, parsed_args, is_create=True):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateSubnet(command.ShowOne):
+class CreateSubnet(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create a subnet")
def get_parser(self, prog_name):
@@ -373,6 +374,8 @@ class CreateSubnet(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_subnet(**attrs)
# tags cannot be set when created, so tags need to be set later.
_tag.update_tags_for_set(client, obj, parsed_args)
@@ -545,7 +548,7 @@ class ListSubnet(command.Lister):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetSubnet(command.Command):
+class SetSubnet(common.NeutronCommandWithExtraArgs):
_description = _("Set subnet properties")
def get_parser(self, prog_name):
@@ -630,6 +633,8 @@ class SetSubnet(command.Command):
attrs['allocation_pools'] = []
if 'service_types' in attrs:
attrs['service_types'] += obj.service_types
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
if attrs:
client.update_subnet(obj, **attrs)
# tags is a subresource and it needs to be updated separately.
@@ -657,7 +662,7 @@ class ShowSubnet(command.ShowOne):
return (display_columns, data)
-class UnsetSubnet(command.Command):
+class UnsetSubnet(common.NeutronUnsetCommandWithExtraArgs):
_description = _("Unset subnet properties")
def get_parser(self, prog_name):
@@ -744,6 +749,9 @@ class UnsetSubnet(command.Command):
_update_arguments(attrs['service_types'],
parsed_args.service_types,
'service-type')
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_subnet(obj, **attrs)
diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py
index 56cf6152..bdf7aba8 100644
--- a/openstackclient/network/v2/subnet_pool.py
+++ b/openstackclient/network/v2/subnet_pool.py
@@ -24,6 +24,7 @@ from osc_lib.utils import tags as _tag
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
from openstackclient.network import sdk_utils
@@ -146,7 +147,7 @@ def _add_default_options(parser):
# TODO(rtheis): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class CreateSubnetPool(command.ShowOne):
+class CreateSubnetPool(command.ShowOne, common.NeutronCommandWithExtraArgs):
_description = _("Create subnet pool")
def get_parser(self, prog_name):
@@ -203,6 +204,8 @@ class CreateSubnetPool(command.ShowOne):
# NeutronServer expects prefixes to be a List
if "prefixes" not in attrs:
attrs['prefixes'] = []
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
obj = client.create_subnet_pool(**attrs)
# tags cannot be set when created, so tags need to be set later.
_tag.update_tags_for_set(client, obj, parsed_args)
@@ -351,7 +354,7 @@ class ListSubnetPool(command.Lister):
# TODO(rtheis): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
-class SetSubnetPool(command.Command):
+class SetSubnetPool(common.NeutronCommandWithExtraArgs):
_description = _("Set subnet pool properties")
def get_parser(self, prog_name):
@@ -408,6 +411,9 @@ class SetSubnetPool(command.Command):
if 'prefixes' in attrs:
attrs['prefixes'].extend(obj.prefixes)
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+
if attrs:
client.update_subnet_pool(obj, **attrs)
# tags is a subresource and it needs to be updated separately.
diff --git a/openstackclient/tests/unit/network/test_common.py b/openstackclient/tests/unit/network/test_common.py
index cde321aa..4dde1b2b 100644
--- a/openstackclient/tests/unit/network/test_common.py
+++ b/openstackclient/tests/unit/network/test_common.py
@@ -102,6 +102,27 @@ class FakeNetworkAndComputeShowOne(common.NetworkAndComputeShowOne):
return client.compute_action(parsed_args)
+class FakeCreateNeutronCommandWithExtraArgs(
+ common.NeutronCommandWithExtraArgs):
+
+ def get_parser(self, prog_name):
+ parser = super(FakeCreateNeutronCommandWithExtraArgs,
+ self).get_parser(prog_name)
+ parser.add_argument(
+ '--known-attribute',
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ attrs = {}
+ if 'known_attribute' in parsed_args:
+ attrs['known_attribute'] = parsed_args.known_attribute
+ attrs.update(
+ self._parse_extra_properties(parsed_args.extra_properties))
+ client.test_create_action(**attrs)
+
+
class TestNetworkAndCompute(utils.TestCommand):
def setUp(self):
@@ -187,3 +208,121 @@ class TestNetworkAndComputeShowOne(TestNetworkAndCompute):
m_action.side_effect = openstack.exceptions.HttpException("bar")
self.assertRaisesRegex(exceptions.CommandError, "bar",
self.cmd.take_action, mock.Mock())
+
+
+class TestNeutronCommandWithExtraArgs(utils.TestCommand):
+
+ def setUp(self):
+ super(TestNeutronCommandWithExtraArgs, self).setUp()
+
+ self.namespace = argparse.Namespace()
+
+ self.app.client_manager.network = mock.Mock()
+ self.network = self.app.client_manager.network
+ self.network.test_create_action = mock.Mock()
+
+ # Subclasses can override the command object to test.
+ self.cmd = FakeCreateNeutronCommandWithExtraArgs(
+ self.app, self.namespace)
+
+ def test_create_extra_attributes_default_type(self):
+ arglist = [
+ '--known-attribute', 'known-value',
+ '--extra-property', 'name=extra_name,value=extra_value'
+ ]
+ verifylist = [
+ ('known_attribute', 'known-value'),
+ ('extra_properties', [{'name': 'extra_name',
+ 'value': 'extra_value'}])
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.network.test_create_action.assert_called_with(
+ known_attribute='known-value', extra_name='extra_value')
+
+ def test_create_extra_attributes_string(self):
+ arglist = [
+ '--known-attribute', 'known-value',
+ '--extra-property', 'type=str,name=extra_name,value=extra_value'
+ ]
+ verifylist = [
+ ('known_attribute', 'known-value'),
+ ('extra_properties', [{'name': 'extra_name',
+ 'type': 'str',
+ 'value': 'extra_value'}])
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.network.test_create_action.assert_called_with(
+ known_attribute='known-value', extra_name='extra_value')
+
+ def test_create_extra_attributes_bool(self):
+ arglist = [
+ '--known-attribute', 'known-value',
+ '--extra-property', 'type=bool,name=extra_name,value=TrUe'
+ ]
+ verifylist = [
+ ('known_attribute', 'known-value'),
+ ('extra_properties', [{'name': 'extra_name',
+ 'type': 'bool',
+ 'value': 'TrUe'}])
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.network.test_create_action.assert_called_with(
+ known_attribute='known-value', extra_name=True)
+
+ def test_create_extra_attributes_int(self):
+ arglist = [
+ '--known-attribute', 'known-value',
+ '--extra-property', 'type=int,name=extra_name,value=8'
+ ]
+ verifylist = [
+ ('known_attribute', 'known-value'),
+ ('extra_properties', [{'name': 'extra_name',
+ 'type': 'int',
+ 'value': '8'}])
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.network.test_create_action.assert_called_with(
+ known_attribute='known-value', extra_name=8)
+
+ def test_create_extra_attributes_list(self):
+ arglist = [
+ '--known-attribute', 'known-value',
+ '--extra-property', 'type=list,name=extra_name,value=v_1;v_2'
+ ]
+ verifylist = [
+ ('known_attribute', 'known-value'),
+ ('extra_properties', [{'name': 'extra_name',
+ 'type': 'list',
+ 'value': 'v_1;v_2'}])
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.network.test_create_action.assert_called_with(
+ known_attribute='known-value', extra_name=['v_1', 'v_2'])
+
+ def test_create_extra_attributes_dict(self):
+ arglist = [
+ '--known-attribute', 'known-value',
+ '--extra-property', 'type=dict,name=extra_name,value=n1:v1;n2:v2'
+ ]
+ verifylist = [
+ ('known_attribute', 'known-value'),
+ ('extra_properties', [{'name': 'extra_name',
+ 'type': 'dict',
+ 'value': 'n1:v1;n2:v2'}])
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.network.test_create_action.assert_called_with(
+ known_attribute='known-value',
+ extra_name={'n1': 'v1', 'n2': 'v2'})
diff --git a/openstackclient/tests/unit/network/test_utils.py b/openstackclient/tests/unit/network/test_utils.py
new file mode 100644
index 00000000..6252d7f7
--- /dev/null
+++ b/openstackclient/tests/unit/network/test_utils.py
@@ -0,0 +1,59 @@
+# 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.
+#
+
+from osc_lib import exceptions
+
+from openstackclient.network import utils
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestUtils(tests_utils.TestCase):
+
+ def test_str2bool(self):
+ self.assertTrue(utils.str2bool("true"))
+ self.assertTrue(utils.str2bool("True"))
+ self.assertTrue(utils.str2bool("TRUE"))
+ self.assertTrue(utils.str2bool("TrUe"))
+
+ self.assertFalse(utils.str2bool("false"))
+ self.assertFalse(utils.str2bool("False"))
+ self.assertFalse(utils.str2bool("FALSE"))
+ self.assertFalse(utils.str2bool("FaLsE"))
+ self.assertFalse(utils.str2bool("Something else"))
+ self.assertFalse(utils.str2bool(""))
+
+ self.assertIsNone(utils.str2bool(None))
+
+ def test_str2list(self):
+ self.assertEqual(
+ ['a', 'b', 'c'], utils.str2list("a;b;c"))
+ self.assertEqual(
+ ['abc'], utils.str2list("abc"))
+
+ self.assertEqual([], utils.str2list(""))
+ self.assertEqual([], utils.str2list(None))
+
+ def test_str2dict(self):
+ self.assertEqual(
+ {'a': 'aaa', 'b': '2'},
+ utils.str2dict('a:aaa;b:2'))
+ self.assertEqual(
+ {'a': 'aaa;b;c', 'd': 'ddd'},
+ utils.str2dict('a:aaa;b;c;d:ddd'))
+
+ self.assertEqual({}, utils.str2dict(""))
+ self.assertEqual({}, utils.str2dict(None))
+
+ self.assertRaises(
+ exceptions.CommandError,
+ utils.str2dict, "aaa;b:2")