python-openstackclient 7.1.2__py3-none-any.whl → 7.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. openstackclient/api/api.py +2 -1
  2. openstackclient/api/image_v2.py +1 -1
  3. openstackclient/api/object_store_v1.py +12 -20
  4. openstackclient/common/clientmanager.py +1 -1
  5. openstackclient/common/module.py +2 -2
  6. openstackclient/common/quota.py +4 -4
  7. openstackclient/compute/v2/flavor.py +1 -1
  8. openstackclient/compute/v2/server.py +123 -60
  9. openstackclient/compute/v2/server_backup.py +1 -1
  10. openstackclient/compute/v2/server_image.py +1 -1
  11. openstackclient/compute/v2/server_migration.py +11 -2
  12. openstackclient/compute/v2/usage.py +3 -3
  13. openstackclient/identity/common.py +4 -1
  14. openstackclient/identity/v2_0/project.py +1 -1
  15. openstackclient/identity/v2_0/role_assignment.py +1 -1
  16. openstackclient/identity/v2_0/user.py +2 -2
  17. openstackclient/identity/v3/access_rule.py +26 -14
  18. openstackclient/identity/v3/identity_provider.py +1 -1
  19. openstackclient/identity/v3/project.py +1 -1
  20. openstackclient/identity/v3/role_assignment.py +24 -3
  21. openstackclient/identity/v3/service.py +2 -1
  22. openstackclient/identity/v3/user.py +35 -15
  23. openstackclient/image/v2/image.py +13 -13
  24. openstackclient/image/v2/metadef_objects.py +6 -4
  25. openstackclient/network/common.py +8 -7
  26. openstackclient/network/v2/floating_ip.py +6 -2
  27. openstackclient/network/v2/floating_ip_port_forwarding.py +2 -2
  28. openstackclient/network/v2/l3_conntrack_helper.py +1 -1
  29. openstackclient/network/v2/ndp_proxy.py +1 -0
  30. openstackclient/network/v2/network_agent.py +2 -6
  31. openstackclient/network/v2/network_qos_rule.py +2 -5
  32. openstackclient/network/v2/network_trunk.py +5 -4
  33. openstackclient/network/v2/port.py +18 -3
  34. openstackclient/network/v2/router.py +7 -4
  35. openstackclient/network/v2/subnet_pool.py +2 -2
  36. openstackclient/shell.py +3 -2
  37. openstackclient/tests/functional/common/test_help.py +3 -9
  38. openstackclient/tests/functional/common/test_module.py +1 -1
  39. openstackclient/tests/functional/common/test_quota.py +2 -4
  40. openstackclient/tests/functional/compute/v2/common.py +1 -3
  41. openstackclient/tests/functional/compute/v2/test_hypervisor.py +3 -3
  42. openstackclient/tests/functional/compute/v2/test_keypair.py +2 -2
  43. openstackclient/tests/functional/compute/v2/test_server.py +1 -1
  44. openstackclient/tests/functional/identity/v2/common.py +31 -48
  45. openstackclient/tests/functional/identity/v2/test_catalog.py +1 -1
  46. openstackclient/tests/functional/identity/v2/test_ec2_credentials.py +2 -2
  47. openstackclient/tests/functional/identity/v2/test_endpoint.py +2 -2
  48. openstackclient/tests/functional/identity/v2/test_project.py +8 -8
  49. openstackclient/tests/functional/identity/v2/test_role.py +14 -34
  50. openstackclient/tests/functional/identity/v2/test_service.py +2 -2
  51. openstackclient/tests/functional/identity/v2/test_token.py +1 -1
  52. openstackclient/tests/functional/identity/v2/test_user.py +7 -9
  53. openstackclient/tests/functional/identity/v3/common.py +69 -110
  54. openstackclient/tests/functional/identity/v3/test_access_rule.py +86 -0
  55. openstackclient/tests/functional/identity/v3/test_application_credential.py +18 -44
  56. openstackclient/tests/functional/identity/v3/test_catalog.py +1 -1
  57. openstackclient/tests/functional/identity/v3/test_domain.py +9 -11
  58. openstackclient/tests/functional/identity/v3/test_endpoint.py +15 -27
  59. openstackclient/tests/functional/identity/v3/test_group.py +32 -93
  60. openstackclient/tests/functional/identity/v3/test_idp.py +3 -3
  61. openstackclient/tests/functional/identity/v3/test_limit.py +32 -32
  62. openstackclient/tests/functional/identity/v3/test_project.py +17 -26
  63. openstackclient/tests/functional/identity/v3/test_region.py +6 -7
  64. openstackclient/tests/functional/identity/v3/test_registered_limit.py +27 -36
  65. openstackclient/tests/functional/identity/v3/test_role.py +30 -60
  66. openstackclient/tests/functional/identity/v3/test_role_assignment.py +33 -80
  67. openstackclient/tests/functional/identity/v3/test_service.py +7 -13
  68. openstackclient/tests/functional/identity/v3/test_service_provider.py +3 -3
  69. openstackclient/tests/functional/identity/v3/test_user.py +17 -34
  70. openstackclient/tests/functional/image/v2/test_image.py +1 -3
  71. openstackclient/tests/functional/network/v2/common.py +1 -3
  72. openstackclient/tests/functional/network/v2/test_default_security_group_rule.py +3 -8
  73. openstackclient/tests/functional/network/v2/test_l3_conntrack_helper.py +27 -31
  74. openstackclient/tests/functional/network/v2/test_network.py +9 -12
  75. openstackclient/tests/functional/network/v2/test_network_agent.py +15 -20
  76. openstackclient/tests/functional/network/v2/test_network_flavor.py +2 -2
  77. openstackclient/tests/functional/network/v2/test_network_ndp_proxy.py +17 -39
  78. openstackclient/tests/functional/network/v2/test_network_qos_rule.py +48 -63
  79. openstackclient/tests/functional/network/v2/test_network_qos_rule_type.py +1 -1
  80. openstackclient/tests/functional/network/v2/test_network_segment_range.py +2 -2
  81. openstackclient/tests/functional/network/v2/test_network_trunk.py +15 -25
  82. openstackclient/tests/functional/network/v2/test_port.py +28 -34
  83. openstackclient/tests/functional/network/v2/test_router.py +13 -19
  84. openstackclient/tests/functional/object/v1/test_object.py +4 -7
  85. openstackclient/tests/functional/volume/base.py +5 -17
  86. openstackclient/tests/functional/volume/v1/test_volume_type.py +11 -11
  87. openstackclient/tests/functional/volume/v2/test_volume_backup.py +1 -1
  88. openstackclient/tests/functional/volume/v2/test_volume_type.py +13 -15
  89. openstackclient/tests/functional/volume/v3/test_volume_type.py +13 -15
  90. openstackclient/tests/unit/api/test_compute_v2.py +0 -5
  91. openstackclient/tests/unit/api/test_object_store_v1.py +6 -4
  92. openstackclient/tests/unit/common/test_extension.py +24 -31
  93. openstackclient/tests/unit/compute/v2/test_host.py +0 -1
  94. openstackclient/tests/unit/compute/v2/test_server.py +124 -116
  95. openstackclient/tests/unit/identity/v3/test_access_rule.py +65 -64
  96. openstackclient/tests/unit/identity/v3/test_group.py +4 -10
  97. openstackclient/tests/unit/identity/v3/test_limit.py +2 -2
  98. openstackclient/tests/unit/identity/v3/test_service.py +0 -3
  99. openstackclient/tests/unit/identity/v3/test_user.py +4 -90
  100. openstackclient/tests/unit/image/v2/test_metadef_objects.py +1 -2
  101. openstackclient/tests/unit/image/v2/test_metadef_resource_type_association.py +2 -6
  102. openstackclient/tests/unit/integ/base.py +1 -1
  103. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +3 -3
  104. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +4 -4
  105. openstackclient/tests/unit/network/v2/test_local_ip_association.py +2 -2
  106. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +12 -13
  107. openstackclient/tests/unit/network/v2/test_network_trunk.py +31 -35
  108. openstackclient/tests/unit/network/v2/test_port.py +40 -17
  109. openstackclient/tests/unit/network/v2/test_subnet_pool.py +1 -1
  110. openstackclient/tests/unit/object/v1/test_object.py +1 -1
  111. openstackclient/tests/unit/utils.py +2 -2
  112. openstackclient/volume/client.py +1 -1
  113. openstackclient/volume/v1/volume.py +2 -2
  114. openstackclient/volume/v1/volume_backup.py +2 -2
  115. openstackclient/volume/v1/volume_snapshot.py +2 -2
  116. openstackclient/volume/v2/volume.py +2 -2
  117. openstackclient/volume/v2/volume_backup.py +2 -2
  118. openstackclient/volume/v2/volume_snapshot.py +2 -2
  119. openstackclient/volume/v2/volume_type.py +4 -4
  120. openstackclient/volume/v3/service.py +0 -1
  121. openstackclient/volume/v3/volume.py +3 -3
  122. openstackclient/volume/v3/volume_backup.py +2 -2
  123. openstackclient/volume/v3/volume_group.py +3 -7
  124. openstackclient/volume/v3/volume_type.py +6 -6
  125. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/AUTHORS +3 -0
  126. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/METADATA +2 -3
  127. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/RECORD +132 -131
  128. python_openstackclient-7.2.0.dist-info/pbr.json +1 -0
  129. python_openstackclient-7.1.2.dist-info/pbr.json +0 -1
  130. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/LICENSE +0 -0
  131. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/WHEEL +0 -0
  132. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/entry_points.txt +0 -0
  133. {python_openstackclient-7.1.2.dist-info → python_openstackclient-7.2.0.dist-info}/top_level.txt +0 -0
@@ -11,7 +11,7 @@
11
11
  # under the License.
12
12
  #
13
13
 
14
- """Identity v2 Assignment action implementations """
14
+ """Identity v2 Assignment action implementations"""
15
15
 
16
16
  from osc_lib.command import command
17
17
  from osc_lib import exceptions
@@ -250,9 +250,9 @@ class ListUser(command.Lister):
250
250
  try:
251
251
  for p in identity_client.tenants.list():
252
252
  project_cache[p.id] = p
253
- except Exception:
253
+ except Exception: # noqa: S110
254
254
  # Just forget it if there's any trouble
255
- pass # nosec: B110
255
+ pass
256
256
  formatters['tenantId'] = functools.partial(
257
257
  ProjectColumn, project_cache=project_cache
258
258
  )
@@ -42,15 +42,15 @@ class DeleteAccessRule(command.Command):
42
42
  return parser
43
43
 
44
44
  def take_action(self, parsed_args):
45
- identity_client = self.app.client_manager.identity
45
+ identity_client = self.app.client_manager.sdk_connection.identity
46
+ conn = self.app.client_manager.sdk_connection
47
+ user_id = conn.config.get_auth().get_user_id(conn.identity)
46
48
 
47
49
  errors = 0
48
50
  for ac in parsed_args.access_rule:
49
51
  try:
50
- access_rule = common.get_resource_by_id(
51
- identity_client.access_rules, ac
52
- )
53
- identity_client.access_rules.delete(access_rule.id)
52
+ access_rule = identity_client.get_access_rule(user_id, ac)
53
+ identity_client.delete_access_rule(user_id, access_rule.id)
54
54
  except Exception as e:
55
55
  errors += 1
56
56
  LOG.error(
@@ -83,16 +83,17 @@ class ListAccessRule(command.Lister):
83
83
  return parser
84
84
 
85
85
  def take_action(self, parsed_args):
86
- identity_client = self.app.client_manager.identity
86
+ identity_client = self.app.client_manager.sdk_connection.identity
87
87
  if parsed_args.user:
88
88
  user_id = common.find_user(
89
89
  identity_client, parsed_args.user, parsed_args.user_domain
90
90
  ).id
91
91
  else:
92
- user_id = None
92
+ conn = self.app.client_manager.sdk_connection
93
+ user_id = conn.config.get_auth().get_user_id(conn.identity)
93
94
 
94
95
  columns = ('ID', 'Service', 'Method', 'Path')
95
- data = identity_client.access_rules.list(user=user_id)
96
+ data = identity_client.access_rules(user=user_id)
96
97
  return (
97
98
  columns,
98
99
  (
@@ -119,11 +120,22 @@ class ShowAccessRule(command.ShowOne):
119
120
  return parser
120
121
 
121
122
  def take_action(self, parsed_args):
122
- identity_client = self.app.client_manager.identity
123
- access_rule = common.get_resource_by_id(
124
- identity_client.access_rules, parsed_args.access_rule
125
- )
123
+ identity_client = self.app.client_manager.sdk_connection.identity
124
+ conn = self.app.client_manager.sdk_connection
125
+ user_id = conn.config.get_auth().get_user_id(conn.identity)
126
126
 
127
- access_rule._info.pop('links', None)
127
+ access_rule = identity_client.get_access_rule(
128
+ user_id, parsed_args.access_rule
129
+ )
128
130
 
129
- return zip(*sorted(access_rule._info.items()))
131
+ columns = ('ID', 'Method', 'Path', 'Service')
132
+ return (
133
+ columns,
134
+ (
135
+ utils.get_item_properties(
136
+ access_rule,
137
+ columns,
138
+ formatters={},
139
+ )
140
+ ),
141
+ )
@@ -133,7 +133,7 @@ class CreateIdentityProvider(command.ShowOne):
133
133
  description=parsed_args.description,
134
134
  domain_id=domain_id,
135
135
  enabled=parsed_args.enabled,
136
- **kwargs
136
+ **kwargs,
137
137
  )
138
138
 
139
139
  idp._info.pop('links', None)
@@ -125,7 +125,7 @@ class CreateProject(command.ShowOne):
125
125
  description=parsed_args.description,
126
126
  enabled=enabled,
127
127
  options=options,
128
- **kwargs
128
+ **kwargs,
129
129
  )
130
130
  except ks_exc.Conflict:
131
131
  if parsed_args.or_show:
@@ -146,12 +146,19 @@ class ListRoleAssignment(command.Lister):
146
146
  domain_id=role_domain_id,
147
147
  )
148
148
 
149
+ user_domain_id = None
150
+ if parsed_args.user_domain:
151
+ project_domain_id = _find_sdk_id(
152
+ identity_client.find_domain,
153
+ name_or_id=parsed_args.user_domain,
154
+ )
155
+
149
156
  user_id = None
150
157
  if parsed_args.user:
151
158
  user_id = _find_sdk_id(
152
159
  identity_client.find_user,
153
160
  name_or_id=parsed_args.user,
154
- domain_id=parsed_args.user_domain,
161
+ domain_id=user_domain_id,
155
162
  )
156
163
  elif parsed_args.authuser:
157
164
  if auth_ref:
@@ -171,6 +178,13 @@ class ListRoleAssignment(command.Lister):
171
178
  name_or_id=parsed_args.domain,
172
179
  )
173
180
 
181
+ project_domain_id = None
182
+ if parsed_args.project_domain:
183
+ project_domain_id = _find_sdk_id(
184
+ identity_client.find_domain,
185
+ name_or_id=parsed_args.project_domain,
186
+ )
187
+
174
188
  project_id = None
175
189
  if parsed_args.project:
176
190
  project_id = _find_sdk_id(
@@ -178,7 +192,7 @@ class ListRoleAssignment(command.Lister):
178
192
  name_or_id=common._get_token_resource(
179
193
  identity_client, 'project', parsed_args.project
180
194
  ),
181
- domain_id=parsed_args.project_domain,
195
+ domain_id=project_domain_id,
182
196
  )
183
197
  elif parsed_args.authproject:
184
198
  if auth_ref:
@@ -187,12 +201,19 @@ class ListRoleAssignment(command.Lister):
187
201
  name_or_id=auth_ref.project_id,
188
202
  )
189
203
 
204
+ group_domain_id = None
205
+ if parsed_args.group_domain:
206
+ group_domain_id = _find_sdk_id(
207
+ identity_client.find_domain,
208
+ name_or_id=parsed_args.group_domain,
209
+ )
210
+
190
211
  group_id = None
191
212
  if parsed_args.group:
192
213
  group_id = _find_sdk_id(
193
214
  identity_client.find_group,
194
215
  name_or_id=parsed_args.group,
195
- domain_id=parsed_args.group_domain,
216
+ domain_id=group_domain_id,
196
217
  )
197
218
 
198
219
  include_names = True if parsed_args.names else None
@@ -225,7 +225,8 @@ class SetService(command.Command):
225
225
  kwargs['name'] = parsed_args.name
226
226
  if parsed_args.description:
227
227
  kwargs['description'] = parsed_args.description
228
- kwargs['is_enabled'] = parsed_args.is_enabled
228
+ if parsed_args.is_enabled is not None:
229
+ kwargs['is_enabled'] = parsed_args.is_enabled
229
230
 
230
231
  identity_client.update_service(service.id, **kwargs)
231
232
 
@@ -249,26 +249,44 @@ class CreateUser(command.ShowOne):
249
249
  def take_action(self, parsed_args):
250
250
  identity_client = self.app.client_manager.sdk_connection.identity
251
251
 
252
+ kwargs = {}
253
+
252
254
  domain_id = None
253
255
  if parsed_args.domain:
254
256
  domain_id = identity_client.find_domain(
255
- name_or_id=parsed_args.domain,
257
+ parsed_args.domain,
256
258
  ignore_missing=False,
257
259
  ).id
260
+ kwargs['domain_id'] = domain_id
258
261
 
259
- project_id = None
260
262
  if parsed_args.project:
261
- project_id = identity_client.find_project(
262
- name_or_id=parsed_args.project,
263
+ project_domain_id = None
264
+ if parsed_args.project_domain:
265
+ project_domain_id = identity_client.find_domain(
266
+ parsed_args.project_domain,
267
+ ignore_missing=False,
268
+ ).id
269
+ kwargs['default_project_id'] = identity_client.find_project(
270
+ parsed_args.project,
263
271
  ignore_missing=False,
264
- domain_id=domain_id,
272
+ domain_id=project_domain_id,
265
273
  ).id
266
274
 
275
+ if parsed_args.description:
276
+ kwargs['description'] = parsed_args.description
277
+
278
+ if parsed_args.email:
279
+ kwargs['email'] = parsed_args.email
280
+
267
281
  is_enabled = True
268
282
  if parsed_args.disable:
269
283
  is_enabled = False
270
- if parsed_args.password_prompt:
271
- parsed_args.password = utils.get_password(self.app.stdin)
284
+
285
+ password = None
286
+ if parsed_args.password:
287
+ password = parsed_args.password
288
+ elif parsed_args.password_prompt:
289
+ password = utils.get_password(self.app.stdin)
272
290
 
273
291
  if not parsed_args.password:
274
292
  LOG.warning(
@@ -278,24 +296,26 @@ class CreateUser(command.ShowOne):
278
296
  )
279
297
  )
280
298
  options = _get_options_for_user(identity_client, parsed_args)
299
+ if options:
300
+ kwargs['options'] = options
281
301
 
282
302
  try:
283
303
  user = identity_client.create_user(
284
- default_project_id=project_id,
285
- description=parsed_args.description,
286
- domain_id=domain_id,
287
- email=parsed_args.email,
288
304
  is_enabled=is_enabled,
289
305
  name=parsed_args.name,
290
- password=parsed_args.password,
291
- options=options,
306
+ password=password,
307
+ **kwargs,
292
308
  )
293
309
  except sdk_exc.ConflictException:
294
310
  if parsed_args.or_show:
311
+ kwargs = {}
312
+ if domain_id:
313
+ kwargs['domain_id'] = domain_id
314
+
295
315
  user = identity_client.find_user(
296
- name_or_id=parsed_args.name,
297
- domain_id=domain_id,
316
+ parsed_args.name,
298
317
  ignore_missing=False,
318
+ **kwargs,
299
319
  )
300
320
  LOG.info(_('Returning existing user %s'), user.name)
301
321
  else:
@@ -421,8 +421,8 @@ class CreateImage(command.ShowOne):
421
421
  identity_common.add_project_domain_option_to_parser(parser)
422
422
  for deadopt in self.deadopts:
423
423
  parser.add_argument(
424
- "--%s" % deadopt,
425
- metavar="<%s>" % deadopt,
424
+ f"--{deadopt}",
425
+ metavar=f"<{deadopt}>",
426
426
  dest=deadopt.replace('-', '_'),
427
427
  help=argparse.SUPPRESS,
428
428
  )
@@ -488,7 +488,7 @@ class CreateImage(command.ShowOne):
488
488
  fp = open(parsed_args.filename, 'rb')
489
489
  except FileNotFoundError:
490
490
  raise exceptions.CommandError(
491
- '%r is not a valid file' % parsed_args.filename,
491
+ f'{parsed_args.filename!r} is not a valid file',
492
492
  )
493
493
  else:
494
494
  fp = get_data_from_stdin()
@@ -1209,8 +1209,8 @@ class SetImage(command.Command):
1209
1209
  identity_common.add_project_domain_option_to_parser(parser)
1210
1210
  for deadopt in self.deadopts:
1211
1211
  parser.add_argument(
1212
- "--%s" % deadopt,
1213
- metavar="<%s>" % deadopt,
1212
+ f"--{deadopt}",
1213
+ metavar=f"<{deadopt}>",
1214
1214
  dest=f"dead_{deadopt.replace('-', '_')}",
1215
1215
  help=argparse.SUPPRESS,
1216
1216
  )
@@ -1575,7 +1575,7 @@ class StageImage(command.Command):
1575
1575
  fp = open(parsed_args.filename, 'rb')
1576
1576
  except FileNotFoundError:
1577
1577
  raise exceptions.CommandError(
1578
- '%r is not a valid file' % parsed_args.filename,
1578
+ f'{parsed_args.filename!r} is not a valid file',
1579
1579
  )
1580
1580
  else:
1581
1581
  fp = get_data_from_stdin()
@@ -1614,8 +1614,6 @@ class ImportImage(command.ShowOne):
1614
1614
  metavar='<image>',
1615
1615
  help=_('Image to initiate import process for (name or ID)'),
1616
1616
  )
1617
- # TODO(stephenfin): Uncomment help text when we have this command
1618
- # implemented
1619
1617
  parser.add_argument(
1620
1618
  '--method',
1621
1619
  metavar='<method>',
@@ -1630,8 +1628,6 @@ class ImportImage(command.ShowOne):
1630
1628
  help=_(
1631
1629
  "Import method used for image import process. "
1632
1630
  "Not all deployments will support all methods. "
1633
- # "Valid values can be retrieved with the 'image import "
1634
- # "methods' command. "
1635
1631
  "The 'glance-direct' method (default) requires images be "
1636
1632
  "first staged using the 'image-stage' command."
1637
1633
  ),
@@ -1734,11 +1730,15 @@ class ImportImage(command.ShowOne):
1734
1730
 
1735
1731
  if parsed_args.import_method not in import_methods:
1736
1732
  msg = _(
1737
- "The '%s' import method is not supported by this deployment. "
1738
- "Supported: %s"
1733
+ "The '%(method)s' import method is not supported by this "
1734
+ "deployment. Supported: %(supported)s"
1739
1735
  )
1740
1736
  raise exceptions.CommandError(
1741
- msg % (parsed_args.import_method, ', '.join(import_methods)),
1737
+ msg
1738
+ % {
1739
+ 'method': parsed_args.import_method,
1740
+ 'supported': ', '.join(import_methods),
1741
+ },
1742
1742
  )
1743
1743
 
1744
1744
  if parsed_args.import_method == 'web-download':
@@ -260,10 +260,12 @@ class ShowMetadefObjectProperty(command.ShowOne):
260
260
  prop['name'] = parsed_args.property
261
261
 
262
262
  except KeyError:
263
- msg = _('Property %s not found in object %s.') % (
264
- parsed_args.property,
265
- parsed_args.object,
266
- )
263
+ msg = _(
264
+ 'Property %(property)s not found in object %(object)s.'
265
+ ) % {
266
+ 'property': parsed_args.property,
267
+ 'object': parsed_args.object,
268
+ }
267
269
  raise exceptions.CommandError(msg)
268
270
 
269
271
  return zip(*sorted(prop.items()))
@@ -120,13 +120,14 @@ class NetDetectionMixin(metaclass=abc.ABCMeta):
120
120
  @staticmethod
121
121
  def split_help(network_help, compute_help):
122
122
  return (
123
- "*%(network_qualifier)s:*\n %(network_help)s\n\n"
124
- "*%(compute_qualifier)s:*\n %(compute_help)s"
125
- % dict(
126
- network_qualifier=_("Network version 2"),
127
- network_help=network_help,
128
- compute_qualifier=_("Compute version 2"),
129
- compute_help=compute_help,
123
+ "*{network_qualifier}:*\n {network_help}\n\n"
124
+ "*{compute_qualifier}:*\n {compute_help}".format(
125
+ **dict(
126
+ network_qualifier=_("Network version 2"),
127
+ network_help=network_help,
128
+ compute_qualifier=_("Compute version 2"),
129
+ compute_help=compute_help,
130
+ )
130
131
  )
131
132
  )
132
133
 
@@ -12,6 +12,7 @@
12
12
 
13
13
  """IP Floating action implementations"""
14
14
 
15
+ from openstack import exceptions as sdk_exceptions
15
16
  from osc_lib import utils
16
17
  from osc_lib.utils import tags as _tag
17
18
 
@@ -390,7 +391,10 @@ class ListFloatingIP(common.NetworkAndComputeLister):
390
391
 
391
392
  _tag.get_tag_filtering_args(parsed_args, query)
392
393
 
393
- data = client.ips(**query)
394
+ try:
395
+ data = list(client.ips(**query))
396
+ except sdk_exceptions.NotFoundException:
397
+ data = []
394
398
 
395
399
  return (
396
400
  headers,
@@ -448,7 +452,7 @@ class SetFloatingIP(common.NeutronCommandWithExtraArgs):
448
452
  '--port',
449
453
  metavar='<port>',
450
454
  help=_("Associate the floating IP with port (name or ID)"),
451
- ),
455
+ )
452
456
  parser.add_argument(
453
457
  '--fixed-ip-address',
454
458
  metavar='<ip-address>',
@@ -144,7 +144,7 @@ class CreateFloatingIPPortForwarding(
144
144
  "The protocol used in the floating IP "
145
145
  "port forwarding, for instance: TCP, UDP"
146
146
  ),
147
- ),
147
+ )
148
148
  parser.add_argument(
149
149
  '--description',
150
150
  metavar='<description>',
@@ -404,7 +404,7 @@ class SetFloatingIPPortForwarding(common.NeutronCommandWithExtraArgs):
404
404
  metavar='<protocol>',
405
405
  choices=['tcp', 'udp'],
406
406
  help=_("The IP protocol used in the floating IP port forwarding"),
407
- ),
407
+ )
408
408
  parser.add_argument(
409
409
  '--description',
410
410
  metavar='<description>',
@@ -245,7 +245,7 @@ class SetConntrackHelper(command.Command):
245
245
  client.update_conntrack_helper(
246
246
  parsed_args.conntrack_helper_id,
247
247
  attrs.pop('router_id'),
248
- **attrs
248
+ **attrs,
249
249
  )
250
250
 
251
251
 
@@ -14,6 +14,7 @@
14
14
  # under the License.
15
15
 
16
16
  """Router NDP proxy action implementations"""
17
+
17
18
  import logging
18
19
 
19
20
  from osc_lib.command import command
@@ -89,9 +89,7 @@ class AddNetworkToAgent(command.Command):
89
89
  try:
90
90
  client.add_dhcp_agent_to_network(agent, network)
91
91
  except Exception:
92
- msg = 'Failed to add {} to {}'.format(
93
- network.name, agent.agent_type
94
- )
92
+ msg = f'Failed to add {network.name} to {agent.agent_type}'
95
93
  exceptions.CommandError(msg)
96
94
 
97
95
 
@@ -321,9 +319,7 @@ class RemoveNetworkFromAgent(command.Command):
321
319
  try:
322
320
  client.remove_dhcp_agent_from_network(agent, network)
323
321
  except Exception:
324
- msg = 'Failed to remove {} to {}'.format(
325
- network.name, agent.agent_type
326
- )
322
+ msg = f'Failed to remove {network.name} to {agent.agent_type}'
327
323
  exceptions.CommandError(msg)
328
324
 
329
325
 
@@ -159,10 +159,7 @@ def _get_item_properties(item, fields):
159
159
 
160
160
  def _rule_action_call(client, action, rule_type):
161
161
  rule_type = rule_type.replace('-', '_')
162
- func_name = '{action}_qos_{rule_type}_rule'.format(
163
- action=action,
164
- rule_type=rule_type,
165
- )
162
+ func_name = f'{action}_qos_{rule_type}_rule'
166
163
  return getattr(client, func_name)
167
164
 
168
165
 
@@ -311,7 +308,7 @@ class DeleteNetworkQosRule(command.Command):
311
308
  )
312
309
  rule_type = _find_rule_type(qos, rule_id)
313
310
  if not rule_type:
314
- raise Exception('Rule %s not found' % rule_id)
311
+ raise Exception(f'Rule {rule_id} not found')
315
312
  _rule_action_call(network_client, ACTION_DELETE, rule_type)(
316
313
  rule_id, qos.id
317
314
  )
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  """Network trunk and subports action implementations"""
18
+
18
19
  import logging
19
20
 
20
21
  from cliff import columns as cliff_columns
@@ -67,8 +68,8 @@ class CreateNetworkTrunk(command.ShowOne):
67
68
  required_keys=['port'],
68
69
  help=_(
69
70
  "Subport to add. Subport is of form "
70
- "\'port=<name or ID>,segmentation-type=<segmentation-type>,"
71
- "segmentation-id=<segmentation-ID>\' (--subport) option "
71
+ "'port=<name or ID>,segmentation-type=<segmentation-type>,"
72
+ "segmentation-id=<segmentation-ID>' (--subport) option "
72
73
  "can be repeated"
73
74
  ),
74
75
  )
@@ -198,8 +199,8 @@ class SetNetworkTrunk(command.Command):
198
199
  required_keys=['port'],
199
200
  help=_(
200
201
  "Subport to add. Subport is of form "
201
- "\'port=<name or ID>,segmentation-type=<segmentation-type>"
202
- ",segmentation-id=<segmentation-ID>\' (--subport) option "
202
+ "'port=<name or ID>,segmentation-type=<segmentation-type>"
203
+ ",segmentation-id=<segmentation-ID>' (--subport) option "
203
204
  "can be repeated"
204
205
  ),
205
206
  )
@@ -274,13 +274,13 @@ def _prepare_filter_fixed_ips(client_manager, parsed_args):
274
274
  _subnet = client.find_subnet(
275
275
  subnet_name_id, ignore_missing=False
276
276
  )
277
- ips.append('subnet_id=%s' % _subnet.id)
277
+ ips.append(f'subnet_id={_subnet.id}')
278
278
 
279
279
  if 'ip-address' in ip_spec:
280
- ips.append('ip_address=%s' % ip_spec['ip-address'])
280
+ ips.append('ip_address={}'.format(ip_spec['ip-address']))
281
281
 
282
282
  if 'ip-substring' in ip_spec:
283
- ips.append('ip_address_substr=%s' % ip_spec['ip-substring'])
283
+ ips.append('ip_address_substr={}'.format(ip_spec['ip-substring']))
284
284
  return ips
285
285
 
286
286
 
@@ -792,6 +792,19 @@ class ListPort(command.Lister):
792
792
  metavar='<security-group>',
793
793
  help=_("List only ports associated with this security group"),
794
794
  )
795
+ # the API sadly reports these in upper case and while it would be
796
+ # wonderful to plaster over this ugliness client-side, there are
797
+ # already users in the wild doing this in upper case that we need to
798
+ # support
799
+ parser.add_argument(
800
+ '--status',
801
+ metavar='<status>',
802
+ choices=('ACTIVE', 'BUILD', 'DOWN', 'ERROR'),
803
+ help=_(
804
+ "List ports according to their status "
805
+ "('ACTIVE', 'BUILD', 'DOWN', 'ERROR')"
806
+ ),
807
+ )
795
808
  identity_common.add_project_domain_option_to_parser(parser)
796
809
  parser.add_argument(
797
810
  '--fixed-ip',
@@ -859,6 +872,8 @@ class ListPort(command.Lister):
859
872
  filters['network_id'] = network.id
860
873
  if parsed_args.mac_address:
861
874
  filters['mac_address'] = parsed_args.mac_address
875
+ if parsed_args.status:
876
+ filters['status'] = parsed_args.status
862
877
  if parsed_args.project:
863
878
  project_id = identity_common.find_project(
864
879
  identity_client,
@@ -164,10 +164,13 @@ def _get_external_gateway_attrs(client_manager, parsed_args):
164
164
  'subnet_id' in ip_spec
165
165
  and ip_net_id not in external_gateways
166
166
  ):
167
- msg = _(
168
- 'Subnet %s does not belong to any of the networks '
169
- 'provided for --external-gateway.'
170
- ) % (ip_spec['subnet_id'])
167
+ msg = (
168
+ _(
169
+ 'Subnet %s does not belong to any of the networks '
170
+ 'provided for --external-gateway.'
171
+ )
172
+ % (ip_spec['subnet_id'])
173
+ )
171
174
  raise exceptions.CommandError(msg)
172
175
  for gw_info in external_gateways[ip_net_id]:
173
176
  if 'external_fixed_ips' not in gw_info:
@@ -201,7 +201,7 @@ class CreateSubnetPool(command.ShowOne, common.NeutronCommandWithExtraArgs):
201
201
  "as the number of IP addresses that can be allocated "
202
202
  "from the subnet pool"
203
203
  ),
204
- ),
204
+ )
205
205
  _tag.add_tag_option_to_parser_for_create(parser, _('subnet pool'))
206
206
  return parser
207
207
 
@@ -433,7 +433,7 @@ class SetSubnetPool(common.NeutronCommandWithExtraArgs):
433
433
  "as the number of IP addresses that can be allocated "
434
434
  "from the subnet pool"
435
435
  ),
436
- ),
436
+ )
437
437
  _tag.add_tag_option_to_parser_for_set(parser, _('subnet pool'))
438
438
 
439
439
  return parser
openstackclient/shell.py CHANGED
@@ -96,8 +96,9 @@ class OpenStackShell(shell.OpenStackShell):
96
96
  key=lambda s: list(map(int, s.split('.'))),
97
97
  )
98
98
  self.log.warning(
99
- "%s version %s is not in supported versions: %s"
100
- % (api, version_opt, ', '.join(sorted_versions))
99
+ "{} version {} is not in supported versions: {}".format(
100
+ api, version_opt, ', '.join(sorted_versions)
101
+ )
101
102
  )
102
103
 
103
104
  # Command groups deal only with major versions
@@ -21,7 +21,7 @@ class HelpTests(base.TestCase):
21
21
  """Functional tests for openstackclient help output."""
22
22
 
23
23
  SERVER_COMMANDS = [
24
- ('server add security group', 'Add security group to server'),
24
+ ('server add security group', 'Add security group(s) to server'),
25
25
  ('server add volume', 'Add volume to server'),
26
26
  ('server backup create', 'Create a server backup image'),
27
27
  ('server create', 'Create a new server'),
@@ -60,15 +60,9 @@ class HelpTests(base.TestCase):
60
60
  """Check server commands in main help message."""
61
61
  raw_output = self.openstack('help')
62
62
  for command, description in self.SERVER_COMMANDS:
63
- msg = 'Command: {} not found in help output:\n{}'.format(
64
- command,
65
- raw_output,
66
- )
63
+ msg = f'Command: {command} not found in help output:\n{raw_output}'
67
64
  self.assertIn(command, raw_output, msg)
68
- msg = 'Description: {} not found in help output:\n{}'.format(
69
- description,
70
- raw_output,
71
- )
65
+ msg = f'Description: {description} not found in help output:\n{raw_output}'
72
66
  self.assertIn(description, raw_output, msg)
73
67
 
74
68
  def test_server_only_help(self):