@@ -446,10 +446,22 @@ def get_parser(self, prog_name):
446446 parser .add_argument (
447447 '--block-device-mapping' ,
448448 metavar = '<dev-name=mapping>' ,
449- action = 'append' ,
450- default = [],
451- help = _ ('Map block devices; map is '
452- '<id>:<type>:<size(GB)>:<delete_on_terminate> '
449+ action = parseractions .KeyValueAction ,
450+ default = {},
451+ # NOTE(RuiChen): Add '\n' at the end of line to put each item in
452+ # the separated line, avoid the help message looks
453+ # messy, see _SmartHelpFormatter in cliff.
454+ help = _ ('Create a block device on the server.\n '
455+ 'Block device mapping in the format\n '
456+ '<dev-name>=<id>:<type>:<size(GB)>:<delete-on-terminate>\n '
457+ '<dev-name>: block device name, like: vdb, xvdc '
458+ '(required)\n '
459+ '<id>: UUID of the volume or snapshot (required)\n '
460+ '<type>: volume or snapshot; default: volume (optional)\n '
461+ '<size(GB)>: volume size if create from snapshot '
462+ '(optional)\n '
463+ '<delete-on-terminate>: true or false; default: false '
464+ '(optional)\n '
453465 '(optional extension)' ),
454466 )
455467 parser .add_argument (
@@ -593,33 +605,39 @@ def take_action(self, parsed_args):
593605 'source_type' : 'volume' ,
594606 'destination_type' : 'volume'
595607 }]
596- for dev_map in parsed_args .block_device_mapping :
597- dev_name , dev_map = dev_map .split ('=' , 1 )
598- if dev_map :
599- dev_map = dev_map .split (':' )
600- if len (dev_map ) > 0 :
601- mapping = {
602- 'device_name' : dev_name ,
603- 'uuid' : utils .find_resource (
604- volume_client .volumes ,
605- dev_map [0 ],
606- ).id }
607- # Block device mapping v1 compatibility
608- if len (dev_map ) > 1 and \
609- dev_map [1 ] in ('volume' , 'snapshot' ):
610- mapping ['source_type' ] = dev_map [1 ]
611- else :
612- mapping ['source_type' ] = 'volume'
613- mapping ['destination_type' ] = 'volume'
614- if len (dev_map ) > 2 and dev_map [2 ]:
615- mapping ['volume_size' ] = dev_map [2 ]
616- if len (dev_map ) > 3 :
617- mapping ['delete_on_termination' ] = dev_map [3 ]
608+ # Handle block device by device name order, like: vdb -> vdc -> vdd
609+ for dev_name in sorted (six .iterkeys (parsed_args .block_device_mapping )):
610+ dev_map = parsed_args .block_device_mapping [dev_name ]
611+ dev_map = dev_map .split (':' )
612+ if dev_map [0 ]:
613+ mapping = {'device_name' : dev_name }
614+ # 1. decide source and destination type
615+ if (len (dev_map ) > 1 and
616+ dev_map [1 ] in ('volume' , 'snapshot' )):
617+ mapping ['source_type' ] = dev_map [1 ]
618618 else :
619- msg = _ ("Volume name or ID must be specified if "
620- "--block-device-mapping is specified" )
621- raise exceptions .CommandError (msg )
622- block_device_mapping_v2 .append (mapping )
619+ mapping ['source_type' ] = 'volume'
620+ mapping ['destination_type' ] = 'volume'
621+ # 2. check target exist, update target uuid according by
622+ # source type
623+ if mapping ['source_type' ] == 'volume' :
624+ volume_id = utils .find_resource (
625+ volume_client .volumes , dev_map [0 ]).id
626+ mapping ['uuid' ] = volume_id
627+ elif mapping ['source_type' ] == 'snapshot' :
628+ snapshot_id = utils .find_resource (
629+ volume_client .volume_snapshots , dev_map [0 ]).id
630+ mapping ['uuid' ] = snapshot_id
631+ # 3. append size and delete_on_termination if exist
632+ if len (dev_map ) > 2 and dev_map [2 ]:
633+ mapping ['volume_size' ] = dev_map [2 ]
634+ if len (dev_map ) > 3 and dev_map [3 ]:
635+ mapping ['delete_on_termination' ] = dev_map [3 ]
636+ else :
637+ msg = _ ("Volume or snapshot (name or ID) must be specified if "
638+ "--block-device-mapping is specified" )
639+ raise exceptions .CommandError (msg )
640+ block_device_mapping_v2 .append (mapping )
623641
624642 nics = []
625643 auto_or_none = False
0 commit comments