skilleter-thingy 0.0.24__py3-none-any.whl → 0.0.25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of skilleter-thingy might be problematic. Click here for more details.
- skilleter_thingy/imagedupe.py +281 -0
- skilleter_thingy/photodupe.py +42 -16
- {skilleter_thingy-0.0.24.dist-info → skilleter_thingy-0.0.25.dist-info}/METADATA +2 -2
- {skilleter_thingy-0.0.24.dist-info → skilleter_thingy-0.0.25.dist-info}/RECORD +8 -9
- skilleter_thingy/aws.py +0 -548
- skilleter_thingy/s3_sync.py +0 -383
- {skilleter_thingy-0.0.24.dist-info → skilleter_thingy-0.0.25.dist-info}/LICENSE +0 -0
- {skilleter_thingy-0.0.24.dist-info → skilleter_thingy-0.0.25.dist-info}/WHEEL +0 -0
- {skilleter_thingy-0.0.24.dist-info → skilleter_thingy-0.0.25.dist-info}/entry_points.txt +0 -0
- {skilleter_thingy-0.0.24.dist-info → skilleter_thingy-0.0.25.dist-info}/top_level.txt +0 -0
skilleter_thingy/aws.py
DELETED
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
#! /usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
################################################################################
|
|
4
|
-
""" Simple AWS module - provides an abstraction layer on top of the boto3 client
|
|
5
|
-
for simple operations such as reading/writing S3 buckets, sending emails
|
|
6
|
-
etc.
|
|
7
|
-
|
|
8
|
-
Currently this is a random collection of functions extracted from the S3
|
|
9
|
-
bucket ACL checking code but it is hoped it will evolve over time into
|
|
10
|
-
something more comprehensive.
|
|
11
|
-
|
|
12
|
-
Author: John Skilleter
|
|
13
|
-
"""
|
|
14
|
-
################################################################################
|
|
15
|
-
|
|
16
|
-
# System modules
|
|
17
|
-
|
|
18
|
-
import sys
|
|
19
|
-
import logging
|
|
20
|
-
import json
|
|
21
|
-
|
|
22
|
-
# AWS modules
|
|
23
|
-
|
|
24
|
-
import boto3
|
|
25
|
-
import botocore
|
|
26
|
-
|
|
27
|
-
################################################################################
|
|
28
|
-
|
|
29
|
-
class GenericAWS:
|
|
30
|
-
""" Class providing generic S3 functionality from which the
|
|
31
|
-
other S3 classes are derived """
|
|
32
|
-
|
|
33
|
-
################################################################################
|
|
34
|
-
|
|
35
|
-
def __init__(self, service, session=None, profile=None, createresource=True, createclient=True, region=None):
|
|
36
|
-
""" Initialisation - just create a client handle, optionally using
|
|
37
|
-
the specified profile """
|
|
38
|
-
|
|
39
|
-
if session:
|
|
40
|
-
self.session = session
|
|
41
|
-
elif profile:
|
|
42
|
-
self.session = boto3.session.Session(profile_name=profile)
|
|
43
|
-
else:
|
|
44
|
-
self.session = boto3
|
|
45
|
-
|
|
46
|
-
args = {}
|
|
47
|
-
if region:
|
|
48
|
-
args['region_name'] = region
|
|
49
|
-
|
|
50
|
-
if createresource:
|
|
51
|
-
self.resource = self.session.resource(service, **args)
|
|
52
|
-
|
|
53
|
-
if createclient:
|
|
54
|
-
self.client = self.session.client(service, **args)
|
|
55
|
-
|
|
56
|
-
self.log = logging.getLogger('%s:%s' % (__name__, service))
|
|
57
|
-
|
|
58
|
-
################################################################################
|
|
59
|
-
|
|
60
|
-
def set_log_level(self, level):
|
|
61
|
-
""" Set logging for the module """
|
|
62
|
-
|
|
63
|
-
self.log.setLevel(level)
|
|
64
|
-
|
|
65
|
-
################################################################################
|
|
66
|
-
|
|
67
|
-
class SES(GenericAWS):
|
|
68
|
-
""" Class for AWS Simple Email Service """
|
|
69
|
-
|
|
70
|
-
################################################################################
|
|
71
|
-
|
|
72
|
-
def __init__(self, session=None, profile=None):
|
|
73
|
-
""" Initialisation """
|
|
74
|
-
|
|
75
|
-
super().__init__('ses', session, profile, createresource=False)
|
|
76
|
-
|
|
77
|
-
################################################################################
|
|
78
|
-
|
|
79
|
-
def send(self, sender, recipient, subject, body):
|
|
80
|
-
""" Send an email """
|
|
81
|
-
|
|
82
|
-
destination = \
|
|
83
|
-
{
|
|
84
|
-
'ToAddresses': [recipient]
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
message = \
|
|
88
|
-
{
|
|
89
|
-
'Subject':
|
|
90
|
-
{
|
|
91
|
-
'Data': subject
|
|
92
|
-
},
|
|
93
|
-
'Body':
|
|
94
|
-
{
|
|
95
|
-
'Text':
|
|
96
|
-
{
|
|
97
|
-
'Data': body
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
# Attempt to send the email - just report the error and quit on failure
|
|
103
|
-
|
|
104
|
-
try:
|
|
105
|
-
self.log.info('Sending email from %s to %s', sender, recipient)
|
|
106
|
-
|
|
107
|
-
self.client.send_email(Source=sender,
|
|
108
|
-
Destination=destination,
|
|
109
|
-
Message=message)
|
|
110
|
-
|
|
111
|
-
except (botocore.exceptions.EndpointConnectionError,
|
|
112
|
-
self.client.exceptions.MessageRejected) as err:
|
|
113
|
-
print('')
|
|
114
|
-
print('Error sending email: %sn' % err)
|
|
115
|
-
print(' Sender: %s' % sender)
|
|
116
|
-
print(' Recipient: %s' % recipient)
|
|
117
|
-
print(' Subject: %s' % subject)
|
|
118
|
-
print(' Body:')
|
|
119
|
-
|
|
120
|
-
for txt in body.split('\n'):
|
|
121
|
-
print(' %s' % txt)
|
|
122
|
-
|
|
123
|
-
print('')
|
|
124
|
-
|
|
125
|
-
sys.exit(1)
|
|
126
|
-
|
|
127
|
-
################################################################################
|
|
128
|
-
|
|
129
|
-
class S3Bucket(GenericAWS):
|
|
130
|
-
""" Class providing access to S3 buckets """
|
|
131
|
-
|
|
132
|
-
################################################################################
|
|
133
|
-
|
|
134
|
-
def __init__(self, session=None, profile=None):
|
|
135
|
-
""" Initialisation - just create a client handle, optionally using
|
|
136
|
-
the specified profile """
|
|
137
|
-
|
|
138
|
-
super().__init__('s3', session, profile)
|
|
139
|
-
|
|
140
|
-
################################################################################
|
|
141
|
-
|
|
142
|
-
def read(self, bucket, key):
|
|
143
|
-
""" Read the specified data from the specified bucket.
|
|
144
|
-
Returns the data, or raises a boto3 exception on error. """
|
|
145
|
-
|
|
146
|
-
self.log.info('Get object from key %s in bucket %s', key, bucket)
|
|
147
|
-
|
|
148
|
-
response = self.client.get_object(Bucket=bucket, Key=key)
|
|
149
|
-
|
|
150
|
-
self.log.debug('Get object: %s', response)
|
|
151
|
-
|
|
152
|
-
return response['Body'].read()
|
|
153
|
-
|
|
154
|
-
################################################################################
|
|
155
|
-
|
|
156
|
-
def write(self, bucket, key, data):
|
|
157
|
-
""" Write data into the specified key of the specified bucket
|
|
158
|
-
Raises a boto3 exception on error. """
|
|
159
|
-
|
|
160
|
-
self.log.info('Writing %d bytes of data to key %s in bucket %s', len(data), key, bucket)
|
|
161
|
-
|
|
162
|
-
self.client.put_object(Bucket=bucket, Key=key, Body=data)
|
|
163
|
-
|
|
164
|
-
################################################################################
|
|
165
|
-
|
|
166
|
-
def get_tags(self, bucket):
|
|
167
|
-
""" Read the tags from a bucket. Returns a dictionary of tags, which will be
|
|
168
|
-
empty if the bucket has no tags. """
|
|
169
|
-
|
|
170
|
-
self.log.info('Reading tags from bucket %s', bucket)
|
|
171
|
-
|
|
172
|
-
try:
|
|
173
|
-
tags = self.client.get_bucket_tagging(Bucket=bucket)['TagSet']
|
|
174
|
-
|
|
175
|
-
except botocore.exceptions.ClientError as err:
|
|
176
|
-
# Any exception except NoSuchTagSet gets raised.
|
|
177
|
-
# NoSuchTagSet simply means that the bucket has no tags
|
|
178
|
-
# and isn't really an error, as such, so we just return
|
|
179
|
-
# an empty dictionary.
|
|
180
|
-
|
|
181
|
-
if err.response['Error']['Code'] != 'NoSuchTagSet':
|
|
182
|
-
self.log.error('Error reading tags for bucket %s: %s', bucket, err.response['Error']['Code'])
|
|
183
|
-
raise
|
|
184
|
-
|
|
185
|
-
tags = {}
|
|
186
|
-
|
|
187
|
-
self.log.info('Tags: %s', tags)
|
|
188
|
-
|
|
189
|
-
return tags
|
|
190
|
-
|
|
191
|
-
################################################################################
|
|
192
|
-
|
|
193
|
-
def get_location(self, bucket):
|
|
194
|
-
""" Return the location of a bucket - note that the Boto3 returns the location
|
|
195
|
-
set to none, rather than us-east-1 if you query a bucket located in that
|
|
196
|
-
region. """
|
|
197
|
-
|
|
198
|
-
try:
|
|
199
|
-
location = self.client.get_bucket_location(Bucket=bucket)['LocationConstraint']
|
|
200
|
-
except botocore.exceptions.ClientError as err:
|
|
201
|
-
self.log.info('Error getting location of bucket %s: %s', bucket, err.response['Error']['Code'])
|
|
202
|
-
raise
|
|
203
|
-
|
|
204
|
-
if not location:
|
|
205
|
-
location = 'us-east-1'
|
|
206
|
-
|
|
207
|
-
return location
|
|
208
|
-
|
|
209
|
-
################################################################################
|
|
210
|
-
|
|
211
|
-
def get_acl(self, bucket):
|
|
212
|
-
""" Return the bucket ACLs """
|
|
213
|
-
|
|
214
|
-
try:
|
|
215
|
-
return self.client.get_bucket_acl(Bucket=bucket)['Grants']
|
|
216
|
-
except botocore.exceptions.ClientError as err:
|
|
217
|
-
self.log.error('Error getting ACL for bucket %s: %s', bucket, err.response['Error']['Code'])
|
|
218
|
-
raise
|
|
219
|
-
|
|
220
|
-
################################################################################
|
|
221
|
-
|
|
222
|
-
def get_policy(self, bucket):
|
|
223
|
-
""" Return bucket policy information as a list of policy dictionaries
|
|
224
|
-
Returns an empty list if the bucket has no policies (similar to
|
|
225
|
-
get_tags() above). """
|
|
226
|
-
|
|
227
|
-
try:
|
|
228
|
-
policy_data = self.client.get_bucket_policy(Bucket=bucket)
|
|
229
|
-
|
|
230
|
-
except botocore.exceptions.ClientError as err:
|
|
231
|
-
# Any exception which *isn't* a no-policy exception gets raised
|
|
232
|
-
# to the caller, the no-policy one causes the function to return
|
|
233
|
-
# an empty policy list.
|
|
234
|
-
|
|
235
|
-
if err.response['Error']['Code'] != 'NoSuchBucketPolicy':
|
|
236
|
-
self.log.error('Error reading policy for bucket %s: %s', bucket, err.response['Error']['Code'])
|
|
237
|
-
raise
|
|
238
|
-
|
|
239
|
-
return []
|
|
240
|
-
|
|
241
|
-
return json.loads(policy_data['Policy'])
|
|
242
|
-
|
|
243
|
-
################################################################################
|
|
244
|
-
|
|
245
|
-
def get_buckets(self):
|
|
246
|
-
""" Return a list of all the available buckets """
|
|
247
|
-
|
|
248
|
-
return [bucket.name for bucket in self.resource.buckets.all()]
|
|
249
|
-
|
|
250
|
-
################################################################################
|
|
251
|
-
|
|
252
|
-
def get_website(self, bucket):
|
|
253
|
-
""" Return the web site configuration for the bucket, or None if the bucket
|
|
254
|
-
is not configured for hosting """
|
|
255
|
-
|
|
256
|
-
try:
|
|
257
|
-
web = self.client.get_bucket_website(Bucket=bucket)
|
|
258
|
-
|
|
259
|
-
except botocore.exceptions.ClientError as err:
|
|
260
|
-
if err.response['Error']['Code'] != 'NoSuchWebsiteConfiguration':
|
|
261
|
-
print('>>>%s' % err.response)
|
|
262
|
-
raise
|
|
263
|
-
|
|
264
|
-
web = None
|
|
265
|
-
|
|
266
|
-
return web
|
|
267
|
-
|
|
268
|
-
################################################################################
|
|
269
|
-
|
|
270
|
-
def get_objects(self, bucket, max_objects=None):
|
|
271
|
-
""" Yield a list of the details of the objects in a bucket, stopping after
|
|
272
|
-
returning max_objects (if specified). """
|
|
273
|
-
|
|
274
|
-
paginator = self.client.get_paginator('list_objects_v2')
|
|
275
|
-
|
|
276
|
-
pagesize = min(25, max_objects) if max_objects else 25
|
|
277
|
-
|
|
278
|
-
objects = paginator.paginate(Bucket=bucket, PaginationConfig={'PageSize': pagesize})
|
|
279
|
-
|
|
280
|
-
count = 0
|
|
281
|
-
|
|
282
|
-
for data in objects:
|
|
283
|
-
if 'Contents' in data:
|
|
284
|
-
for obj in data['Contents']:
|
|
285
|
-
|
|
286
|
-
if max_objects:
|
|
287
|
-
count += 1
|
|
288
|
-
if count > max_objects:
|
|
289
|
-
break
|
|
290
|
-
|
|
291
|
-
yield obj
|
|
292
|
-
|
|
293
|
-
################################################################################
|
|
294
|
-
|
|
295
|
-
def get_object_acl(self, bucket, obj):
|
|
296
|
-
""" Return the ACL data for an object in a bucket """
|
|
297
|
-
|
|
298
|
-
try:
|
|
299
|
-
return self.client.get_object_acl(Bucket=bucket, Key=obj)['Grants']
|
|
300
|
-
except botocore.exceptions.ClientError as err:
|
|
301
|
-
self.log.error('Error getting ACL for object %s in bucket %s: %s', obj, bucket, err.response['Error']['Code'])
|
|
302
|
-
raise
|
|
303
|
-
|
|
304
|
-
################################################################################
|
|
305
|
-
|
|
306
|
-
def get_lifecycle(self, bucket):
|
|
307
|
-
""" Return the bucket lifecycle data """
|
|
308
|
-
|
|
309
|
-
try:
|
|
310
|
-
lifecycle = self.client.get_bucket_lifecycle_configuration(Bucket=bucket)
|
|
311
|
-
except botocore.exceptions.ClientError as err:
|
|
312
|
-
if err.response['Error']['Code'] == 'NoSuchLifecycleConfiguration':
|
|
313
|
-
lifecycle = None
|
|
314
|
-
else:
|
|
315
|
-
raise
|
|
316
|
-
|
|
317
|
-
return lifecycle
|
|
318
|
-
|
|
319
|
-
################################################################################
|
|
320
|
-
|
|
321
|
-
class STS(GenericAWS):
|
|
322
|
-
""" Class providing access to STS functionality """
|
|
323
|
-
|
|
324
|
-
def __init__(self, session=None, profile=None):
|
|
325
|
-
""" Initialise the STS client (there is no STS resource in boto3) """
|
|
326
|
-
|
|
327
|
-
super().__init__('sts', session, profile, createresource=False)
|
|
328
|
-
|
|
329
|
-
################################################################################
|
|
330
|
-
|
|
331
|
-
def account(self):
|
|
332
|
-
""" Return the name of the current AWS account """
|
|
333
|
-
|
|
334
|
-
return self.client.get_caller_identity()['Account']
|
|
335
|
-
|
|
336
|
-
################################################################################
|
|
337
|
-
|
|
338
|
-
class IAM(GenericAWS):
|
|
339
|
-
""" Class providing access to IAM """
|
|
340
|
-
|
|
341
|
-
def __init__(self, session=None, profile=None):
|
|
342
|
-
""" Initialise the IAM client/resource """
|
|
343
|
-
|
|
344
|
-
super().__init__('iam', session, profile, createresource=False)
|
|
345
|
-
|
|
346
|
-
def role_exists(self, role):
|
|
347
|
-
""" Return True if the role exists """
|
|
348
|
-
|
|
349
|
-
try:
|
|
350
|
-
self.client.get_role(RoleName=role)
|
|
351
|
-
except botocore.exceptions.ClientError as err:
|
|
352
|
-
if err.response['Error']['Code'] != 'NoSuchEntity':
|
|
353
|
-
raise
|
|
354
|
-
|
|
355
|
-
return False
|
|
356
|
-
else:
|
|
357
|
-
return True
|
|
358
|
-
|
|
359
|
-
def create_role(self, role, description, policy):
|
|
360
|
-
""" Create a new role """
|
|
361
|
-
|
|
362
|
-
response = self.client.create_role(RoleName=role, Description=description, AssumeRolePolicyDocument=policy)
|
|
363
|
-
|
|
364
|
-
return response
|
|
365
|
-
|
|
366
|
-
def put_role_policy(self, role, policy_name, policy):
|
|
367
|
-
""" Update the policy in an existing role """
|
|
368
|
-
|
|
369
|
-
response = self.client.put_role_policy(RoleName=role, PolicyName=policy_name, PolicyDocument=policy)
|
|
370
|
-
|
|
371
|
-
return response
|
|
372
|
-
|
|
373
|
-
def get_role_policy(self, role, policy_name):
|
|
374
|
-
""" Read the policy in an existing role """
|
|
375
|
-
|
|
376
|
-
response = self.client.get_role_policy(RoleName=role, PolicyName=policy_name)
|
|
377
|
-
|
|
378
|
-
return response
|
|
379
|
-
|
|
380
|
-
################################################################################
|
|
381
|
-
|
|
382
|
-
class Events(GenericAWS):
|
|
383
|
-
""" Class providing access to CloudWatch Events """
|
|
384
|
-
|
|
385
|
-
def __init__(self, session=None, profile=None):
|
|
386
|
-
""" Initialise the CloudWatch Events client/resource """
|
|
387
|
-
|
|
388
|
-
super().__init__('events', session, profile, createresource=False)
|
|
389
|
-
|
|
390
|
-
def put_rule(self, name, schedule):
|
|
391
|
-
""" Create or update the specified rule """
|
|
392
|
-
|
|
393
|
-
self.client.put_rule(Name=name, ScheduleExpression=schedule)
|
|
394
|
-
|
|
395
|
-
def put_target(self, name, targets):
|
|
396
|
-
""" Add the specified target(s) to the specified rule, or update
|
|
397
|
-
existing targets """
|
|
398
|
-
|
|
399
|
-
self.client.put_targets(Rule=name, Targets=targets)
|
|
400
|
-
|
|
401
|
-
################################################################################
|
|
402
|
-
|
|
403
|
-
DEFAULT_LAMBDA_TIMEOUT = 3
|
|
404
|
-
DEFAULT_LAMBDA_MEMORY = 128
|
|
405
|
-
DEFAULT_LAMBDA_HANDLER = 'main.main'
|
|
406
|
-
DEFAULT_LAMBDA_RUNTIME = 'python3.6'
|
|
407
|
-
|
|
408
|
-
class Lambda(GenericAWS):
|
|
409
|
-
""" Class providing access to Lambda functions """
|
|
410
|
-
|
|
411
|
-
def __init__(self, session=None, profile=None, region=None):
|
|
412
|
-
""" Initialise the Lambda client/resource """
|
|
413
|
-
|
|
414
|
-
super().__init__('lambda', session, profile, createresource=False, region=region)
|
|
415
|
-
|
|
416
|
-
def exists(self, name):
|
|
417
|
-
""" Return True if the specified Lambda function exists """
|
|
418
|
-
|
|
419
|
-
try:
|
|
420
|
-
self.client.get_function(FunctionName=name)
|
|
421
|
-
except botocore.exceptions.ClientError as err:
|
|
422
|
-
if err.response['Error']['Code'] != 'ResourceNotFoundException':
|
|
423
|
-
raise
|
|
424
|
-
return False
|
|
425
|
-
else:
|
|
426
|
-
return True
|
|
427
|
-
|
|
428
|
-
def update_function(self, name, zipfile):
|
|
429
|
-
""" Update the specified Lambda function given a zip file """
|
|
430
|
-
|
|
431
|
-
with open(zipfile, 'rb') as zipper:
|
|
432
|
-
zipdata = zipper.read()
|
|
433
|
-
|
|
434
|
-
response = self.client.update_function_code(FunctionName=name, ZipFile=zipdata)
|
|
435
|
-
|
|
436
|
-
return response
|
|
437
|
-
|
|
438
|
-
def update_function_configuration(self, name,
|
|
439
|
-
handler=None,
|
|
440
|
-
environment=None):
|
|
441
|
-
""" Update the handler associated with a Lambda fucntion """
|
|
442
|
-
|
|
443
|
-
update_args = {}
|
|
444
|
-
update_args['FunctionName'] = name
|
|
445
|
-
|
|
446
|
-
if handler:
|
|
447
|
-
update_args['Handler'] = handler
|
|
448
|
-
|
|
449
|
-
if environment:
|
|
450
|
-
update_args['Environment'] = {'Variables': environment}
|
|
451
|
-
|
|
452
|
-
self.client.update_function_configuration(**update_args)
|
|
453
|
-
|
|
454
|
-
def create_function(self, name, role, description, zipfile,
|
|
455
|
-
runtime=DEFAULT_LAMBDA_RUNTIME,
|
|
456
|
-
handler=DEFAULT_LAMBDA_HANDLER,
|
|
457
|
-
timeout=DEFAULT_LAMBDA_TIMEOUT,
|
|
458
|
-
memory=DEFAULT_LAMBDA_MEMORY):
|
|
459
|
-
""" Create the specified Lambda function given a zip file"""
|
|
460
|
-
|
|
461
|
-
with open(zipfile, 'rb') as zipper:
|
|
462
|
-
zipdata = zipper.read()
|
|
463
|
-
|
|
464
|
-
response = self.client.create_function(FunctionName=name,
|
|
465
|
-
Runtime=runtime,
|
|
466
|
-
Role=role,
|
|
467
|
-
Handler=handler,
|
|
468
|
-
Code={'ZipFile': zipdata},
|
|
469
|
-
Description=description,
|
|
470
|
-
Timeout=timeout,
|
|
471
|
-
MemorySize=memory)
|
|
472
|
-
|
|
473
|
-
return response
|
|
474
|
-
|
|
475
|
-
################################################################################
|
|
476
|
-
|
|
477
|
-
def get_session(profile_name=None):
|
|
478
|
-
""" Wrapper for boto3.session.Session """
|
|
479
|
-
|
|
480
|
-
return boto3.session.Session(profile_name=profile_name)
|
|
481
|
-
|
|
482
|
-
################################################################################
|
|
483
|
-
|
|
484
|
-
def set_stream_logger(name='botocore', level=10, format_string=None):
|
|
485
|
-
""" Wrapper for boto3.set_stream_logger """
|
|
486
|
-
|
|
487
|
-
return boto3.set_stream_logger(name=name, level=level, format_string=format_string)
|
|
488
|
-
|
|
489
|
-
################################################################################
|
|
490
|
-
|
|
491
|
-
def set_default_region(region):
|
|
492
|
-
""" Set the default region for the module """
|
|
493
|
-
|
|
494
|
-
boto3.setup_default_session(region_name=region)
|
|
495
|
-
|
|
496
|
-
################################################################################
|
|
497
|
-
|
|
498
|
-
def get_regions(servicename):
|
|
499
|
-
""" Generate a list of regions where a service is supported """
|
|
500
|
-
|
|
501
|
-
return boto3.session.Session().get_available_regions(servicename)
|
|
502
|
-
|
|
503
|
-
################################################################################
|
|
504
|
-
|
|
505
|
-
def get_resources():
|
|
506
|
-
""" Devious method of getting the list of clients supported by boto3
|
|
507
|
-
Note that I'm somewhat embarrassed by this, but can't find a better
|
|
508
|
-
way of doing it! """
|
|
509
|
-
|
|
510
|
-
try:
|
|
511
|
-
boto3.resource('XXX-NOT-A-RESOURCE-XXX')
|
|
512
|
-
except boto3.exceptions.ResourceNotExistsError as err:
|
|
513
|
-
return str(err).replace(' - ', '').split('\n')[2:-1]
|
|
514
|
-
|
|
515
|
-
################################################################################
|
|
516
|
-
|
|
517
|
-
def get_clients():
|
|
518
|
-
""" Similarly devious way of getting the list of supported clients.
|
|
519
|
-
This is equally as yukky as the get_resources() function. """
|
|
520
|
-
|
|
521
|
-
try:
|
|
522
|
-
boto3.client('XXX-NOT-A-CLIENT-XXX')
|
|
523
|
-
except botocore.exceptions.UnknownServiceError as err:
|
|
524
|
-
return repr(err)[:-3].split(': ')[2].split(', ')
|
|
525
|
-
|
|
526
|
-
################################################################################
|
|
527
|
-
|
|
528
|
-
def test_function():
|
|
529
|
-
""" Module test function """
|
|
530
|
-
|
|
531
|
-
# Test STS
|
|
532
|
-
|
|
533
|
-
sts_client = STS()
|
|
534
|
-
|
|
535
|
-
print('Current account: %s' % sts_client.account())
|
|
536
|
-
|
|
537
|
-
# TODO: Test SES
|
|
538
|
-
# TODO: Test S3
|
|
539
|
-
# TODO: Test IAM
|
|
540
|
-
# TODO: Test Cloudwatch Events
|
|
541
|
-
# TODO: Test Lambda
|
|
542
|
-
# TODO: Test set_default_region(), get_session(), get_resources(), get_regions(), get_clients()
|
|
543
|
-
|
|
544
|
-
################################################################################
|
|
545
|
-
# Test code
|
|
546
|
-
|
|
547
|
-
if __name__ == '__main__':
|
|
548
|
-
test_function()
|