Skip to content

Commit 443c311

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Allow to send extra attributes in Neutron related commands"
2 parents 84a606b + b26b7f3 commit 443c311

26 files changed

Lines changed: 486 additions & 49 deletions

lower-constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ msgpack-python==0.4.0
3838
munch==2.1.0
3939
netaddr==0.7.18
4040
netifaces==0.10.4
41-
openstacksdk==0.53.0
41+
openstacksdk==0.56.0
4242
os-client-config==2.1.0
4343
os-service-types==1.7.0
4444
osc-lib==2.3.0

openstackclient/network/common.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
import logging
1717

1818
import openstack.exceptions
19+
from osc_lib.cli import parseractions
1920
from osc_lib.command import command
2021
from osc_lib import exceptions
2122

2223
from openstackclient.i18n import _
24+
from openstackclient.network import utils
2325

2426

2527
LOG = logging.getLogger(__name__)
@@ -75,7 +77,6 @@ def _network_type(self):
7577
"""
7678
# Have we set it up yet for this command?
7779
if not hasattr(self, '_net_type'):
78-
# import pdb; pdb.set_trace()
7980
try:
8081
if self.app.client_manager.is_network_endpoint_enabled():
8182
net_type = _NET_TYPE_NEUTRON
@@ -255,3 +256,74 @@ def take_action(self, parsed_args):
255256
if exc.details:
256257
msg += ", " + str(exc.details)
257258
raise exceptions.CommandError(msg)
259+
260+
261+
class NeutronCommandWithExtraArgs(command.Command):
262+
"""Create and Update commands with additional extra properties.
263+
264+
Extra properties can be passed to the command and are then send to the
265+
Neutron as given to the command.
266+
"""
267+
268+
# dict of allowed types
269+
_allowed_types_dict = {
270+
'bool': utils.str2bool,
271+
'dict': utils.str2dict,
272+
'list': utils.str2list,
273+
'int': int,
274+
'str': str,
275+
}
276+
277+
def _get_property_converter(self, _property):
278+
if 'type' not in _property:
279+
converter = str
280+
else:
281+
converter = self._allowed_types_dict.get(_property['type'])
282+
283+
if not converter:
284+
raise exceptions.CommandError(
285+
_("Type {property_type} of property {name} "
286+
"is not supported").format(
287+
property_type=_property['type'],
288+
name=_property['name']))
289+
return converter
290+
291+
def _parse_extra_properties(self, extra_properties):
292+
result = {}
293+
if extra_properties:
294+
for _property in extra_properties:
295+
converter = self._get_property_converter(_property)
296+
result[_property['name']] = converter(_property['value'])
297+
return result
298+
299+
def get_parser(self, prog_name):
300+
parser = super(NeutronCommandWithExtraArgs, self).get_parser(prog_name)
301+
parser.add_argument(
302+
'--extra-property',
303+
metavar='type=<property_type>,name=<property_name>,'
304+
'value=<property_value>',
305+
dest='extra_properties',
306+
action=parseractions.MultiKeyValueAction,
307+
required_keys=['name', 'value'],
308+
optional_keys=['type'],
309+
help=_("Additional parameters can be passed using this property. "
310+
"Default type of the extra property is string ('str'), but "
311+
"other types can be used as well. Available types are: "
312+
"'dict', 'list', 'str', 'bool', 'int'. "
313+
"In case of 'list' type, 'value' can be "
314+
"semicolon-separated list of values. "
315+
"For 'dict' value is semicolon-separated list of the "
316+
"key:value pairs.")
317+
)
318+
return parser
319+
320+
321+
class NeutronUnsetCommandWithExtraArgs(NeutronCommandWithExtraArgs):
322+
323+
def _parse_extra_properties(self, extra_properties):
324+
result = {}
325+
if extra_properties:
326+
for _property in extra_properties:
327+
result[_property['name']] = None
328+
329+
return result

openstackclient/network/utils.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
# under the License.
1212
#
1313

14+
from osc_lib import exceptions
15+
16+
from openstackclient.i18n import _
17+
1418

1519
# Transform compute security group rule for display.
1620
def transform_compute_security_group_rule(sg_rule):
@@ -39,3 +43,41 @@ def transform_compute_security_group_rule(sg_rule):
3943
else:
4044
info['remote_security_group'] = ''
4145
return info
46+
47+
48+
def str2bool(strbool):
49+
if strbool is None:
50+
return None
51+
return strbool.lower() == 'true'
52+
53+
54+
def str2list(strlist):
55+
result = []
56+
if strlist:
57+
result = strlist.split(';')
58+
return result
59+
60+
61+
def str2dict(strdict):
62+
"""Convert key1:value1;key2:value2;... string into dictionary.
63+
64+
:param strdict: string in the form of key1:value1;key2:value2
65+
"""
66+
result = {}
67+
if not strdict:
68+
return result
69+
i = 0
70+
kvlist = []
71+
for kv in strdict.split(';'):
72+
if ':' in kv:
73+
kvlist.append(kv)
74+
i += 1
75+
elif i == 0:
76+
msg = _("missing value for key '%s'")
77+
raise exceptions.CommandError(msg % kv)
78+
else:
79+
kvlist[i - 1] = "%s;%s" % (kvlist[i - 1], kv)
80+
for kv in kvlist:
81+
key, sep, value = kv.partition(':')
82+
result[key] = value
83+
return result

openstackclient/network/v2/address_group.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from openstackclient.i18n import _
2424
from openstackclient.identity import common as identity_common
25+
from openstackclient.network import common
2526
from openstackclient.network import sdk_utils
2627

2728

@@ -57,7 +58,7 @@ def _get_attrs(client_manager, parsed_args):
5758
return attrs
5859

5960

60-
class CreateAddressGroup(command.ShowOne):
61+
class CreateAddressGroup(command.ShowOne, common.NeutronCommandWithExtraArgs):
6162
_description = _("Create a new Address Group")
6263

6364
def get_parser(self, prog_name):
@@ -93,6 +94,9 @@ def take_action(self, parsed_args):
9394
client = self.app.client_manager.network
9495
attrs = _get_attrs(self.app.client_manager, parsed_args)
9596

97+
attrs.update(
98+
self._parse_extra_properties(parsed_args.extra_properties))
99+
96100
obj = client.create_address_group(**attrs)
97101
display_columns, columns = _get_columns(obj)
98102
data = utils.get_item_properties(obj, columns, formatters={})
@@ -191,7 +195,7 @@ def take_action(self, parsed_args):
191195
) for s in data))
192196

193197

194-
class SetAddressGroup(command.Command):
198+
class SetAddressGroup(common.NeutronCommandWithExtraArgs):
195199
_description = _("Set address group properties")
196200

197201
def get_parser(self, prog_name):
@@ -231,6 +235,9 @@ def take_action(self, parsed_args):
231235
attrs['name'] = parsed_args.name
232236
if parsed_args.description is not None:
233237
attrs['description'] = parsed_args.description
238+
attrs.update(
239+
self._parse_extra_properties(parsed_args.extra_properties))
240+
234241
if attrs:
235242
client.update_address_group(obj, **attrs)
236243
if parsed_args.address:

openstackclient/network/v2/address_scope.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from openstackclient.i18n import _
2323
from openstackclient.identity import common as identity_common
24+
from openstackclient.network import common
2425
from openstackclient.network import sdk_utils
2526

2627

@@ -57,7 +58,7 @@ def _get_attrs(client_manager, parsed_args):
5758

5859
# TODO(rtheis): Use the SDK resource mapped attribute names once the
5960
# OSC minimum requirements include SDK 1.0.
60-
class CreateAddressScope(command.ShowOne):
61+
class CreateAddressScope(command.ShowOne, common.NeutronCommandWithExtraArgs):
6162
_description = _("Create a new Address Scope")
6263

6364
def get_parser(self, prog_name):
@@ -98,6 +99,8 @@ def get_parser(self, prog_name):
9899
def take_action(self, parsed_args):
99100
client = self.app.client_manager.network
100101
attrs = _get_attrs(self.app.client_manager, parsed_args)
102+
attrs.update(
103+
self._parse_extra_properties(parsed_args.extra_properties))
101104
obj = client.create_address_scope(**attrs)
102105
display_columns, columns = _get_columns(obj)
103106
data = utils.get_item_properties(obj, columns, formatters={})
@@ -226,7 +229,7 @@ def take_action(self, parsed_args):
226229

227230
# TODO(rtheis): Use the SDK resource mapped attribute names once the
228231
# OSC minimum requirements include SDK 1.0.
229-
class SetAddressScope(command.Command):
232+
class SetAddressScope(common.NeutronCommandWithExtraArgs):
230233
_description = _("Set address scope properties")
231234

232235
def get_parser(self, prog_name):
@@ -267,6 +270,8 @@ def take_action(self, parsed_args):
267270
attrs['shared'] = True
268271
if parsed_args.no_share:
269272
attrs['shared'] = False
273+
attrs.update(
274+
self._parse_extra_properties(parsed_args.extra_properties))
270275
client.update_address_scope(obj, **attrs)
271276

272277

openstackclient/network/v2/floating_ip.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
"""IP Floating action implementations"""
1515

16-
from osc_lib.command import command
1716
from osc_lib import utils
1817
from osc_lib.utils import tags as _tag
1918

@@ -94,7 +93,8 @@ def _get_attrs(client_manager, parsed_args):
9493
return attrs
9594

9695

97-
class CreateFloatingIP(common.NetworkAndComputeShowOne):
96+
class CreateFloatingIP(common.NetworkAndComputeShowOne,
97+
common.NeutronCommandWithExtraArgs):
9898
_description = _("Create floating IP")
9999

100100
def update_parser_common(self, parser):
@@ -175,6 +175,8 @@ def update_parser_network(self, parser):
175175

176176
def take_action_network(self, client, parsed_args):
177177
attrs = _get_attrs(self.app.client_manager, parsed_args)
178+
attrs.update(
179+
self._parse_extra_properties(parsed_args.extra_properties))
178180
with common.check_missing_extension_if_error(
179181
self.app.client_manager.network, attrs):
180182
obj = client.create_ip(**attrs)
@@ -390,7 +392,7 @@ def take_action_compute(self, client, parsed_args):
390392
) for s in data))
391393

392394

393-
class SetFloatingIP(command.Command):
395+
class SetFloatingIP(common.NeutronCommandWithExtraArgs):
394396
_description = _("Set floating IP Properties")
395397

396398
def get_parser(self, prog_name):
@@ -456,6 +458,9 @@ def take_action(self, parsed_args):
456458
if 'no_qos_policy' in parsed_args and parsed_args.no_qos_policy:
457459
attrs['qos_policy_id'] = None
458460

461+
attrs.update(
462+
self._parse_extra_properties(parsed_args.extra_properties))
463+
459464
if attrs:
460465
client.update_ip(obj, **attrs)
461466

@@ -490,7 +495,7 @@ def take_action_compute(self, client, parsed_args):
490495
return (columns, data)
491496

492497

493-
class UnsetFloatingIP(command.Command):
498+
class UnsetFloatingIP(common.NeutronCommandWithExtraArgs):
494499
_description = _("Unset floating IP Properties")
495500

496501
def get_parser(self, prog_name):
@@ -526,6 +531,8 @@ def take_action(self, parsed_args):
526531
attrs['port_id'] = None
527532
if parsed_args.qos_policy:
528533
attrs['qos_policy_id'] = None
534+
attrs.update(
535+
self._parse_extra_properties(parsed_args.extra_properties))
529536

530537
if attrs:
531538
client.update_ip(obj, **attrs)

openstackclient/network/v2/floating_ip_port_forwarding.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from osc_lib import utils
2020

2121
from openstackclient.i18n import _
22+
from openstackclient.network import common
2223
from openstackclient.network import sdk_utils
2324

2425

@@ -32,7 +33,8 @@ def _get_columns(item):
3233
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
3334

3435

35-
class CreateFloatingIPPortForwarding(command.ShowOne):
36+
class CreateFloatingIPPortForwarding(command.ShowOne,
37+
common.NeutronCommandWithExtraArgs):
3638
_description = _("Create floating IP port forwarding")
3739

3840
def get_parser(self, prog_name):
@@ -122,6 +124,9 @@ def take_action(self, parsed_args):
122124
if parsed_args.description is not None:
123125
attrs['description'] = parsed_args.description
124126

127+
attrs.update(
128+
self._parse_extra_properties(parsed_args.extra_properties))
129+
125130
obj = client.create_floating_ip_port_forwarding(
126131
floating_ip.id,
127132
**attrs
@@ -258,7 +263,7 @@ def take_action(self, parsed_args):
258263
) for s in data))
259264

260265

261-
class SetFloatingIPPortForwarding(command.Command):
266+
class SetFloatingIPPortForwarding(common.NeutronCommandWithExtraArgs):
262267
_description = _("Set floating IP Port Forwarding Properties")
263268

264269
def get_parser(self, prog_name):
@@ -352,6 +357,9 @@ def take_action(self, parsed_args):
352357
if parsed_args.description is not None:
353358
attrs['description'] = parsed_args.description
354359

360+
attrs.update(
361+
self._parse_extra_properties(parsed_args.extra_properties))
362+
355363
client.update_floating_ip_port_forwarding(
356364
floating_ip.id, parsed_args.port_forwarding_id, **attrs)
357365

0 commit comments

Comments
 (0)