Skip to content

Commit e474c30

Browse files
authored
CI small fix (#797)
* add a wait and timeout for principals to be removed from an iot thing * move certificate deletion * f-string fix
1 parent f00c3a5 commit e474c30

File tree

1 file changed

+56
-4
lines changed

1 file changed

+56
-4
lines changed

utils/ci_iot_thing.py

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,46 @@
33

44
import 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

947
def 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(f"ERROR: Could not delete certificate for IoT thing {thing_name}, probably thing does not exist",
110+
print(f"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(f"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

Comments
 (0)