@@ -98,16 +98,6 @@ def _get_ip_address(addresses, address_type, ip_address_family):
9898 )
9999
100100
101- def _prefix_checked_value (prefix ):
102- def func (value ):
103- if ',' in value or '=' in value :
104- msg = _ ("Invalid argument %s, "
105- "characters ',' and '=' are not allowed" ) % value
106- raise argparse .ArgumentTypeError (msg )
107- return prefix + value
108- return func
109-
110-
111101def _prep_server_detail (compute_client , image_client , server , refresh = True ):
112102 """Prepare the detailed server dict for printing
113103
@@ -611,6 +601,81 @@ def take_action(self, parsed_args):
611601 )
612602
613603
604+ # TODO(stephenfin): Replace with 'MultiKeyValueAction' when we no longer
605+ # support '--nic=auto' and '--nic=none'
606+ class NICAction (argparse .Action ):
607+
608+ def __init__ (
609+ self ,
610+ option_strings ,
611+ dest ,
612+ nargs = None ,
613+ const = None ,
614+ default = None ,
615+ type = None ,
616+ choices = None ,
617+ required = False ,
618+ help = None ,
619+ metavar = None ,
620+ key = None ,
621+ ):
622+ self .key = key
623+ super ().__init__ (
624+ option_strings = option_strings , dest = dest , nargs = nargs , const = const ,
625+ default = default , type = type , choices = choices , required = required ,
626+ help = help , metavar = metavar ,
627+ )
628+
629+ def __call__ (self , parser , namespace , values , option_string = None ):
630+ # Make sure we have an empty dict rather than None
631+ if getattr (namespace , self .dest , None ) is None :
632+ setattr (namespace , self .dest , [])
633+
634+ # Handle the special auto/none cases
635+ if values in ('auto' , 'none' ):
636+ getattr (namespace , self .dest ).append (values )
637+ return
638+
639+ if self .key :
640+ if ',' in values or '=' in values :
641+ msg = _ (
642+ "Invalid argument %s; characters ',' and '=' are not "
643+ "allowed"
644+ )
645+ raise argparse .ArgumentTypeError (msg % values )
646+
647+ values = '=' .join ([self .key , values ])
648+
649+ info = {
650+ 'net-id' : '' ,
651+ 'port-id' : '' ,
652+ 'v4-fixed-ip' : '' ,
653+ 'v6-fixed-ip' : '' ,
654+ }
655+
656+ for kv_str in values .split (',' ):
657+ k , sep , v = kv_str .partition ("=" )
658+
659+ if k not in info or not v :
660+ msg = _ (
661+ "Invalid argument %s; argument must be of form "
662+ "'net-id=net-uuid,v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,"
663+ "port-id=port-uuid'"
664+ )
665+ raise argparse .ArgumentTypeError (msg % values )
666+
667+ info [k ] = v
668+
669+ if info ['net-id' ] and info ['port-id' ]:
670+ msg = _ (
671+ 'Invalid argument %s; either network or port should be '
672+ 'specified but not both'
673+ )
674+ raise argparse .ArgumentTypeError (msg % values )
675+
676+ getattr (namespace , self .dest ).append (info )
677+
678+
614679class CreateServer (command .ShowOne ):
615680 _description = _ ("Create a new server" )
616681
@@ -701,9 +766,10 @@ def get_parser(self, prog_name):
701766 parser .add_argument (
702767 '--network' ,
703768 metavar = "<network>" ,
704- action = 'append' ,
705- dest = 'nic' ,
706- type = _prefix_checked_value ('net-id=' ),
769+ dest = 'nics' ,
770+ default = [],
771+ action = NICAction ,
772+ key = 'net-id' ,
707773 # NOTE(RuiChen): Add '\n' to the end of line to improve formatting;
708774 # see cliff's _SmartHelpFormatter for more details.
709775 help = _ (
@@ -719,9 +785,10 @@ def get_parser(self, prog_name):
719785 parser .add_argument (
720786 '--port' ,
721787 metavar = "<port>" ,
722- action = 'append' ,
723- dest = 'nic' ,
724- type = _prefix_checked_value ('port-id=' ),
788+ dest = 'nics' ,
789+ default = [],
790+ action = NICAction ,
791+ key = 'port-id' ,
725792 help = _ (
726793 "Create a NIC on the server and connect it to port. "
727794 "Specify option multiple times to create multiple NICs. "
@@ -733,21 +800,28 @@ def get_parser(self, prog_name):
733800 )
734801 parser .add_argument (
735802 '--nic' ,
736- metavar = "<net-id=net-uuid,v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,"
737- "port-id=port-uuid,auto,none>" ,
738- action = 'append' ,
803+ metavar = "<net-id=net-uuid,port-id=port-uuid,v4-fixed-ip=ip-addr,"
804+ "v6-fixed-ip=ip-addr,auto,none>" ,
805+ action = NICAction ,
806+ dest = 'nics' ,
807+ default = [],
739808 help = _ (
740- "Create a NIC on the server. "
741- "Specify option multiple times to create multiple NICs. "
742- "Either net-id or port-id must be provided, but not both. "
743- "net-id: attach NIC to network with this UUID, "
744- "port-id: attach NIC to port with this UUID, "
745- "v4-fixed-ip: IPv4 fixed address for NIC (optional), "
746- "v6-fixed-ip: IPv6 fixed address for NIC (optional), "
747- "none: (v2.37+) no network is attached, "
809+ "Create a NIC on the server.\n "
810+ "NIC in the format:\n "
811+ "net-id=<net-uuid>: attach NIC to network with this UUID,\n "
812+ "port-id=<port-uuid>: attach NIC to port with this UUID,\n "
813+ "v4-fixed-ip=<ip-addr>: IPv4 fixed address for NIC (optional),"
814+ "\n "
815+ "v6-fixed-ip=<ip-addr>: IPv6 fixed address for NIC (optional),"
816+ "\n "
817+ "none: (v2.37+) no network is attached,\n "
748818 "auto: (v2.37+) the compute service will automatically "
749- "allocate a network. Specifying a --nic of auto or none "
750- "cannot be used with any other --nic value."
819+ "allocate a network.\n "
820+ "\n "
821+ "Specify option multiple times to create multiple NICs.\n "
822+ "Specifying a --nic of auto or none cannot be used with any "
823+ "other --nic value.\n "
824+ "Either net-id or port-id must be provided, but not both."
751825 ),
752826 )
753827 parser .add_argument (
@@ -1103,84 +1177,55 @@ def _match_image(image_api, wanted_properties):
11031177 raise exceptions .CommandError (msg )
11041178 block_device_mapping_v2 .append (mapping )
11051179
1106- nics = []
1107- auto_or_none = False
1108- if parsed_args .nic is None :
1109- parsed_args .nic = []
1110- for nic_str in parsed_args .nic :
1111- # Handle the special auto/none cases
1112- if nic_str in ('auto' , 'none' ):
1113- auto_or_none = True
1114- nics .append (nic_str )
1115- else :
1116- nic_info = {
1117- 'net-id' : '' ,
1118- 'v4-fixed-ip' : '' ,
1119- 'v6-fixed-ip' : '' ,
1120- 'port-id' : '' ,
1121- }
1122- for kv_str in nic_str .split ("," ):
1123- k , sep , v = kv_str .partition ("=" )
1124- if k in nic_info and v :
1125- nic_info [k ] = v
1126- else :
1127- msg = _ (
1128- "Invalid nic argument '%s'. Nic arguments "
1129- "must be of the form --nic <net-id=net-uuid"
1130- ",v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,"
1131- "port-id=port-uuid>."
1132- )
1133- raise exceptions .CommandError (msg % k )
1180+ nics = parsed_args .nics
11341181
1135- if bool (nic_info ["net-id" ]) == bool (nic_info ["port-id" ]):
1136- msg = _ (
1137- 'Either network or port should be specified '
1138- 'but not both'
1139- )
1140- raise exceptions .CommandError (msg )
1182+ if 'auto' in nics or 'none' in nics :
1183+ if len (nics ) > 1 :
1184+ msg = _ (
1185+ 'Specifying a --nic of auto or none cannot '
1186+ 'be used with any other --nic, --network '
1187+ 'or --port value.'
1188+ )
1189+ raise exceptions .CommandError (msg )
11411190
1191+ nics = nics [0 ]
1192+ else :
1193+ for nic in nics :
11421194 if self .app .client_manager .is_network_endpoint_enabled ():
11431195 network_client = self .app .client_manager .network
1144- if nic_info ["net-id" ]:
1196+
1197+ if nic ['net-id' ]:
11451198 net = network_client .find_network (
1146- nic_info ["net-id" ], ignore_missing = False )
1147- nic_info ["net-id" ] = net .id
1148- if nic_info ["port-id" ]:
1199+ nic ['net-id' ], ignore_missing = False ,
1200+ )
1201+ nic ['net-id' ] = net .id
1202+
1203+ if nic ['port-id' ]:
11491204 port = network_client .find_port (
1150- nic_info ["port-id" ], ignore_missing = False )
1151- nic_info ["port-id" ] = port .id
1205+ nic ['port-id' ], ignore_missing = False ,
1206+ )
1207+ nic ['port-id' ] = port .id
11521208 else :
1153- if nic_info [ " net-id" ]:
1154- nic_info [ " net-id" ] = compute_client .api .network_find (
1155- nic_info [ " net-id" ]
1209+ if nic [ ' net-id' ]:
1210+ nic [ ' net-id' ] = compute_client .api .network_find (
1211+ nic [ ' net-id' ],
11561212 )['id' ]
1157- if nic_info ["port-id" ]:
1213+
1214+ if nic ['port-id' ]:
11581215 msg = _ (
11591216 "Can't create server with port specified "
11601217 "since network endpoint not enabled"
11611218 )
11621219 raise exceptions .CommandError (msg )
11631220
1164- nics .append (nic_info )
1165-
1166- if nics :
1167- if auto_or_none :
1168- if len (nics ) > 1 :
1169- msg = _ (
1170- 'Specifying a --nic of auto or none cannot '
1171- 'be used with any other --nic, --network '
1172- 'or --port value.'
1173- )
1174- raise exceptions .CommandError (msg )
1175- nics = nics [0 ]
1176- else :
1221+ if not nics :
11771222 # Compute API version >= 2.37 requires a value, so default to
11781223 # 'auto' to maintain legacy behavior if a nic wasn't specified.
11791224 if compute_client .api_version >= api_versions .APIVersion ('2.37' ):
11801225 nics = 'auto'
11811226 else :
1182- # Default to empty list if nothing was specified, let nova
1183- # side to decide the default behavior.
1227+ # Default to empty list if nothing was specified and let nova
1228+ # decide the default behavior.
11841229 nics = []
11851230
11861231 # Check security group exist and convert ID to name
0 commit comments