python-openstackclient 7.2.1__py3-none-any.whl → 7.3.1__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.
- openstackclient/common/limits.py +1 -1
- openstackclient/common/quota.py +7 -2
- openstackclient/compute/v2/server.py +38 -22
- openstackclient/compute/v2/usage.py +2 -2
- openstackclient/identity/common.py +22 -34
- openstackclient/identity/v3/credential.py +45 -28
- openstackclient/identity/v3/limit.py +15 -0
- openstackclient/identity/v3/region.py +23 -22
- openstackclient/identity/v3/registered_limit.py +18 -0
- openstackclient/identity/v3/role.py +287 -117
- openstackclient/identity/v3/role_assignment.py +1 -1
- openstackclient/identity/v3/service_provider.py +95 -45
- openstackclient/identity/v3/trust.py +114 -75
- openstackclient/image/v2/image.py +3 -0
- openstackclient/network/v2/network.py +33 -0
- openstackclient/network/v2/network_flavor_profile.py +1 -17
- openstackclient/network/v2/port.py +75 -20
- openstackclient/tests/functional/compute/v2/test_server.py +87 -1
- openstackclient/tests/functional/identity/v3/common.py +1 -1
- openstackclient/tests/functional/identity/v3/test_application_credential.py +2 -1
- openstackclient/tests/functional/identity/v3/test_role.py +24 -0
- openstackclient/tests/functional/identity/v3/test_role_assignment.py +8 -0
- openstackclient/tests/functional/identity/v3/test_service_provider.py +1 -5
- openstackclient/tests/functional/network/v2/test_port.py +107 -1
- openstackclient/tests/unit/compute/v2/fakes.py +0 -304
- openstackclient/tests/unit/compute/v2/test_aggregate.py +40 -31
- openstackclient/tests/unit/compute/v2/test_console.py +7 -3
- openstackclient/tests/unit/compute/v2/test_hypervisor.py +60 -53
- openstackclient/tests/unit/compute/v2/test_keypair.py +57 -69
- openstackclient/tests/unit/compute/v2/test_server.py +63 -5
- openstackclient/tests/unit/compute/v2/test_server_group.py +99 -105
- openstackclient/tests/unit/compute/v2/test_server_volume.py +12 -5
- openstackclient/tests/unit/compute/v2/test_service.py +83 -37
- openstackclient/tests/unit/compute/v2/test_usage.py +12 -7
- openstackclient/tests/unit/identity/v2_0/test_catalog.py +3 -6
- openstackclient/tests/unit/identity/v2_0/test_role.py +1 -2
- openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +2 -1
- openstackclient/tests/unit/identity/v2_0/test_token.py +6 -20
- openstackclient/tests/unit/identity/v3/test_catalog.py +2 -5
- openstackclient/tests/unit/identity/v3/test_credential.py +74 -63
- openstackclient/tests/unit/identity/v3/test_project.py +1 -3
- openstackclient/tests/unit/identity/v3/test_region.py +74 -96
- openstackclient/tests/unit/identity/v3/test_role.py +679 -603
- openstackclient/tests/unit/identity/v3/test_role_assignment.py +263 -1
- openstackclient/tests/unit/identity/v3/test_service_provider.py +159 -209
- openstackclient/tests/unit/identity/v3/test_token.py +5 -20
- openstackclient/tests/unit/identity/v3/test_trust.py +137 -155
- openstackclient/tests/unit/image/v2/test_image.py +6 -0
- openstackclient/tests/unit/network/v2/fakes.py +3 -0
- openstackclient/tests/unit/network/v2/test_network.py +25 -0
- openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +0 -35
- openstackclient/tests/unit/network/v2/test_port.py +128 -15
- openstackclient/tests/unit/utils.py +8 -2
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +31 -13
- openstackclient/tests/unit/volume/v3/test_volume_backup.py +34 -13
- openstackclient/volume/v2/volume_backup.py +11 -2
- openstackclient/volume/v3/volume_backup.py +13 -2
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/AUTHORS +2 -0
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/METADATA +14 -16
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/RECORD +65 -65
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/WHEEL +1 -1
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/entry_points.txt +0 -1
- python_openstackclient-7.3.1.dist-info/pbr.json +1 -0
- python_openstackclient-7.2.1.dist-info/pbr.json +0 -1
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/LICENSE +0 -0
- {python_openstackclient-7.2.1.dist-info → python_openstackclient-7.3.1.dist-info}/top_level.txt +0 -0
|
@@ -38,6 +38,20 @@ class AdminStateColumn(cliff_columns.FormattableColumn):
|
|
|
38
38
|
return 'UP' if self._value else 'DOWN'
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
class SubPortColumn(format_columns.ListDictColumn):
|
|
42
|
+
def _retrieve_subports(self):
|
|
43
|
+
if isinstance(self._value, dict):
|
|
44
|
+
self._value = self._value['sub_ports']
|
|
45
|
+
|
|
46
|
+
def human_readable(self):
|
|
47
|
+
self._retrieve_subports()
|
|
48
|
+
return super().human_readable()
|
|
49
|
+
|
|
50
|
+
def machine_readable(self):
|
|
51
|
+
self._retrieve_subports()
|
|
52
|
+
return super().machine_readable()
|
|
53
|
+
|
|
54
|
+
|
|
41
55
|
_formatters = {
|
|
42
56
|
'admin_state_up': AdminStateColumn,
|
|
43
57
|
'is_admin_state_up': AdminStateColumn,
|
|
@@ -52,6 +66,8 @@ _formatters = {
|
|
|
52
66
|
'security_group_ids': format_columns.ListColumn,
|
|
53
67
|
'tags': format_columns.ListColumn,
|
|
54
68
|
}
|
|
69
|
+
_list_formatters = copy.deepcopy(_formatters)
|
|
70
|
+
_list_formatters.update({'trunk_details': SubPortColumn})
|
|
55
71
|
|
|
56
72
|
|
|
57
73
|
def _get_columns(item):
|
|
@@ -93,6 +109,7 @@ def _get_columns(item):
|
|
|
93
109
|
'status': 'status',
|
|
94
110
|
'tags': 'tags',
|
|
95
111
|
'trunk_details': 'trunk_details',
|
|
112
|
+
'trusted': 'trusted',
|
|
96
113
|
'updated_at': 'updated_at',
|
|
97
114
|
}
|
|
98
115
|
return (
|
|
@@ -222,6 +239,10 @@ def _get_attrs(client_manager, parsed_args):
|
|
|
222
239
|
and parsed_args.hardware_offload_type
|
|
223
240
|
):
|
|
224
241
|
attrs['hardware_offload_type'] = parsed_args.hardware_offload_type
|
|
242
|
+
if parsed_args.not_trusted:
|
|
243
|
+
attrs['trusted'] = False
|
|
244
|
+
if parsed_args.trusted:
|
|
245
|
+
attrs['trusted'] = True
|
|
225
246
|
|
|
226
247
|
return attrs
|
|
227
248
|
|
|
@@ -388,6 +409,25 @@ def _add_updatable_args(parser, create=False):
|
|
|
388
409
|
'(repeat option to set multiple hints)'
|
|
389
410
|
),
|
|
390
411
|
)
|
|
412
|
+
port_trusted = parser.add_mutually_exclusive_group()
|
|
413
|
+
port_trusted.add_argument(
|
|
414
|
+
'--trusted',
|
|
415
|
+
action='store_true',
|
|
416
|
+
help=_(
|
|
417
|
+
"Set port to be trusted. This will be populated into the "
|
|
418
|
+
"'binding:profile' dictionary and passed to the services "
|
|
419
|
+
"which expect it in this dictionary (for example, Nova)"
|
|
420
|
+
),
|
|
421
|
+
)
|
|
422
|
+
port_trusted.add_argument(
|
|
423
|
+
'--not-trusted',
|
|
424
|
+
action='store_true',
|
|
425
|
+
help=_(
|
|
426
|
+
"Set port to be not trusted. This will be populated into the "
|
|
427
|
+
"'binding:profile' dictionary and passed to the services "
|
|
428
|
+
"which expect it in this dictionary (for example, Nova)"
|
|
429
|
+
),
|
|
430
|
+
)
|
|
391
431
|
|
|
392
432
|
|
|
393
433
|
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
|
|
@@ -534,7 +574,7 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
|
|
534
574
|
'--security-group',
|
|
535
575
|
metavar='<security-group>',
|
|
536
576
|
action='append',
|
|
537
|
-
dest='
|
|
577
|
+
dest='security_groups',
|
|
538
578
|
help=_(
|
|
539
579
|
"Security group to associate with this port (name or ID) "
|
|
540
580
|
"(repeat option to set multiple security groups)"
|
|
@@ -542,8 +582,9 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
|
|
542
582
|
)
|
|
543
583
|
secgroups.add_argument(
|
|
544
584
|
'--no-security-group',
|
|
545
|
-
|
|
546
|
-
|
|
585
|
+
action='store_const',
|
|
586
|
+
const=[],
|
|
587
|
+
dest='security_groups',
|
|
547
588
|
help=_("Associate no security groups with this port"),
|
|
548
589
|
)
|
|
549
590
|
parser.add_argument(
|
|
@@ -609,13 +650,11 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
|
|
609
650
|
elif parsed_args.no_fixed_ip:
|
|
610
651
|
attrs['fixed_ips'] = []
|
|
611
652
|
|
|
612
|
-
if parsed_args.
|
|
653
|
+
if parsed_args.security_groups is not None:
|
|
613
654
|
attrs['security_group_ids'] = [
|
|
614
655
|
client.find_security_group(sg, ignore_missing=False).id
|
|
615
|
-
for sg in parsed_args.
|
|
656
|
+
for sg in parsed_args.security_groups
|
|
616
657
|
]
|
|
617
|
-
elif parsed_args.no_security_group:
|
|
618
|
-
attrs['security_group_ids'] = []
|
|
619
658
|
|
|
620
659
|
if parsed_args.allowed_address_pairs:
|
|
621
660
|
attrs['allowed_address_pairs'] = _convert_address_pairs(
|
|
@@ -828,25 +867,30 @@ class ListPort(command.Lister):
|
|
|
828
867
|
network_client = self.app.client_manager.network
|
|
829
868
|
identity_client = self.app.client_manager.identity
|
|
830
869
|
|
|
831
|
-
columns =
|
|
870
|
+
columns = [
|
|
832
871
|
'id',
|
|
833
872
|
'name',
|
|
834
873
|
'mac_address',
|
|
835
874
|
'fixed_ips',
|
|
836
875
|
'status',
|
|
837
|
-
|
|
838
|
-
column_headers =
|
|
876
|
+
]
|
|
877
|
+
column_headers = [
|
|
839
878
|
'ID',
|
|
840
879
|
'Name',
|
|
841
880
|
'MAC Address',
|
|
842
881
|
'Fixed IP Addresses',
|
|
843
882
|
'Status',
|
|
844
|
-
|
|
883
|
+
]
|
|
845
884
|
|
|
846
885
|
filters = {}
|
|
847
886
|
if parsed_args.long:
|
|
848
|
-
columns
|
|
849
|
-
|
|
887
|
+
columns.extend(
|
|
888
|
+
['security_groups', 'device_owner', 'tags', 'trunk_details']
|
|
889
|
+
)
|
|
890
|
+
column_headers.extend(
|
|
891
|
+
['Security Groups', 'Device Owner', 'Tags', 'Trunk subports']
|
|
892
|
+
)
|
|
893
|
+
|
|
850
894
|
if parsed_args.device_owner is not None:
|
|
851
895
|
filters['device_owner'] = parsed_args.device_owner
|
|
852
896
|
if parsed_args.device_id is not None:
|
|
@@ -894,6 +938,12 @@ class ListPort(command.Lister):
|
|
|
894
938
|
|
|
895
939
|
data = network_client.ports(fields=columns, **filters)
|
|
896
940
|
|
|
941
|
+
if parsed_args.long:
|
|
942
|
+
columns = [
|
|
943
|
+
'security_group_ids' if item == 'security_groups' else item
|
|
944
|
+
for item in columns
|
|
945
|
+
]
|
|
946
|
+
|
|
897
947
|
headers, attrs = utils.calculate_header_and_attrs(
|
|
898
948
|
column_headers, columns, parsed_args
|
|
899
949
|
)
|
|
@@ -903,7 +953,7 @@ class ListPort(command.Lister):
|
|
|
903
953
|
utils.get_item_properties(
|
|
904
954
|
s,
|
|
905
955
|
attrs,
|
|
906
|
-
formatters=
|
|
956
|
+
formatters=_list_formatters,
|
|
907
957
|
)
|
|
908
958
|
for s in data
|
|
909
959
|
),
|
|
@@ -982,7 +1032,7 @@ class SetPort(common.NeutronCommandWithExtraArgs):
|
|
|
982
1032
|
'--security-group',
|
|
983
1033
|
metavar='<security-group>',
|
|
984
1034
|
action='append',
|
|
985
|
-
dest='
|
|
1035
|
+
dest='security_groups',
|
|
986
1036
|
help=_(
|
|
987
1037
|
"Security group to associate with this port (name or ID) "
|
|
988
1038
|
"(repeat option to set multiple security groups)"
|
|
@@ -1083,7 +1133,7 @@ class SetPort(common.NeutronCommandWithExtraArgs):
|
|
|
1083
1133
|
|
|
1084
1134
|
if parsed_args.no_security_group:
|
|
1085
1135
|
attrs['security_group_ids'] = []
|
|
1086
|
-
if parsed_args.
|
|
1136
|
+
if parsed_args.security_groups:
|
|
1087
1137
|
if 'security_group_ids' not in attrs:
|
|
1088
1138
|
# NOTE(dtroyer): Get existing security groups, iterate the
|
|
1089
1139
|
# list to force a new list object to be
|
|
@@ -1094,7 +1144,7 @@ class SetPort(common.NeutronCommandWithExtraArgs):
|
|
|
1094
1144
|
]
|
|
1095
1145
|
attrs['security_group_ids'].extend(
|
|
1096
1146
|
client.find_security_group(sg, ignore_missing=False).id
|
|
1097
|
-
for sg in parsed_args.
|
|
1147
|
+
for sg in parsed_args.security_groups
|
|
1098
1148
|
)
|
|
1099
1149
|
|
|
1100
1150
|
if parsed_args.no_allowed_address_pair:
|
|
@@ -1137,6 +1187,11 @@ class SetPort(common.NeutronCommandWithExtraArgs):
|
|
|
1137
1187
|
raise exceptions.CommandError(msg)
|
|
1138
1188
|
attrs['hints'] = expanded_hints
|
|
1139
1189
|
|
|
1190
|
+
if parsed_args.not_trusted:
|
|
1191
|
+
attrs['trusted'] = False
|
|
1192
|
+
if parsed_args.trusted:
|
|
1193
|
+
attrs['trusted'] = True
|
|
1194
|
+
|
|
1140
1195
|
attrs.update(
|
|
1141
1196
|
self._parse_extra_properties(parsed_args.extra_properties)
|
|
1142
1197
|
)
|
|
@@ -1202,7 +1257,7 @@ class UnsetPort(common.NeutronUnsetCommandWithExtraArgs):
|
|
|
1202
1257
|
'--security-group',
|
|
1203
1258
|
metavar='<security-group>',
|
|
1204
1259
|
action='append',
|
|
1205
|
-
dest='
|
|
1260
|
+
dest='security_groups',
|
|
1206
1261
|
help=_(
|
|
1207
1262
|
"Security group which should be removed this port (name "
|
|
1208
1263
|
"or ID) (repeat option to unset multiple security groups)"
|
|
@@ -1287,9 +1342,9 @@ class UnsetPort(common.NeutronUnsetCommandWithExtraArgs):
|
|
|
1287
1342
|
msg = _("Port does not contain binding-profile %s") % key
|
|
1288
1343
|
raise exceptions.CommandError(msg)
|
|
1289
1344
|
attrs['binding:profile'] = tmp_binding_profile
|
|
1290
|
-
if parsed_args.
|
|
1345
|
+
if parsed_args.security_groups:
|
|
1291
1346
|
try:
|
|
1292
|
-
for sg in parsed_args.
|
|
1347
|
+
for sg in parsed_args.security_groups:
|
|
1293
1348
|
sg_id = client.find_security_group(
|
|
1294
1349
|
sg, ignore_missing=False
|
|
1295
1350
|
).id
|
|
@@ -1295,7 +1295,7 @@ class ServerTests(common.ComputeTestCase):
|
|
|
1295
1295
|
)
|
|
1296
1296
|
if ip_address in cmd_output['addresses']['private']:
|
|
1297
1297
|
# Hang out for a bit and try again
|
|
1298
|
-
print('retrying
|
|
1298
|
+
print('retrying remove port check')
|
|
1299
1299
|
wait_time += 10
|
|
1300
1300
|
time.sleep(10)
|
|
1301
1301
|
else:
|
|
@@ -1367,6 +1367,92 @@ class ServerTests(common.ComputeTestCase):
|
|
|
1367
1367
|
addresses = cmd_output['addresses']['private']
|
|
1368
1368
|
self.assertIn(ip_address, addresses)
|
|
1369
1369
|
|
|
1370
|
+
def test_server_add_remove_security_group(self):
|
|
1371
|
+
name = uuid.uuid4().hex
|
|
1372
|
+
cmd_output = self.openstack(
|
|
1373
|
+
'server create '
|
|
1374
|
+
+ '--network private '
|
|
1375
|
+
+ '--flavor '
|
|
1376
|
+
+ self.flavor_name
|
|
1377
|
+
+ ' '
|
|
1378
|
+
+ '--image '
|
|
1379
|
+
+ self.image_name
|
|
1380
|
+
+ ' '
|
|
1381
|
+
+ '--wait '
|
|
1382
|
+
+ name,
|
|
1383
|
+
parse_output=True,
|
|
1384
|
+
)
|
|
1385
|
+
|
|
1386
|
+
self.assertIsNotNone(cmd_output['id'])
|
|
1387
|
+
self.assertEqual(name, cmd_output['name'])
|
|
1388
|
+
self.addCleanup(self.openstack, 'server delete --wait ' + name)
|
|
1389
|
+
|
|
1390
|
+
# create security group
|
|
1391
|
+
security_group_name = uuid.uuid4().hex
|
|
1392
|
+
|
|
1393
|
+
cmd_output = self.openstack(
|
|
1394
|
+
'security group list',
|
|
1395
|
+
parse_output=True,
|
|
1396
|
+
)
|
|
1397
|
+
self.assertNotIn(security_group_name, cmd_output)
|
|
1398
|
+
|
|
1399
|
+
cmd_output = self.openstack(
|
|
1400
|
+
'security group create ' + security_group_name,
|
|
1401
|
+
parse_output=True,
|
|
1402
|
+
)
|
|
1403
|
+
self.assertIsNotNone(cmd_output['id'])
|
|
1404
|
+
self.addCleanup(
|
|
1405
|
+
self.openstack, 'security group delete ' + security_group_name
|
|
1406
|
+
)
|
|
1407
|
+
|
|
1408
|
+
# add security group to server, assert the name of the security group
|
|
1409
|
+
# appears
|
|
1410
|
+
self.openstack(
|
|
1411
|
+
'server add security group ' + name + ' ' + security_group_name
|
|
1412
|
+
)
|
|
1413
|
+
|
|
1414
|
+
wait_time = 0
|
|
1415
|
+
while wait_time < 60:
|
|
1416
|
+
cmd_output = self.openstack(
|
|
1417
|
+
'server show ' + name,
|
|
1418
|
+
parse_output=True,
|
|
1419
|
+
)
|
|
1420
|
+
if security_group_name not in [
|
|
1421
|
+
x['name'] for x in cmd_output['security_groups']
|
|
1422
|
+
]:
|
|
1423
|
+
# Hang out for a bit and try again
|
|
1424
|
+
print('retrying add security group check')
|
|
1425
|
+
wait_time += 10
|
|
1426
|
+
time.sleep(10)
|
|
1427
|
+
else:
|
|
1428
|
+
break
|
|
1429
|
+
security_groups = [x['name'] for x in cmd_output['security_groups']]
|
|
1430
|
+
self.assertIn(security_group_name, security_groups)
|
|
1431
|
+
|
|
1432
|
+
# remove security group, assert the name of the security group doesn't
|
|
1433
|
+
# appear
|
|
1434
|
+
self.openstack(
|
|
1435
|
+
'server remove security group ' + name + ' ' + security_group_name
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
wait_time = 0
|
|
1439
|
+
while wait_time < 60:
|
|
1440
|
+
cmd_output = self.openstack(
|
|
1441
|
+
'server show ' + name,
|
|
1442
|
+
parse_output=True,
|
|
1443
|
+
)
|
|
1444
|
+
if security_group_name not in [
|
|
1445
|
+
x['name'] for x in cmd_output['security_groups']
|
|
1446
|
+
]:
|
|
1447
|
+
# Hang out for a bit and try again
|
|
1448
|
+
print('retrying remove security group check')
|
|
1449
|
+
wait_time += 10
|
|
1450
|
+
time.sleep(10)
|
|
1451
|
+
else:
|
|
1452
|
+
break
|
|
1453
|
+
security_groups = [x['name'] for x in cmd_output['security_groups']]
|
|
1454
|
+
self.assertNotIn(security_group_name, security_groups)
|
|
1455
|
+
|
|
1370
1456
|
def test_server_add_remove_volume(self):
|
|
1371
1457
|
volume_wait_for = volume_common.BaseVolumeTests.wait_for_status
|
|
1372
1458
|
|
|
@@ -49,7 +49,7 @@ class IdentityTests(base.TestCase):
|
|
|
49
49
|
]
|
|
50
50
|
ROLE_FIELDS = ['id', 'name', 'domain_id', 'description']
|
|
51
51
|
SERVICE_FIELDS = ['id', 'enabled', 'name', 'type', 'description']
|
|
52
|
-
REGION_FIELDS = ['description', '
|
|
52
|
+
REGION_FIELDS = ['description', 'parent_region', 'region']
|
|
53
53
|
ENDPOINT_FIELDS = [
|
|
54
54
|
'id',
|
|
55
55
|
'region',
|
|
@@ -107,7 +107,8 @@ class ApplicationCredentialTests(common.IdentityTests):
|
|
|
107
107
|
secret = data_utils.rand_name('secret')
|
|
108
108
|
description = data_utils.rand_name('description')
|
|
109
109
|
tomorrow = (
|
|
110
|
-
datetime.datetime.
|
|
110
|
+
datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
|
111
|
+
+ datetime.timedelta(days=1)
|
|
111
112
|
).strftime('%Y-%m-%dT%H:%M:%S%z')
|
|
112
113
|
role1, role2 = self._create_role_assignments()
|
|
113
114
|
raw_output = self.openstack(
|
|
@@ -93,6 +93,30 @@ class RoleTests(common.IdentityTests):
|
|
|
93
93
|
)
|
|
94
94
|
self.assertEqual(0, len(raw_output))
|
|
95
95
|
|
|
96
|
+
def test_role_add_inherited(self):
|
|
97
|
+
role_name = self._create_dummy_role()
|
|
98
|
+
username = self._create_dummy_user()
|
|
99
|
+
raw_output = self.openstack(
|
|
100
|
+
'role add '
|
|
101
|
+
f'--project {self.project_name} '
|
|
102
|
+
f'--project-domain {self.domain_name} '
|
|
103
|
+
f'--user {username} '
|
|
104
|
+
f'--user-domain {self.domain_name} '
|
|
105
|
+
'--inherited '
|
|
106
|
+
f'{role_name}'
|
|
107
|
+
)
|
|
108
|
+
self.addCleanup(
|
|
109
|
+
self.openstack,
|
|
110
|
+
'role remove '
|
|
111
|
+
f'--project {self.project_name} '
|
|
112
|
+
f'--project-domain {self.domain_name} '
|
|
113
|
+
f'--user {username} '
|
|
114
|
+
f'--user-domain {self.domain_name} '
|
|
115
|
+
'--inherited '
|
|
116
|
+
f'{role_name}',
|
|
117
|
+
)
|
|
118
|
+
self.assertEqual(0, len(raw_output))
|
|
119
|
+
|
|
96
120
|
def test_role_remove(self):
|
|
97
121
|
role_name = self._create_dummy_role()
|
|
98
122
|
username = self._create_dummy_user()
|
|
@@ -151,6 +151,14 @@ class RoleAssignmentTests(common.IdentityTests):
|
|
|
151
151
|
'--inherited '
|
|
152
152
|
f'{role_name}'
|
|
153
153
|
)
|
|
154
|
+
self.addCleanup(
|
|
155
|
+
self.openstack,
|
|
156
|
+
'role remove '
|
|
157
|
+
f'--project {self.project_name} '
|
|
158
|
+
f'--user {username} '
|
|
159
|
+
'--inherited '
|
|
160
|
+
f'{role_name}',
|
|
161
|
+
)
|
|
154
162
|
self.assertEqual(0, len(raw_output))
|
|
155
163
|
|
|
156
164
|
raw_output = self.openstack('role assignment list --inherited')
|
|
@@ -60,9 +60,5 @@ class ServiceProviderTests(common.IdentityTests):
|
|
|
60
60
|
'description': new_description,
|
|
61
61
|
}
|
|
62
62
|
)
|
|
63
|
-
self.assertEqual(0, len(raw_output))
|
|
64
|
-
raw_output = self.openstack(
|
|
65
|
-
f'service provider show {service_provider}'
|
|
66
|
-
)
|
|
67
63
|
updated_value = self.parse_show_as_object(raw_output)
|
|
68
|
-
self.
|
|
64
|
+
self.assertEqual(new_description, updated_value.get('description'))
|
|
@@ -81,10 +81,20 @@ class PortTests(common.NetworkTagTests):
|
|
|
81
81
|
self.addCleanup(self.openstack, f'port delete {id1}')
|
|
82
82
|
self.assertEqual(self.NAME, json_output.get('name'))
|
|
83
83
|
|
|
84
|
+
# sg for port2
|
|
85
|
+
sg_name1 = uuid.uuid4().hex
|
|
84
86
|
json_output = self.openstack(
|
|
85
|
-
f'
|
|
87
|
+
f'security group create {sg_name1}',
|
|
86
88
|
parse_output=True,
|
|
87
89
|
)
|
|
90
|
+
sg_id1 = json_output.get('id')
|
|
91
|
+
self.addCleanup(self.openstack, f'security group delete {sg_id1}')
|
|
92
|
+
json_output = self.openstack(
|
|
93
|
+
f'port create --network {self.NETWORK_NAME} '
|
|
94
|
+
f'--security-group {sg_name1} {self.NAME}x',
|
|
95
|
+
parse_output=True,
|
|
96
|
+
)
|
|
97
|
+
|
|
88
98
|
id2 = json_output.get('id')
|
|
89
99
|
self.assertIsNotNone(id2)
|
|
90
100
|
mac2 = json_output.get('mac_address')
|
|
@@ -113,6 +123,12 @@ class PortTests(common.NetworkTagTests):
|
|
|
113
123
|
id_list = [item.get('ID') for item in json_output]
|
|
114
124
|
self.assertIn(id1, id_list)
|
|
115
125
|
self.assertIn(id2, id_list)
|
|
126
|
+
item_sg_map = {
|
|
127
|
+
item.get('ID'): item.get('Security Groups') for item in json_output
|
|
128
|
+
}
|
|
129
|
+
self.assertIn(id1, item_sg_map.keys())
|
|
130
|
+
self.assertIn(id2, item_sg_map.keys())
|
|
131
|
+
self.assertIn([sg_id1], item_sg_map.values())
|
|
116
132
|
|
|
117
133
|
# Test list --mac-address
|
|
118
134
|
json_output = self.openstack(
|
|
@@ -127,6 +143,17 @@ class PortTests(common.NetworkTagTests):
|
|
|
127
143
|
self.assertNotIn(mac1, item_map.values())
|
|
128
144
|
self.assertIn(mac2, item_map.values())
|
|
129
145
|
|
|
146
|
+
# Test list --security-group
|
|
147
|
+
json_output = self.openstack(
|
|
148
|
+
f'port list --security-group {sg_id1}',
|
|
149
|
+
parse_output=True,
|
|
150
|
+
)
|
|
151
|
+
item_map = {
|
|
152
|
+
item.get('ID'): item.get('Security Groups') for item in json_output
|
|
153
|
+
}
|
|
154
|
+
self.assertNotIn(id1, item_map.keys())
|
|
155
|
+
self.assertIn(id2, item_map.keys())
|
|
156
|
+
|
|
130
157
|
# Test list with unknown fields
|
|
131
158
|
json_output = self.openstack(
|
|
132
159
|
'port list -c ID -c Name -c device_id',
|
|
@@ -262,3 +289,82 @@ class PortTests(common.NetworkTagTests):
|
|
|
262
289
|
f'{self.base_command} create --network {self.NETWORK_NAME} {args} {name}',
|
|
263
290
|
parse_output=True,
|
|
264
291
|
)
|
|
292
|
+
|
|
293
|
+
def _trunk_creation(self):
|
|
294
|
+
pport = uuid.uuid4().hex
|
|
295
|
+
sport1 = uuid.uuid4().hex
|
|
296
|
+
sport2 = uuid.uuid4().hex
|
|
297
|
+
trunk = uuid.uuid4().hex
|
|
298
|
+
json_output = self.openstack(
|
|
299
|
+
'port create ' f'--network {self.NETWORK_NAME} {pport}',
|
|
300
|
+
parse_output=True,
|
|
301
|
+
)
|
|
302
|
+
pport_id = json_output.get('id')
|
|
303
|
+
json_output = self.openstack(
|
|
304
|
+
'port create ' f'--network {self.NETWORK_NAME} {sport1}',
|
|
305
|
+
parse_output=True,
|
|
306
|
+
)
|
|
307
|
+
sport1_id = json_output.get('id')
|
|
308
|
+
json_output = self.openstack(
|
|
309
|
+
'port create ' f'--network {self.NETWORK_NAME} {sport2}',
|
|
310
|
+
parse_output=True,
|
|
311
|
+
)
|
|
312
|
+
sport2_id = json_output.get('id')
|
|
313
|
+
|
|
314
|
+
self.openstack(
|
|
315
|
+
f'network trunk create --parent-port {pport} {trunk}',
|
|
316
|
+
)
|
|
317
|
+
self.openstack(
|
|
318
|
+
f'network trunk set --subport port={sport1},'
|
|
319
|
+
f'segmentation-type=vlan,segmentation-id=100 {trunk}',
|
|
320
|
+
)
|
|
321
|
+
self.openstack(
|
|
322
|
+
f'network trunk set --subport port={sport2},'
|
|
323
|
+
f'segmentation-type=vlan,segmentation-id=101 {trunk}',
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# NOTE(ralonsoh): keep this order to first delete the trunk and then
|
|
327
|
+
# the ports.
|
|
328
|
+
self.addCleanup(self.openstack, f'port delete {pport_id}')
|
|
329
|
+
self.addCleanup(self.openstack, f'port delete {sport1_id}')
|
|
330
|
+
self.addCleanup(self.openstack, f'port delete {sport2_id}')
|
|
331
|
+
self.addCleanup(self.openstack, f'network trunk delete {trunk}')
|
|
332
|
+
|
|
333
|
+
return pport_id, sport1_id, sport2_id
|
|
334
|
+
|
|
335
|
+
def check_subports(self, subports, pport_id, sport1_id, sport2_id):
|
|
336
|
+
self.assertEqual(2, len(subports))
|
|
337
|
+
for subport in subports:
|
|
338
|
+
if subport['port_id'] == sport1_id:
|
|
339
|
+
self.assertEqual(100, subport['segmentation_id'])
|
|
340
|
+
elif subport['port_id'] == sport2_id:
|
|
341
|
+
self.assertEqual(101, subport['segmentation_id'])
|
|
342
|
+
else:
|
|
343
|
+
self.fail(
|
|
344
|
+
f'Port {pport_id} does not have subport '
|
|
345
|
+
f'{subport["port_id"]}'
|
|
346
|
+
)
|
|
347
|
+
self.assertEqual('vlan', subport['segmentation_type'])
|
|
348
|
+
|
|
349
|
+
def test_port_list_with_trunk(self):
|
|
350
|
+
pport_id, sport1_id, sport2_id = self._trunk_creation()
|
|
351
|
+
|
|
352
|
+
# List all ports with "--long" flag to retrieve the trunk details
|
|
353
|
+
json_output = self.openstack(
|
|
354
|
+
'port list --long',
|
|
355
|
+
parse_output=True,
|
|
356
|
+
)
|
|
357
|
+
port = next(port for port in json_output if port['ID'] == pport_id)
|
|
358
|
+
subports = port['Trunk subports']
|
|
359
|
+
self.check_subports(subports, pport_id, sport1_id, sport2_id)
|
|
360
|
+
|
|
361
|
+
def test_port_show_with_trunk(self):
|
|
362
|
+
pport_id, sport1_id, sport2_id = self._trunk_creation()
|
|
363
|
+
|
|
364
|
+
# List all ports with "--long" flag to retrieve the trunk details
|
|
365
|
+
port = self.openstack(
|
|
366
|
+
f'port show {pport_id}',
|
|
367
|
+
parse_output=True,
|
|
368
|
+
)
|
|
369
|
+
subports = port['trunk_details']['sub_ports']
|
|
370
|
+
self.check_subports(subports, pport_id, sport1_id, sport2_id)
|