33
44import logging
55import boto3
6+ import time
67
78from botocore .exceptions import ClientError
89
@@ -32,61 +33,6 @@ def from_client(cls):
3233
3334 # snippet-end:[python.example_code.controltower.ControlTowerWrapper.decl]
3435
35- # snippet-start:[python.example_code.controltower.SetupLandingZone]
36- def create_landing_zone (self , manifest ):
37- """
38- Sets up a landing zone using the provided manifest.
39-
40- :param manifest: The landing zone manifest containing configuration details.
41- :return: Dictionary containing the landing zone ARN and operation ID.
42- :raises ClientError: If the landing zone setup fails.
43-
44- """
45- try :
46- response = self .controltower_client .create_landing_zone (
47- manifest = manifest ,
48- version = '3.3'
49- )
50- return response
51- except ClientError as err :
52- if err .response ["Error" ]["Code" ] == "AccessDeniedException" :
53- logger .error ("Access denied. Please ensure you have the necessary permissions." )
54- else :
55- logger .error (
56- "Couldn't set up landing zone. Here's why: %s: %s" ,
57- err .response ["Error" ]["Code" ],
58- err .response ["Error" ]["Message" ]
59- )
60- raise
61-
62- # snippet-end:[python.example_code.controltower.SetupLandingZone]
63-
64- # snippet-start:[python.example_code.controltower.DeleteLandingZone]
65- def delete_landing_zone (self , landing_zone_identifier ):
66- """
67- Deletes a landing zone by its identifier.
68-
69- :param landing_zone_identifier: The landing zone identifier to delete.
70- :raises ClientError: If the landing zone delete fails.
71-
72- """
73- try :
74- self .controltower_client .delete_landing_zone (
75- landingZoneIdentifier = landing_zone_identifier
76- )
77- except ClientError as err :
78- if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
79- logger .error ("Landing zone not found." )
80- else :
81- logger .error (
82- "Couldn't delete landing zone. Here's why: %s: %s" ,
83- err .response ["Error" ]["Code" ],
84- err .response ["Error" ]["Message" ]
85- )
86- raise
87-
88- # snippet-end:[python.example_code.controltower.DeleteLandingZone]
89-
9036 # snippet-start:[python.example_code.controltower.ListBaselines]
9137 def list_baselines (self ):
9238 """
@@ -116,12 +62,13 @@ def list_baselines(self):
11662 # snippet-end:[python.example_code.controltower.ListBaselines]
11763
11864 # snippet-start:[python.example_code.controltower.EnableBaseline]
119- def enable_baseline (self , target_identifier , baseline_identifier , baseline_version ):
65+ def enable_baseline (self , target_identifier , identity_center_baseline , baseline_identifier , baseline_version ):
12066 """
12167 Enables a baseline for the specified target if it's not already enabled.
12268
12369 :param target_identifier: The ARN of the target.
12470 :param baseline_identifier: The identifier of baseline to enable.
71+ :param identity_center_baseline: The identifier of identity center baseline if it is enabled.
12572 :param baseline_version: The version of baseline to enable.
12673 :return: The enabled baseline ARN or None if already enabled.
12774 :raises ClientError: If enabling the baseline fails for reasons other than it being already enabled.
@@ -130,13 +77,29 @@ def enable_baseline(self, target_identifier, baseline_identifier, baseline_versi
13077 response = self .controltower_client .enable_baseline (
13178 baselineIdentifier = baseline_identifier ,
13279 baselineVersion = baseline_version ,
133- targetIdentifier = target_identifier
80+ targetIdentifier = target_identifier ,
81+ parameters = [
82+ {
83+ "key" : "IdentityCenterEnabledBaselineArn" ,
84+ "value" : identity_center_baseline
85+ }
86+ ]
13487 )
88+
89+ operation_id = response ['operationIdentifier' ]
90+ while True :
91+ status = self .get_baseline_operation (operation_id )
92+ print (f"Baseline operation status: { status } " )
93+ if status in ['SUCCEEDED' , 'FAILED' ]:
94+ break
95+ time .sleep (30 )
96+
13597 return response ['arn' ]
13698 except ClientError as err :
13799 if err .response ["Error" ]["Code" ] == "ValidationException" :
138100 if "already enabled" in err .response ["Error" ]["Message" ]:
139101 print ("Baseline is already enabled for this target" )
102+ return None
140103 else :
141104 print ("Unable to enable baseline due to validation exception: %s: %s" ,
142105 err .response ["Error" ]["Code" ],
@@ -194,7 +157,16 @@ def enable_control(self, control_arn, target_identifier):
194157 controlIdentifier = control_arn ,
195158 targetIdentifier = target_identifier
196159 )
197- return response ['operationIdentifier' ]
160+
161+ operation_id = response ['operationIdentifier' ]
162+ while True :
163+ status = self .get_control_operation (operation_id )
164+ print (f"Control operation status: { status } " )
165+ if status in ['SUCCEEDED' , 'FAILED' ]:
166+ break
167+ time .sleep (30 )
168+
169+ return operation_id
198170
199171 except ClientError as err :
200172 if (err .response ["Error" ]["Code" ] == "ValidationException" and
@@ -227,7 +199,7 @@ def get_control_operation(self, operation_id):
227199 return response ['controlOperation' ]['status' ]
228200 except ClientError as err :
229201 if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
230- logger .error ("Control not found." )
202+ logger .error ("Operation not found." )
231203 else :
232204 logger .error (
233205 "Couldn't get control operation status. Here's why: %s: %s" ,
@@ -238,61 +210,70 @@ def get_control_operation(self, operation_id):
238210
239211 # snippet-end:[python.example_code.controltower.GetControlOperation]
240212
241- # snippet-start:[python.example_code.controltower.DisableControl ]
242- def disable_control (self , control_arn , target_identifier ):
213+ # snippet-start:[python.example_code.controltower.GetBaselineOperation ]
214+ def get_baseline_operation (self , operation_id ):
243215 """
244- Disables a control for a specified target .
216+ Gets the status of a baseline operation .
245217
246- :param control_arn: The ARN of the control to disable.
247- :param target_identifier: The identifier of the target (e.g., OU ARN).
248- :return: The operation ID.
249- :raises ClientError: If disabling the control fails.
218+ :param operation_id: The ID of the baseline operation.
219+ :return: The operation status.
220+ :raises ClientError: If getting the operation status fails.
250221 """
251222 try :
252- response = self .controltower_client .disable_control (
253- controlIdentifier = control_arn ,
254- targetIdentifier = target_identifier
223+ response = self .controltower_client .get_baseline_operation (
224+ operationIdentifier = operation_id
255225 )
256- return response ['operationIdentifier ' ]
226+ return response ['baselineOperation' ][ 'status ' ]
257227 except ClientError as err :
258228 if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
259- logger .error ("Control not found." )
229+ logger .error ("Operation not found." )
260230 else :
261231 logger .error (
262- "Couldn't disable control . Here's why: %s: %s" ,
232+ "Couldn't get baseline operation status . Here's why: %s: %s" ,
263233 err .response ["Error" ]["Code" ],
264234 err .response ["Error" ]["Message" ]
265235 )
266236 raise
267237
268- # snippet-end:[python.example_code.controltower.DisableControl ]
238+ # snippet-end:[python.example_code.controltower.GetBaselineOperation ]
269239
270- # snippet-start:[python.example_code.controltower.GetLandingZoneOperation ]
271- def get_landing_zone_operation (self , operation_id ):
240+ # snippet-start:[python.example_code.controltower.DisableControl ]
241+ def disable_control (self , control_arn , target_identifier ):
272242 """
273- Gets the status of a landing zone operation .
243+ Disables a control for a specified target .
274244
275- :param operation_id: The ID of the landing zone operation.
276- :return: The operation status.
277- :raises ClientError: If getting the operation status fails.
245+ :param control_arn: The ARN of the control to disable.
246+ :param target_identifier: The identifier of the target (e.g., OU ARN).
247+ :return: The operation ID.
248+ :raises ClientError: If disabling the control fails.
278249 """
279250 try :
280- response = self .controltower_client .get_landing_zone_operation (
281- operationIdentifier = operation_id
251+ response = self .controltower_client .disable_control (
252+ controlIdentifier = control_arn ,
253+ targetIdentifier = target_identifier
282254 )
283- return response ['operationDetails' ]['status' ]
255+
256+ operation_id = response ['operationIdentifier' ]
257+ while True :
258+ status = self .get_control_operation (operation_id )
259+ print (f"Control operation status: { status } " )
260+ if status in ['SUCCEEDED' , 'FAILED' ]:
261+ break
262+ time .sleep (30 )
263+
264+ return operation_id
284265 except ClientError as err :
285266 if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
286- logger .error ("Landing zone not found." )
267+ logger .error ("Control not found." )
287268 else :
288269 logger .error (
289- "Couldn't get landing zone operation status . Here's why: %s: %s" ,
270+ "Couldn't disable control . Here's why: %s: %s" ,
290271 err .response ["Error" ]["Code" ],
291272 err .response ["Error" ]["Message" ]
292273 )
293274 raise
294275
295- # snippet-end:[python.example_code.controltower.GetLandingZoneOperation ]
276+ # snippet-end:[python.example_code.controltower.DisableControl ]
296277
297278 # snippet-start:[python.example_code.controltower.ListLandingZones]
298279 def list_landing_zones (self ):
@@ -333,66 +314,87 @@ def list_enabled_baselines(self, target_identifier):
333314 try :
334315 paginator = self .controltower_client .get_paginator ('list_enabled_baselines' )
335316 enabled_baselines = []
336- for page in paginator .paginate (targetIdentifier = target_identifier ):
317+ for page in paginator .paginate ():
337318 enabled_baselines .extend (page ['enabledBaselines' ])
338319 return enabled_baselines
339320
340321 except ClientError as err :
341- logger .error (
342- "Couldn't list enabled baselines. Here's why: %s: %s" ,
343- err .response ["Error" ]["Code" ],
344- err .response ["Error" ]["Message" ]
345- )
322+ if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
323+ logger .error ("Target not found." )
324+ else :
325+ logger .error (
326+ "Couldn't list enabled baselines. Here's why: %s: %s" ,
327+ err .response ["Error" ]["Code" ],
328+ err .response ["Error" ]["Message" ]
329+ )
346330 raise
347331 # snippet-end:[python.example_code.controltower.ListEnabledBaselines]
348332
349333 # snippet-start:[python.example_code.controltower.ResetEnabledBaseline]
350- def reset_enabled_baseline (self , target_identifier , baseline_identifier ):
334+ def reset_enabled_baseline (self , enabled_baseline_identifier ):
351335 """
352336 Resets an enabled baseline for a specific target.
353337
354- :param target_identifier: The identifier of the target (e.g., OU ARN).
355- :param baseline_identifier: The identifier of the baseline to reset.
338+ :param enabled_baseline_identifier: The identifier of the enabled baseline to reset.
356339 :return: The operation ID.
357340 :raises ClientError: If resetting the baseline fails.
358341 """
359342 try :
360343 response = self .controltower_client .reset_enabled_baseline (
361- targetIdentifier = target_identifier ,
362- baselineIdentifier = baseline_identifier
344+ enabledBaselineIdentifier = enabled_baseline_identifier
363345 )
364- return response ['operationIdentifier' ]
346+ operation_id = response ['operationIdentifier' ]
347+ while True :
348+ status = self .get_baseline_operation (operation_id )
349+ print (f"Baseline operation status: { status } " )
350+ if status in ['SUCCEEDED' , 'FAILED' ]:
351+ break
352+ time .sleep (30 )
353+ return operation_id
365354 except ClientError as err :
366- logger .error (
367- "Couldn't reset enabled baseline. Here's why: %s: %s" ,
368- err .response ["Error" ]["Code" ],
369- err .response ["Error" ]["Message" ]
370- )
355+ if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
356+ logger .error ("Target not found." )
357+ else :
358+ logger .error (
359+ "Couldn't reset enabled baseline. Here's why: %s: %s" ,
360+ err .response ["Error" ]["Code" ],
361+ err .response ["Error" ]["Message" ]
362+ )
371363 raise
372364 # snippet-end:[python.example_code.controltower.ResetEnabledBaseline]
373365
374366 # snippet-start:[python.example_code.controltower.DisableBaseline]
375- def disable_baseline (self , target_identifier , baseline_identifier ):
367+ def disable_baseline (self , enabled_baseline_identifier ):
376368 """
377- Disables a baseline for a specific target.
369+ Disables a baseline for a specific target and waits for the operation to complete .
378370
379- :param target_identifier: The identifier of the target (e.g., OU ARN).
380- :param baseline_identifier: The identifier of the baseline to disable.
371+ :param enabled_baseline_identifier: The identifier of the baseline to disable.
381372 :return: The operation ID.
382373 :raises ClientError: If disabling the baseline fails.
383374 """
384375 try :
385376 response = self .controltower_client .disable_baseline (
386- targetIdentifier = target_identifier ,
387- baselineIdentifier = baseline_identifier
377+ enabledBaselineIdentifier = enabled_baseline_identifier
388378 )
379+
380+ operation_id = response ['operationIdentifier' ]
381+ while True :
382+ status = self .get_baseline_operation (operation_id )
383+ print (f"Baseline operation status: { status } " )
384+ if status in ['SUCCEEDED' , 'FAILED' ]:
385+ break
386+ time .sleep (30 )
387+
389388 return response ['operationIdentifier' ]
390389 except ClientError as err :
391- logger .error (
392- "Couldn't disable baseline. Here's why: %s: %s" ,
393- err .response ["Error" ]["Code" ],
394- err .response ["Error" ]["Message" ]
395- )
390+ if err .response ["Error" ]["Code" ] == "ResourceNotFoundException" :
391+ logger .error ("Target not found." )
392+ else :
393+ logger .error (
394+ "Couldn't disable baseline. Here's why: %s: %s" ,
395+ err .response ["Error" ]["Code" ],
396+ err .response ["Error" ]["Message" ]
397+ )
396398 raise
397399 # snippet-end:[python.example_code.controltower.DisableBaseline]
398400
@@ -413,11 +415,14 @@ def list_enabled_controls(self, target_identifier):
413415 return enabled_controls
414416
415417 except ClientError as err :
416- logger .error (
417- "Couldn't list enabled controls. Here's why: %s: %s" ,
418- err .response ["Error" ]["Code" ],
419- err .response ["Error" ]["Message" ]
420- )
418+ if err .response ["Error" ]["Code" ] == "AccessDeniedException" :
419+ logger .error ("Access denied. Please ensure you have the necessary permissions." )
420+ else :
421+ logger .error (
422+ "Couldn't list enabled controls. Here's why: %s: %s" ,
423+ err .response ["Error" ]["Code" ],
424+ err .response ["Error" ]["Message" ]
425+ )
421426 raise
422427 # snippet-end:[python.example_code.controltower.ListEnabledControls]
423428
0 commit comments