Skip to content

Commit 70f05a6

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Use the compute SDK in server list"
2 parents 6cd72f6 + c97f73c commit 70f05a6

4 files changed

Lines changed: 205 additions & 189 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 74 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,28 @@ def human_readable(self):
6666
return 'N/A'
6767

6868

69+
class AddressesColumn(cliff_columns.FormattableColumn):
70+
"""Generate a formatted string of a server's addresses."""
71+
72+
def human_readable(self):
73+
try:
74+
return utils.format_dict_of_list({
75+
k: [i['addr'] for i in v if 'addr' in i]
76+
for k, v in self._value.items()})
77+
except Exception:
78+
return 'N/A'
79+
80+
81+
class HostColumn(cliff_columns.FormattableColumn):
82+
"""Generate a formatted string of a hostname."""
83+
84+
def human_readable(self):
85+
if self._value is None:
86+
return ''
87+
88+
return self._value
89+
90+
6991
def _get_ip_address(addresses, address_type, ip_address_family):
7092
# Old style addresses
7193
if address_type in addresses:
@@ -2288,7 +2310,7 @@ def get_parser(self, prog_name):
22882310
return parser
22892311

22902312
def take_action(self, parsed_args):
2291-
compute_client = self.app.client_manager.compute
2313+
compute_client = self.app.client_manager.sdk_connection.compute
22922314
identity_client = self.app.client_manager.identity
22932315
image_client = self.app.client_manager.image
22942316

@@ -2313,10 +2335,11 @@ def take_action(self, parsed_args):
23132335
# flavor name is given, map it to ID.
23142336
flavor_id = None
23152337
if parsed_args.flavor:
2316-
flavor_id = utils.find_resource(
2317-
compute_client.flavors,
2318-
parsed_args.flavor,
2319-
).id
2338+
flavor = compute_client.find_flavor(parsed_args.flavor)
2339+
if flavor is None:
2340+
msg = _('Unable to find flavor: %s') % parsed_args.flavor
2341+
raise exceptions.CommandError(msg)
2342+
flavor_id = flavor.id
23202343

23212344
# Nova only supports list servers searching by image ID. So if a
23222345
# image name is given, map it to ID.
@@ -2332,19 +2355,21 @@ def take_action(self, parsed_args):
23322355
'ip': parsed_args.ip,
23332356
'ip6': parsed_args.ip6,
23342357
'name': parsed_args.name,
2335-
'instance_name': parsed_args.instance_name,
23362358
'status': parsed_args.status,
23372359
'flavor': flavor_id,
23382360
'image': image_id,
23392361
'host': parsed_args.host,
2340-
'tenant_id': project_id,
2341-
'all_tenants': parsed_args.all_projects,
2362+
'project_id': project_id,
2363+
'all_projects': parsed_args.all_projects,
23422364
'user_id': user_id,
23432365
'deleted': parsed_args.deleted,
23442366
'changes-before': parsed_args.changes_before,
23452367
'changes-since': parsed_args.changes_since,
23462368
}
23472369

2370+
if parsed_args.instance_name is not None:
2371+
search_opts['instance_name'] = parsed_args.instance_name
2372+
23482373
if parsed_args.availability_zone:
23492374
search_opts['availability_zone'] = parsed_args.availability_zone
23502375

@@ -2376,7 +2401,7 @@ def take_action(self, parsed_args):
23762401
search_opts['power_state'] = power_state
23772402

23782403
if parsed_args.tags:
2379-
if compute_client.api_version < api_versions.APIVersion('2.26'):
2404+
if not sdk_utils.supports_microversion(compute_client, '2.26'):
23802405
msg = _(
23812406
'--os-compute-api-version 2.26 or greater is required to '
23822407
'support the --tag option'
@@ -2386,7 +2411,7 @@ def take_action(self, parsed_args):
23862411
search_opts['tags'] = ','.join(parsed_args.tags)
23872412

23882413
if parsed_args.not_tags:
2389-
if compute_client.api_version < api_versions.APIVersion('2.26'):
2414+
if not sdk_utils.supports_microversion(compute_client, '2.26'):
23902415
msg = _(
23912416
'--os-compute-api-version 2.26 or greater is required to '
23922417
'support the --not-tag option'
@@ -2396,7 +2421,7 @@ def take_action(self, parsed_args):
23962421
search_opts['not-tags'] = ','.join(parsed_args.not_tags)
23972422

23982423
if parsed_args.locked:
2399-
if compute_client.api_version < api_versions.APIVersion('2.73'):
2424+
if not sdk_utils.supports_microversion(compute_client, '2.73'):
24002425
msg = _(
24012426
'--os-compute-api-version 2.73 or greater is required to '
24022427
'support the --locked option'
@@ -2405,7 +2430,7 @@ def take_action(self, parsed_args):
24052430

24062431
search_opts['locked'] = True
24072432
elif parsed_args.unlocked:
2408-
if compute_client.api_version < api_versions.APIVersion('2.73'):
2433+
if not sdk_utils.supports_microversion(compute_client, '2.73'):
24092434
msg = _(
24102435
'--os-compute-api-version 2.73 or greater is required to '
24112436
'support the --unlocked option'
@@ -2414,10 +2439,14 @@ def take_action(self, parsed_args):
24142439

24152440
search_opts['locked'] = False
24162441

2442+
if parsed_args.limit is not None:
2443+
search_opts['limit'] = parsed_args.limit
2444+
search_opts['paginated'] = False
2445+
24172446
LOG.debug('search options: %s', search_opts)
24182447

24192448
if search_opts['changes-before']:
2420-
if compute_client.api_version < api_versions.APIVersion('2.66'):
2449+
if not sdk_utils.supports_microversion(compute_client, '2.66'):
24212450
msg = _('--os-compute-api-version 2.66 or later is required')
24222451
raise exceptions.CommandError(msg)
24232452

@@ -2451,15 +2480,15 @@ def take_action(self, parsed_args):
24512480

24522481
if parsed_args.long:
24532482
columns += (
2454-
'OS-EXT-STS:task_state',
2455-
'OS-EXT-STS:power_state',
2483+
'task_state',
2484+
'power_state',
24562485
)
24572486
column_headers += (
24582487
'Task State',
24592488
'Power State',
24602489
)
24612490

2462-
columns += ('networks',)
2491+
columns += ('addresses',)
24632492
column_headers += ('Networks',)
24642493

24652494
if parsed_args.long:
@@ -2481,7 +2510,7 @@ def take_action(self, parsed_args):
24812510
# microversion 2.47 puts the embedded flavor into the server response
24822511
# body but omits the id, so if not present we just expose the original
24832512
# flavor name in the output
2484-
if compute_client.api_version >= api_versions.APIVersion('2.47'):
2513+
if sdk_utils.supports_microversion(compute_client, '2.47'):
24852514
columns += ('flavor_name',)
24862515
column_headers += ('Flavor',)
24872516
else:
@@ -2503,8 +2532,8 @@ def take_action(self, parsed_args):
25032532

25042533
if parsed_args.long:
25052534
columns += (
2506-
'OS-EXT-AZ:availability_zone',
2507-
'OS-EXT-SRV-ATTR:host',
2535+
'availability_zone',
2536+
'hypervisor_hostname',
25082537
'metadata',
25092538
)
25102539
column_headers += (
@@ -2513,40 +2542,38 @@ def take_action(self, parsed_args):
25132542
'Properties',
25142543
)
25152544

2516-
marker_id = None
2517-
25182545
# support for additional columns
25192546
if parsed_args.columns:
25202547
for c in parsed_args.columns:
25212548
if c in ('Project ID', 'project_id'):
2522-
columns += ('tenant_id',)
2549+
columns += ('project_id',)
25232550
column_headers += ('Project ID',)
25242551
if c in ('User ID', 'user_id'):
25252552
columns += ('user_id',)
25262553
column_headers += ('User ID',)
25272554
if c in ('Created At', 'created_at'):
2528-
columns += ('created',)
2555+
columns += ('created_at',)
25292556
column_headers += ('Created At',)
25302557
if c in ('Security Groups', 'security_groups'):
25312558
columns += ('security_groups_name',)
25322559
column_headers += ('Security Groups',)
25332560
if c in ("Task State", "task_state"):
2534-
columns += ('OS-EXT-STS:task_state',)
2561+
columns += ('task_state',)
25352562
column_headers += ('Task State',)
25362563
if c in ("Power State", "power_state"):
2537-
columns += ('OS-EXT-STS:power_state',)
2564+
columns += ('power_state',)
25382565
column_headers += ('Power State',)
25392566
if c in ("Image ID", "image_id"):
25402567
columns += ('Image ID',)
25412568
column_headers += ('Image ID',)
25422569
if c in ("Flavor ID", "flavor_id"):
2543-
columns += ('Flavor ID',)
2570+
columns += ('flavor_id',)
25442571
column_headers += ('Flavor ID',)
25452572
if c in ('Availability Zone', "availability_zone"):
2546-
columns += ('OS-EXT-AZ:availability_zone',)
2573+
columns += ('availability_zone',)
25472574
column_headers += ('Availability Zone',)
25482575
if c in ('Host', "host"):
2549-
columns += ('OS-EXT-SRV-ATTR:host',)
2576+
columns += ('hypervisor_hostname',)
25502577
column_headers += ('Host',)
25512578
if c in ('Properties', "properties"):
25522579
columns += ('Metadata',)
@@ -2556,24 +2583,18 @@ def take_action(self, parsed_args):
25562583
column_headers = tuple(column_headers)
25572584
columns = tuple(columns)
25582585

2559-
if parsed_args.marker:
2586+
if parsed_args.marker is not None:
25602587
# Check if both "--marker" and "--deleted" are used.
25612588
# In that scenario a lookup is not needed as the marker
25622589
# needs to be an ID, because find_resource does not
25632590
# handle deleted resources
25642591
if parsed_args.deleted:
25652592
marker_id = parsed_args.marker
25662593
else:
2567-
marker_id = utils.find_resource(
2568-
compute_client.servers,
2569-
parsed_args.marker,
2570-
).id
2594+
marker_id = compute_client.find_server(parsed_args.marker).id
2595+
search_opts['marker'] = marker_id
25712596

2572-
data = compute_client.servers.list(
2573-
search_opts=search_opts,
2574-
marker=marker_id,
2575-
limit=parsed_args.limit,
2576-
)
2597+
data = list(compute_client.servers(**search_opts))
25772598

25782599
images = {}
25792600
flavors = {}
@@ -2628,12 +2649,12 @@ def take_action(self, parsed_args):
26282649
# "Flavor Name" is not crucial, so we swallow any
26292650
# exceptions
26302651
try:
2631-
flavors[f_id] = compute_client.flavors.get(f_id)
2652+
flavors[f_id] = compute_client.find_flavor(f_id)
26322653
except Exception:
26332654
pass
26342655
else:
26352656
try:
2636-
flavors_list = compute_client.flavors.list(is_public=None)
2657+
flavors_list = compute_client.flavors(is_public=None)
26372658
for i in flavors_list:
26382659
flavors[i.id] = i
26392660
except Exception:
@@ -2642,7 +2663,7 @@ def take_action(self, parsed_args):
26422663
# Populate image_name, image_id, flavor_name and flavor_id attributes
26432664
# of server objects so that we can display those columns.
26442665
for s in data:
2645-
if compute_client.api_version >= api_versions.APIVersion('2.69'):
2666+
if sdk_utils.supports_microversion(compute_client, '2.69'):
26462667
# NOTE(tssurya): From 2.69, we will have the keys 'flavor'
26472668
# and 'image' missing in the server response during
26482669
# infrastructure failure situations.
@@ -2651,7 +2672,7 @@ def take_action(self, parsed_args):
26512672
if not hasattr(s, 'image') or not hasattr(s, 'flavor'):
26522673
continue
26532674

2654-
if 'id' in s.image:
2675+
if 'id' in s.image and s.image.id is not None:
26552676
image = images.get(s.image['id'])
26562677
if image:
26572678
s.image_name = image.name
@@ -2664,7 +2685,7 @@ def take_action(self, parsed_args):
26642685
s.image_name = IMAGE_STRING_FOR_BFV
26652686
s.image_id = IMAGE_STRING_FOR_BFV
26662687

2667-
if compute_client.api_version < api_versions.APIVersion('2.47'):
2688+
if not sdk_utils.supports_microversion(compute_client, '2.47'):
26682689
flavor = flavors.get(s.flavor['id'])
26692690
if flavor:
26702691
s.flavor_name = flavor.name
@@ -2674,7 +2695,7 @@ def take_action(self, parsed_args):
26742695

26752696
# Add a list with security group name as attribute
26762697
for s in data:
2677-
if hasattr(s, 'security_groups'):
2698+
if hasattr(s, 'security_groups') and s.security_groups is not None:
26782699
s.security_groups_name = [x["name"] for x in s.security_groups]
26792700
else:
26802701
s.security_groups_name = []
@@ -2687,10 +2708,10 @@ def take_action(self, parsed_args):
26872708
# it's on, providing useful information to a user in this
26882709
# situation.
26892710
if (
2690-
compute_client.api_version >= api_versions.APIVersion('2.16') and
2711+
sdk_utils.supports_microversion(compute_client, '2.16') and
26912712
parsed_args.long
26922713
):
2693-
if any([hasattr(s, 'host_status') for s in data]):
2714+
if any([s.host_status is not None for s in data]):
26942715
columns += ('Host Status',)
26952716
column_headers += ('Host Status',)
26962717

@@ -2700,16 +2721,17 @@ def take_action(self, parsed_args):
27002721
utils.get_item_properties(
27012722
s, columns,
27022723
mixed_case_fields=(
2703-
'OS-EXT-STS:task_state',
2704-
'OS-EXT-STS:power_state',
2705-
'OS-EXT-AZ:availability_zone',
2706-
'OS-EXT-SRV-ATTR:host',
2724+
'task_state',
2725+
'power_state',
2726+
'availability_zone',
2727+
'host',
27072728
),
27082729
formatters={
2709-
'OS-EXT-STS:power_state': PowerStateColumn,
2710-
'networks': format_columns.DictListColumn,
2730+
'power_state': PowerStateColumn,
2731+
'addresses': AddressesColumn,
27112732
'metadata': format_columns.DictColumn,
27122733
'security_groups_name': format_columns.ListColumn,
2734+
'hypervisor_hostname': HostColumn,
27132735
},
27142736
) for s in data
27152737
),

openstackclient/tests/functional/compute/v2/test_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def test_server_list_with_marker_and_deleted(self):
105105
'server list -f json --deleted --marker ' + name2
106106
))
107107
except exceptions.CommandFailed as e:
108-
self.assertIn('marker [%s] not found (HTTP 400)' % (name2),
108+
self.assertIn('marker [%s] not found' % (name2),
109109
e.stderr.decode('utf-8'))
110110

111111
def test_server_list_with_changes_before(self):

0 commit comments

Comments
 (0)