@@ -1243,15 +1243,20 @@ def _func(value):
12431243
12441244 return password
12451245
1246+ # Type aliases for config_create parameters
1247+ ConfigCreateDevice = Union ["Disk" , "Volume" , Dict [str , Any ]]
1248+ ConfigCreateDisk = Union ["Disk" , int ]
1249+ ConfigCreateVolume = Union ["Volume" , int ]
1250+
12461251 # create derived objects
12471252 def config_create (
12481253 self ,
12491254 kernel = None ,
12501255 label = None ,
1251- devices = [] ,
1252- disks = [] ,
1253- volumes = [] ,
1254- interfaces = [] ,
1256+ devices = None ,
1257+ disks = None ,
1258+ volumes = None ,
1259+ interfaces = None ,
12551260 ** kwargs ,
12561261 ):
12571262 """
@@ -1265,15 +1270,20 @@ def config_create(
12651270 :param volumes: The volumes, starting after the last disk, to map to this
12661271 config
12671272 :param devices: A list of devices to assign to this config, in device
1268- index order. Values must be of type Disk or Volume. If this is
1269- given, you may not include disks or volumes.
1273+ index order, or a raw device mapping dict to pass directly to the
1274+ API. List values must be of type Disk or Volume. If this is given,
1275+ you may not include disks or volumes.
12701276 :param **kwargs: Any other arguments accepted by the api.
12711277
12721278 :returns: A new Linode Config
12731279 """
12741280 # needed here to avoid circular imports
12751281 from .volume import Volume # pylint: disable=import-outside-toplevel
12761282
1283+ disks = [] if disks is None else disks
1284+ volumes = [] if volumes is None else volumes
1285+ interfaces = [] if interfaces is None else interfaces
1286+
12771287 hypervisor_prefix = "sd" if self .hypervisor == "kvm" else "xvd"
12781288
12791289 device_limit = int (
@@ -1288,52 +1298,58 @@ def config_create(
12881298 for suffix in generate_device_suffixes (device_limit )
12891299 ]
12901300
1291- device_map = {
1292- device_names [i ]: None for i in range (0 , len (device_names ))
1293- }
1301+ def _flatten_device (device : Any ):
1302+ if device is None :
1303+ return None
1304+ elif isinstance (device , Disk ):
1305+ return {"disk_id" : device .id }
1306+ elif isinstance (device , Volume ):
1307+ return {"volume_id" : device .id }
1308+ else :
1309+ raise TypeError ("Disk or Volume expected!" )
1310+
1311+ def _build_devices ():
1312+ # Devices is a dict, pass through
1313+ if isinstance (devices , dict ):
1314+ return devices
1315+
1316+ if devices is not None :
1317+ device_list = (
1318+ devices if isinstance (devices , list ) else [devices ]
1319+ )
1320+
1321+ return {
1322+ device_names [i ]: _flatten_device (device_list [i ])
1323+ for i in range (len (devices ))
1324+ }
1325+
1326+ # Devices were given through named args
1327+ return [
1328+ (
1329+ {"volume_id" : volume .id }
1330+ if isinstance (volume , int )
1331+ else _flatten_device (volume )
1332+ )
1333+ for volume in volumes
1334+ ] + [
1335+ (
1336+ {"disk_id" : disk .id }
1337+ if isinstance (disk , int )
1338+ else _flatten_device (disk )
1339+ )
1340+ for disk in disks
1341+ ]
12941342
12951343 if devices and (disks or volumes ):
12961344 raise ValueError (
12971345 'You may not call config_create with "devices" and '
12981346 'either of "disks" or "volumes" specified!'
12991347 )
13001348
1301- if not devices :
1302- if not isinstance (disks , list ):
1303- disks = [disks ]
1304- if not isinstance (volumes , list ):
1305- volumes = [volumes ]
1306-
1307- devices = []
1308-
1309- for d in disks :
1310- if d is None :
1311- devices .append (None )
1312- elif isinstance (d , Disk ):
1313- devices .append (d )
1314- else :
1315- devices .append (Disk (self ._client , int (d ), self .id ))
1316-
1317- for v in volumes :
1318- if v is None :
1319- devices .append (None )
1320- elif isinstance (v , Volume ):
1321- devices .append (v )
1322- else :
1323- devices .append (Volume (self ._client , int (v )))
1324-
1325- if not devices :
1326- raise ValueError ("Must include at least one disk or volume!" )
1349+ device_map = _build_devices ()
13271350
1328- for i , d in enumerate (devices ):
1329- if d is None :
1330- pass
1331- elif isinstance (d , Disk ):
1332- device_map [device_names [i ]] = {"disk_id" : d .id }
1333- elif isinstance (d , Volume ):
1334- device_map [device_names [i ]] = {"volume_id" : d .id }
1335- else :
1336- raise TypeError ("Disk or Volume expected!" )
1351+ if len (device_map ) < 1 :
1352+ raise ValueError ("Must include at least one disk or volume!" )
13371353
13381354 param_interfaces = []
13391355 for interface in interfaces :
@@ -1845,8 +1861,8 @@ def clone(
18451861 to_linode = None ,
18461862 region = None ,
18471863 instance_type = None ,
1848- configs = [] ,
1849- disks = [] ,
1864+ configs = None ,
1865+ disks = None ,
18501866 label = None ,
18511867 group = None ,
18521868 with_backups = None ,
@@ -1902,6 +1918,9 @@ def clone(
19021918 'You may only specify one of "to_linode" and "region"'
19031919 )
19041920
1921+ configs = [] if configs is None else configs
1922+ disks = [] if disks is None else disks
1923+
19051924 if region and not type :
19061925 raise ValueError ('Specifying a region requires a "service" as well' )
19071926
0 commit comments