1818
1919import logging
2020
21+ from openstack import utils as sdk_utils
2122from osc_lib .cli import format_columns
2223from osc_lib .cli import parseractions
2324from osc_lib .command import command
3031LOG = logging .getLogger (__name__ )
3132
3233
34+ _aggregate_formatters = {
35+ 'Hosts' : format_columns .ListColumn ,
36+ 'Metadata' : format_columns .DictColumn ,
37+ 'hosts' : format_columns .ListColumn ,
38+ 'metadata' : format_columns .DictColumn ,
39+ }
40+
41+
42+ def _get_aggregate_columns (item ):
43+ # To maintain backwards compatibility we need to rename sdk props to
44+ # whatever OSC was using before
45+ column_map = {
46+ 'metadata' : 'properties' ,
47+ }
48+ hidden_columns = ['links' , 'location' ]
49+ return utils .get_osc_show_columns_for_sdk_resource (
50+ item , column_map , hidden_columns )
51+
52+
3353class AddAggregateHost (command .ShowOne ):
3454 _description = _ ("Add host to aggregate" )
3555
@@ -48,26 +68,18 @@ def get_parser(self, prog_name):
4868 return parser
4969
5070 def take_action (self , parsed_args ):
51- compute_client = self .app .client_manager .compute
71+ compute_client = self .app .client_manager .sdk_connection . compute
5272
53- aggregate = utils .find_resource (
54- compute_client .aggregates ,
55- parsed_args .aggregate ,
56- )
57- data = compute_client .aggregates .add_host (aggregate , parsed_args .host )
58-
59- info = {}
60- info .update (data ._info )
61-
62- # Special mapping for columns to make the output easier to read:
63- # 'metadata' --> 'properties'
64- info .update (
65- {
66- 'hosts' : format_columns .ListColumn (info .pop ('hosts' )),
67- 'properties' : format_columns .DictColumn (info .pop ('metadata' )),
68- },
69- )
70- return zip (* sorted (info .items ()))
73+ aggregate = compute_client .find_aggregate (
74+ parsed_args .aggregate , ignore_missing = False )
75+
76+ aggregate = compute_client .add_host_to_aggregate (
77+ aggregate .id , parsed_args .host )
78+
79+ display_columns , columns = _get_aggregate_columns (aggregate )
80+ data = utils .get_item_properties (
81+ aggregate , columns , formatters = _aggregate_formatters )
82+ return (display_columns , data )
7183
7284
7385class CreateAggregate (command .ShowOne ):
@@ -95,36 +107,25 @@ def get_parser(self, prog_name):
95107 return parser
96108
97109 def take_action (self , parsed_args ):
98- compute_client = self .app .client_manager .compute
110+ compute_client = self .app .client_manager .sdk_connection . compute
99111
100- info = {}
101- data = compute_client . aggregates . create (
102- parsed_args .name ,
103- parsed_args .zone ,
104- )
105- info . update ( data . _info )
112+ attrs = {'name' : parsed_args . name }
113+
114+ if parsed_args .zone :
115+ attrs [ 'availability_zone' ] = parsed_args .zone
116+
117+ aggregate = compute_client . create_aggregate ( ** attrs )
106118
107119 if parsed_args .property :
108- info . update ( compute_client .aggregates . set_metadata (
109- data ,
120+ aggregate = compute_client .set_aggregate_metadata (
121+ aggregate . id ,
110122 parsed_args .property ,
111- )._info )
112-
113- # Special mapping for columns to make the output easier to read:
114- # 'metadata' --> 'properties'
115- hosts = None
116- properties = None
117- if 'hosts' in info .keys ():
118- hosts = format_columns .ListColumn (info .pop ('hosts' ))
119- if 'metadata' in info .keys ():
120- properties = format_columns .DictColumn (info .pop ('metadata' ))
121- info .update (
122- {
123- 'hosts' : hosts ,
124- 'properties' : properties ,
125- },
126- )
127- return zip (* sorted (info .items ()))
123+ )
124+
125+ display_columns , columns = _get_aggregate_columns (aggregate )
126+ data = utils .get_item_properties (
127+ aggregate , columns , formatters = _aggregate_formatters )
128+ return (display_columns , data )
128129
129130
130131class DeleteAggregate (command .Command ):
@@ -141,13 +142,14 @@ def get_parser(self, prog_name):
141142 return parser
142143
143144 def take_action (self , parsed_args ):
144- compute_client = self .app .client_manager .compute
145+ compute_client = self .app .client_manager .sdk_connection . compute
145146 result = 0
146147 for a in parsed_args .aggregate :
147148 try :
148- data = utils .find_resource (
149- compute_client .aggregates , a )
150- compute_client .aggregates .delete (data .id )
149+ aggregate = compute_client .find_aggregate (
150+ a , ignore_missing = False )
151+ compute_client .delete_aggregate (
152+ aggregate .id , ignore_missing = False )
151153 except Exception as e :
152154 result += 1
153155 LOG .error (_ ("Failed to delete aggregate with name or "
@@ -175,15 +177,15 @@ def get_parser(self, prog_name):
175177 return parser
176178
177179 def take_action (self , parsed_args ):
178- compute_client = self .app .client_manager .compute
180+ compute_client = self .app .client_manager .sdk_connection . compute
179181
180- data = compute_client .aggregates . list ( )
182+ aggregates = list ( compute_client .aggregates () )
181183
182184 if parsed_args .long :
183185 # Remove availability_zone from metadata because Nova doesn't
184- for d in data :
185- if 'availability_zone' in d .metadata :
186- d .metadata .pop ('availability_zone' )
186+ for aggregate in aggregates :
187+ if 'availability_zone' in aggregate .metadata :
188+ aggregate .metadata .pop ('availability_zone' )
187189 # This is the easiest way to change column headers
188190 column_headers = (
189191 "ID" ,
@@ -204,14 +206,11 @@ def take_action(self, parsed_args):
204206 "Availability Zone" ,
205207 )
206208
207- return (column_headers ,
208- (utils .get_item_properties (
209- s , columns ,
210- formatters = {
211- 'Hosts' : format_columns .ListColumn ,
212- 'Metadata' : format_columns .DictColumn ,
213- },
214- ) for s in data ))
209+ data = (
210+ utils .get_item_properties (
211+ s , columns , formatters = _aggregate_formatters
212+ ) for s in aggregates )
213+ return (column_headers , data )
215214
216215
217216class RemoveAggregateHost (command .ShowOne ):
@@ -232,29 +231,18 @@ def get_parser(self, prog_name):
232231 return parser
233232
234233 def take_action (self , parsed_args ):
235- compute_client = self .app .client_manager .compute
234+ compute_client = self .app .client_manager .sdk_connection . compute
236235
237- aggregate = utils .find_resource (
238- compute_client .aggregates ,
239- parsed_args .aggregate ,
240- )
241- data = compute_client .aggregates .remove_host (
242- aggregate ,
243- parsed_args .host ,
244- )
236+ aggregate = compute_client .find_aggregate (
237+ parsed_args .aggregate , ignore_missing = False )
245238
246- info = {}
247- info . update ( data . _info )
239+ aggregate = compute_client . remove_host_from_aggregate (
240+ aggregate . id , parsed_args . host )
248241
249- # Special mapping for columns to make the output easier to read:
250- # 'metadata' --> 'properties'
251- info .update (
252- {
253- 'hosts' : format_columns .ListColumn (info .pop ('hosts' )),
254- 'properties' : format_columns .DictColumn (info .pop ('metadata' )),
255- },
256- )
257- return zip (* sorted (info .items ()))
242+ display_columns , columns = _get_aggregate_columns (aggregate )
243+ data = utils .get_item_properties (
244+ aggregate , columns , formatters = _aggregate_formatters )
245+ return (display_columns , data )
258246
259247
260248class SetAggregate (command .Command ):
@@ -296,39 +284,31 @@ def get_parser(self, prog_name):
296284
297285 def take_action (self , parsed_args ):
298286
299- compute_client = self .app .client_manager .compute
300- aggregate = utils .find_resource (
301- compute_client .aggregates ,
302- parsed_args .aggregate ,
303- )
287+ compute_client = self .app .client_manager .sdk_connection .compute
288+ aggregate = compute_client .find_aggregate (
289+ parsed_args .aggregate , ignore_missing = False )
304290
305291 kwargs = {}
306292 if parsed_args .name :
307293 kwargs ['name' ] = parsed_args .name
308294 if parsed_args .zone :
309295 kwargs ['availability_zone' ] = parsed_args .zone
310296 if kwargs :
311- compute_client .aggregates .update (
312- aggregate ,
313- kwargs
314- )
297+ compute_client .update_aggregate (aggregate .id , ** kwargs )
315298
316299 set_property = {}
317300 if parsed_args .no_property :
318- # NOTE(RuiChen): "availability_zone" is removed from response of
319- # aggregate show and create commands, don't see it
320- # anywhere, so pop it, avoid the unexpected server
321- # exception(can't unset the availability zone from
322- # aggregate metadata in nova).
301+ # NOTE(RuiChen): "availability_zone" can not be unset from
302+ # properties. It is already excluded from show and create output.
323303 set_property .update ({key : None
324304 for key in aggregate .metadata .keys ()
325305 if key != 'availability_zone' })
326306 if parsed_args .property :
327307 set_property .update (parsed_args .property )
328308
329309 if set_property :
330- compute_client .aggregates . set_metadata (
331- aggregate ,
310+ compute_client .set_aggregate_metadata (
311+ aggregate . id ,
332312 set_property
333313 )
334314
@@ -347,31 +327,18 @@ def get_parser(self, prog_name):
347327
348328 def take_action (self , parsed_args ):
349329
350- compute_client = self .app .client_manager .compute
351- data = utils .find_resource (
352- compute_client .aggregates ,
353- parsed_args .aggregate ,
354- )
330+ compute_client = self .app .client_manager .sdk_connection .compute
331+ aggregate = compute_client .find_aggregate (
332+ parsed_args .aggregate , ignore_missing = False )
333+
355334 # Remove availability_zone from metadata because Nova doesn't
356- if 'availability_zone' in data .metadata :
357- data .metadata .pop ('availability_zone' )
358-
359- # Special mapping for columns to make the output easier to read:
360- # 'metadata' --> 'properties'
361- data ._info .update (
362- {
363- 'hosts' : format_columns .ListColumn (
364- data ._info .pop ('hosts' )
365- ),
366- 'properties' : format_columns .DictColumn (
367- data ._info .pop ('metadata' )
368- ),
369- },
370- )
335+ if 'availability_zone' in aggregate .metadata :
336+ aggregate .metadata .pop ('availability_zone' )
371337
372- info = {}
373- info .update (data ._info )
374- return zip (* sorted (info .items ()))
338+ display_columns , columns = _get_aggregate_columns (aggregate )
339+ data = utils .get_item_properties (
340+ aggregate , columns , formatters = _aggregate_formatters )
341+ return (display_columns , data )
375342
376343
377344class UnsetAggregate (command .Command ):
@@ -394,14 +361,56 @@ def get_parser(self, prog_name):
394361 return parser
395362
396363 def take_action (self , parsed_args ):
397- compute_client = self .app .client_manager .compute
398- aggregate = utils .find_resource (
399- compute_client .aggregates ,
400- parsed_args .aggregate )
364+ compute_client = self .app .client_manager .sdk_connection .compute
365+ aggregate = compute_client .find_aggregate (
366+ parsed_args .aggregate , ignore_missing = False )
401367
402368 unset_property = {}
403369 if parsed_args .property :
404370 unset_property .update ({key : None for key in parsed_args .property })
405371 if unset_property :
406- compute_client .aggregates .set_metadata (aggregate ,
407- unset_property )
372+ compute_client .set_aggregate_metadata (
373+ aggregate , unset_property )
374+
375+
376+ class CacheImageForAggregate (command .Command ):
377+ _description = _ ("Request image caching for aggregate" )
378+ # NOTE(gtema): According to stephenfin and dansmith there is no and will
379+ # not be anything to return.
380+
381+ def get_parser (self , prog_name ):
382+ parser = super (CacheImageForAggregate , self ).get_parser (prog_name )
383+ parser .add_argument (
384+ 'aggregate' ,
385+ metavar = '<aggregate>' ,
386+ help = _ ("Aggregate (name or ID)" )
387+ )
388+ parser .add_argument (
389+ 'image' ,
390+ metavar = '<image>' ,
391+ nargs = '+' ,
392+ help = _ ("Image ID to request caching for aggregate (name or ID). "
393+ "May be specified multiple times." )
394+ )
395+ return parser
396+
397+ def take_action (self , parsed_args ):
398+ compute_client = self .app .client_manager .sdk_connection .compute
399+
400+ if not sdk_utils .supports_microversion (compute_client , '2.81' ):
401+ msg = _ (
402+ 'This operation requires server support for '
403+ 'API microversion 2.81'
404+ )
405+ raise exceptions .CommandError (msg )
406+
407+ aggregate = compute_client .find_aggregate (
408+ parsed_args .aggregate , ignore_missing = False )
409+
410+ images = []
411+ for img in parsed_args .image :
412+ image = self .app .client_manager .sdk_connection .image .find_image (
413+ img , ignore_missing = False )
414+ images .append (image .id )
415+
416+ compute_client .aggregate_precache_images (aggregate .id , images )
0 commit comments