11import base64
22import os
33from collections .abc import Iterable
4- from typing import Optional , Union
4+ from typing import Any , Dict , Optional , Union
55
6- from linode_api4 import InstanceDiskEncryptionType
76from linode_api4 .common import load_and_validate_keys
87from linode_api4 .errors import UnexpectedResponseError
98from linode_api4 .groups import Group
109from linode_api4 .objects import (
11- Base ,
1210 ConfigInterface ,
1311 Firewall ,
14- Image ,
1512 Instance ,
13+ InstanceDiskEncryptionType ,
1614 Kernel ,
15+ PlacementGroup ,
1716 StackScript ,
1817 Type ,
1918)
19+ from linode_api4 .objects .base import _flatten_request_body_recursive
2020from linode_api4 .objects .filtering import Filter
21- from linode_api4 .objects .linode import _expand_placement_group_assignment
22- from linode_api4 .paginated_list import PaginatedList
21+ from linode_api4 .objects .linode import (
22+ Backup ,
23+ InstancePlacementGroupAssignment ,
24+ _expand_placement_group_assignment ,
25+ )
26+ from linode_api4 .util import drop_null_keys
2327
2428
2529class LinodeGroup (Group ):
@@ -135,9 +139,20 @@ def instance_create(
135139 region ,
136140 image = None ,
137141 authorized_keys = None ,
142+ firewall : Optional [Union [Firewall , int ]] = None ,
143+ backup : Optional [Union [Backup , int ]] = None ,
144+ stackscript : Optional [Union [StackScript , int ]] = None ,
138145 disk_encryption : Optional [
139146 Union [InstanceDiskEncryptionType , str ]
140147 ] = None ,
148+ placement_group : Optional [
149+ Union [
150+ InstancePlacementGroupAssignment ,
151+ PlacementGroup ,
152+ Dict [str , Any ],
153+ int ,
154+ ]
155+ ] = None ,
141156 ** kwargs ,
142157 ):
143158 """
@@ -290,65 +305,45 @@ def instance_create(
290305 This usually indicates that you are using
291306 an outdated library.
292307 """
308+
293309 ret_pass = None
294310 if image and not "root_pass" in kwargs :
295311 ret_pass = Instance .generate_root_password ()
296312 kwargs ["root_pass" ] = ret_pass
297313
298- authorized_keys = load_and_validate_keys (authorized_keys )
299-
300- if "stackscript" in kwargs :
301- # translate stackscripts
302- kwargs ["stackscript_id" ] = (
303- kwargs ["stackscript" ].id
304- if issubclass (type (kwargs ["stackscript" ]), Base )
305- else kwargs ["stackscript" ]
306- )
307- del kwargs ["stackscript" ]
308-
309- if "backup" in kwargs :
310- # translate backups
311- kwargs ["backup_id" ] = (
312- kwargs ["backup" ].id
313- if issubclass (type (kwargs ["backup" ]), Base )
314- else kwargs ["backup" ]
315- )
316- del kwargs ["backup" ]
317-
318- if "firewall" in kwargs :
319- fw = kwargs .pop ("firewall" )
320- kwargs ["firewall_id" ] = fw .id if isinstance (fw , Firewall ) else fw
321-
322- if "interfaces" in kwargs :
323- interfaces = kwargs .get ("interfaces" )
324- if interfaces is not None and isinstance (interfaces , Iterable ):
325- kwargs ["interfaces" ] = [
326- i ._serialize () if isinstance (i , ConfigInterface ) else i
327- for i in interfaces
328- ]
329-
330- if "placement_group" in kwargs :
331- kwargs ["placement_group" ] = _expand_placement_group_assignment (
332- kwargs .get ("placement_group" )
333- )
314+ interfaces = kwargs .get ("interfaces" , None )
315+ if interfaces is not None and isinstance (interfaces , Iterable ):
316+ kwargs ["interfaces" ] = [
317+ i ._serialize () if isinstance (i , ConfigInterface ) else i
318+ for i in interfaces
319+ ]
334320
335321 params = {
336- "type" : ltype .id if issubclass (type (ltype ), Base ) else ltype ,
337- "region" : region .id if issubclass (type (region ), Base ) else region ,
338- "image" : (
339- (image .id if issubclass (type (image ), Base ) else image )
340- if image
322+ "type" : ltype ,
323+ "region" : region ,
324+ "image" : image ,
325+ "authorized_keys" : load_and_validate_keys (authorized_keys ),
326+ # These will automatically be flattened below
327+ "firewall_id" : firewall ,
328+ "backup_id" : backup ,
329+ "stackscript_id" : stackscript ,
330+ # Special cases
331+ "disk_encryption" : (
332+ str (disk_encryption ) if disk_encryption else None
333+ ),
334+ "placement_group" : (
335+ _expand_placement_group_assignment (placement_group )
336+ if placement_group
341337 else None
342338 ),
343- "authorized_keys" : authorized_keys ,
344339 }
345340
346- if disk_encryption is not None :
347- params ["disk_encryption" ] = str (disk_encryption )
348-
349341 params .update (kwargs )
350342
351- result = self .client .post ("/linode/instances" , data = params )
343+ result = self .client .post (
344+ "/linode/instances" ,
345+ data = _flatten_request_body_recursive (drop_null_keys (params )),
346+ )
352347
353348 if not "id" in result :
354349 raise UnexpectedResponseError (
@@ -421,19 +416,6 @@ def stackscript_create(
421416 :returns: The new StackScript
422417 :rtype: StackScript
423418 """
424- image_list = None
425- if type (images ) is list or type (images ) is PaginatedList :
426- image_list = [
427- d .id if issubclass (type (d ), Base ) else d for d in images
428- ]
429- elif type (images ) is Image :
430- image_list = [images .id ]
431- elif type (images ) is str :
432- image_list = [images ]
433- else :
434- raise ValueError (
435- "images must be a list of Images or a single Image"
436- )
437419
438420 script_body = script
439421 if not script .startswith ("#!" ):
@@ -448,14 +430,17 @@ def stackscript_create(
448430
449431 params = {
450432 "label" : label ,
451- "images" : image_list ,
433+ "images" : images ,
452434 "is_public" : public ,
453435 "script" : script_body ,
454436 "description" : desc if desc else "" ,
455437 }
456438 params .update (kwargs )
457439
458- result = self .client .post ("/linode/stackscripts" , data = params )
440+ result = self .client .post (
441+ "/linode/stackscripts" ,
442+ data = _flatten_request_body_recursive (params ),
443+ )
459444
460445 if not "id" in result :
461446 raise UnexpectedResponseError (
0 commit comments