33
44import  sys 
55
6- import  boto3 
7- 
6+ import  boto3 , time 
7+ from  botocore .exceptions  import  ClientError , WaiterError 
8+ 
9+ class  ThingDetachedWaiter :
10+  """ 
11+  Wait until principal (cert or Cognito identity) is detached from a thing. 
12+  Raise WaiterError after timeout seconds. 
13+  """ 
14+ 
15+  def  __init__ (self , client , delay = 2.0 , max_delay = 10.0 , timeout = 60.0 ):
16+  self ._client  =  client 
17+  self ._delay  =  delay 
18+  self ._max_delay  =  max_delay 
19+  self ._timeout  =  timeout 
20+ 
21+  def  wait (self , thing_name ):
22+  start  =  time .monotonic ()
23+  sleep  =  self ._delay 
24+ 
25+  while  True :
26+  try :
27+  resp  =  self ._client .list_thing_principals (thingName = thing_name )
28+  except  ClientError  as  e :
29+  if  e .response ["Error" ]["Code" ] ==  "ResourceNotFoundException" :
30+  return 
31+  raise 
32+ 
33+  if  not  resp .get ("principals" ):
34+  # No principals, we can move on. 
35+  return 
36+ 
37+  if  time .monotonic () -  start  >  self ._timeout :
38+  raise  WaiterError (
39+  name = "ThingDetached" ,
40+  reason = "timeout" ,
41+  last_response = resp ,
42+  )
43+ 
44+  time .sleep (sleep )
45+  sleep  =  min (sleep  *  1.6 , self ._max_delay ) # exponential backoff on retrys 
846
947def  create_iot_thing (thing_name , region , policy_name , certificate_path , key_path , thing_group = None ):
1048 """ Create IoT thing along with policy and credentials. """ 
@@ -57,6 +95,8 @@ def delete_iot_thing(thing_name, region):
5795 print (f"ERROR: Could not make Boto3 client. Credentials likely could not be sourced" , file = sys .stderr )
5896 raise 
5997
98+  cert_ids  =  []
99+ 
60100 # Detach and delete thing's principals. 
61101 try :
62102 thing_principals  =  iot_client .list_thing_principals (thingName = thing_name )
@@ -65,12 +105,24 @@ def delete_iot_thing(thing_name, region):
65105 certificate_id  =  principal .split ("/" )[1 ]
66106 iot_client .detach_thing_principal (thingName = thing_name , principal = principal )
67107 iot_client .update_certificate (certificateId = certificate_id , newStatus = 'INACTIVE' )
68-  iot_client . delete_certificate ( certificateId = certificate_id ,  forceDelete = True )
108+  cert_ids . append ( certificate_id )
69109 except  Exception :
70-  print ("ERROR: Could not delete  certificate for IoT thing  {thing_name}, probably thing does not exist" ,
110+  print ("ERROR: Could not detatch principal or set its  certificate to INACTIVE for  {thing_name}, probably thing does not exist" ,
71111 file = sys .stderr )
72112 raise 
73113
114+  # Wait for thing to be free of principals 
115+  ThingDetachedWaiter (iot_client , timeout = 10 ).wait (thing_name )
116+ 
117+  # Delete all the certificates 
118+  for  cert  in  cert_ids :
119+  try :
120+  iot_client .delete_certificate (certificateId = cert , forceDelete = True )
121+  except  Exception :
122+  print ("ERROR: Could not delete certificate for IoT thing {thing_name}." ,
123+  file = sys .stderr )
124+  raise 
125+ 
74126 # Delete thing. 
75127 try :
76128 iot_client .delete_thing (thingName = thing_name )
0 commit comments