diff --git a/skew/arn/__init__.py b/skew/arn/__init__.py index e72136b..2e6e312 100644 --- a/skew/arn/__init__.py +++ b/skew/arn/__init__.py @@ -21,6 +21,7 @@ import skew.resources from skew.config import get_config +from skew.awsclient import SkewSessionFactory LOG = logging.getLogger(__name__) DebugFmtString = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' @@ -121,11 +122,15 @@ def enumerate(self, context, **kwargs): LOG.debug('resource_type=%s, resource_id=%s', resource_type, resource_id) resources = [] + + session_factory = SkewSessionFactory(region, account, **kwargs) + for resource_type in self.matches(context): resource_path = '.'.join([provider, service_name, resource_type]) resource_cls = skew.resources.find_resource_class(resource_path) resources.extend(resource_cls.enumerate( - self._arn, region, account, resource_id, **kwargs)) + session_factory, self._arn, resource_id)) + return resources diff --git a/skew/awsclient.py b/skew/awsclient.py index fd506bb..a14e14d 100644 --- a/skew/awsclient.py +++ b/skew/awsclient.py @@ -78,7 +78,9 @@ def _create_client(self): pill.record() elif self.placebo_mode == 'playback': pill.playback() - return session.client(self.service_name, region_name=self.region_name) + return session.client( + self.service_name, + region_name=self.region_name or 'us-east-1') def call(self, op_name, query=None, **kwargs): """ @@ -137,3 +139,14 @@ def call(self, op_name, query=None, **kwargs): def get_awsclient(service_name, region_name, account_id, **kwargs): return AWSClient(service_name, region_name, account_id, **kwargs) + + +class SkewSessionFactory(object): + + def __init__(self, region, account, **kwargs): + self.region_name = region + self.account = account + self.kwargs = kwargs + + def get_client(self, service_name): + return AWSClient(service_name, self.region_name, self.account, **self.kwargs) diff --git a/skew/resources/aws/__init__.py b/skew/resources/aws/__init__.py index 87aef41..3a34c09 100644 --- a/skew/resources/aws/__init__.py +++ b/skew/resources/aws/__init__.py @@ -88,7 +88,8 @@ class Meta(object): def filter(cls, arn, resource_id, data): pass - def __init__(self, client, data, query=None): + def __init__(self, session_factory, client, data, query=None): + self._session = session_factory self._client = client self._query = query if data is None: @@ -103,10 +104,6 @@ def __init__(self, client, data, query=None): else: self._id = '' self._cloudwatch = None - if hasattr(self.Meta, 'dimension') and self.Meta.dimension: - self._cloudwatch = skew.awsclient.get_awsclient( - 'cloudwatch', self._client.region_name, - self._client.account_id) self._metrics = None self._name = None self._date = None @@ -118,14 +115,16 @@ def __repr__(self): @property def arn(self): return 'arn:aws:%s:%s:%s:%s/%s' % ( - self._client.service_name, - self._client.region_name, - self._client.account_id, self.resourcetype, self.id) + self.Meta.service_name, + self.session.region_name, + self.session.account_id, self.resourcetype, self.id) @property def metrics(self): if self._metrics is None: - if self._cloudwatch: + if getattr(self.Meta, 'dimension', None): + if self._cloudwatch is None: + self._cloudwatch = self.session.get_client('cloudwatch') data = self._cloudwatch.call( 'list_metrics', Dimensions=[{'Name': self.Meta.dimension, diff --git a/skew/resources/aws/autoscaling.py b/skew/resources/aws/autoscaling.py index 0d84ee2..d36c456 100644 --- a/skew/resources/aws/autoscaling.py +++ b/skew/resources/aws/autoscaling.py @@ -31,8 +31,8 @@ class Meta(object): filter_name = 'AutoScalingGroupNames' filter_type = 'list' - def __init__(self, client, data, query=None): - super(AutoScalingGroup, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(AutoScalingGroup, self).__init__(session_factory, client, data, query) self._arn_query = jmespath.compile('AutoScalingGroupARN') @property @@ -55,8 +55,8 @@ class Meta(object): filter_name = 'LaunchConfigurationNames' filter_type = 'list' - def __init__(self, client, data, query=None): - super(LaunchConfiguration, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(LaunchConfiguration, self).__init__(session_factory, client, data, query) self._arn_query = jmespath.compile('LaunchConfigurationARN') @property diff --git a/skew/resources/aws/cloudformation.py b/skew/resources/aws/cloudformation.py index 782af9f..fc259b4 100644 --- a/skew/resources/aws/cloudformation.py +++ b/skew/resources/aws/cloudformation.py @@ -18,9 +18,10 @@ class Stack(AWSResource): @classmethod - def enumerate(cls, arn, region, account, resource_id=None, **kwargs): - resources = super(Stack, cls).enumerate(arn, region, account, - resource_id, **kwargs) + def enumerate(cls, session_factory, arn, resource_id=None): + resources = super(Stack, cls).enumerate( + session_factory, arn, resource_id) + for stack in resources: stack.data['Resources'] = [] for stack_resource in stack: @@ -47,15 +48,15 @@ class Meta(object): date = 'CreationTime' dimension = None - def __init__(self, client, data, query=None): - super(Stack, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Stack, self).__init__(session_factory, client, data, query) self._data = data - self._resources = [] + self._resources = None def __iter__(self): detail_op, param_name, detail_path = self.Meta.detail_spec params = {param_name: self.id} - if not self._resources: + if self._resources is None: data = self._client.call(detail_op, **params) self._resources = jmespath.search(detail_path, data) for resource in self._resources: diff --git a/skew/resources/aws/dynamodb.py b/skew/resources/aws/dynamodb.py index a719d38..c6464e8 100644 --- a/skew/resources/aws/dynamodb.py +++ b/skew/resources/aws/dynamodb.py @@ -40,8 +40,8 @@ def filter(cls, arn, resource_id, data): LOG.debug('%s == %s', resource_id, data) return resource_id == data - def __init__(self, client, data, query=None): - super(Table, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Table, self).__init__(session_factory, client, data, query) self._id = data detail_op, param_name, detail_path = self.Meta.detail_spec params = {param_name: self.id} diff --git a/skew/resources/aws/firehose.py b/skew/resources/aws/firehose.py index f498b9d..add4120 100644 --- a/skew/resources/aws/firehose.py +++ b/skew/resources/aws/firehose.py @@ -1,4 +1,4 @@ -# Licensed under the Apache License, Version 2.0 (the "License"). You +o# Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # @@ -27,8 +27,8 @@ class Meta(object): date = 'CreateTimestamp' dimension = 'DeliveryStreamName' - def __init__(self, client, data, query=None): - super(DeliveryStream, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(DeliveryStream, self).__init__(session_factory, client, data, query) self._id = data detail_op, param_name, detail_path = self.Meta.detail_spec params = {param_name: self.id} diff --git a/skew/resources/aws/kinesis.py b/skew/resources/aws/kinesis.py index 8fcc1f3..24ab6d4 100644 --- a/skew/resources/aws/kinesis.py +++ b/skew/resources/aws/kinesis.py @@ -29,7 +29,7 @@ class Meta(object): date = None dimension = 'StreamName' - def __init__(self, client, data, query=None): - super(Stream, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Stream, self).__init__(session_factory, client, data, query) self.data = {self.Meta.id: data} self._id = self.data[self.Meta.id] diff --git a/skew/resources/aws/lambda.py b/skew/resources/aws/lambda.py index 40f28fc..0116be1 100644 --- a/skew/resources/aws/lambda.py +++ b/skew/resources/aws/lambda.py @@ -23,9 +23,9 @@ class Function(AWSResource): @classmethod - def enumerate(cls, arn, region, account, resource_id=None, **kwargs): - resources = super(Function, cls).enumerate(arn, region, account, - resource_id, **kwargs) + def enumerate(cls, session_factory, arn, resource_id=None): + resources = super(Function, cls).enumerate( + session_factory, arn, resource_id) for r in resources: r.data['EventSources'] = [] kwargs = {'FunctionName': r.data['FunctionName']} diff --git a/skew/resources/aws/s3.py b/skew/resources/aws/s3.py index 7a58549..fd3ee21 100644 --- a/skew/resources/aws/s3.py +++ b/skew/resources/aws/s3.py @@ -23,13 +23,11 @@ class Bucket(AWSResource): _location_cache = {} @classmethod - def enumerate(cls, arn, region, account, resource_id=None, **kwargs): - resources = super(Bucket, cls).enumerate(arn, region, account, - resource_id, - **kwargs) + def enumerate(cls, session_factory, arn, resource_id=None): + resources = super(Bucket, cls).enumerate( + session_factory, arn, resource_id) region_resources = [] - if region is None: - region = 'us-east-1' + region = session_factory.region_name or 'us-east-1' for r in resources: location = cls._location_cache.get(r.id) if location is None: @@ -57,8 +55,8 @@ class Meta(object): date = 'CreationDate' dimension = None - def __init__(self, client, data, query=None): - super(Bucket, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Bucket, self).__init__(session_factory, client, data, query) self._data = data self._keys = [] diff --git a/skew/resources/aws/sns.py b/skew/resources/aws/sns.py index cf0c8ef..f09876d 100644 --- a/skew/resources/aws/sns.py +++ b/skew/resources/aws/sns.py @@ -42,8 +42,8 @@ def filter(cls, arn, resource_id, data): def arn(self): return self.data.get('TopicArn') - def __init__(self, client, data, query=None): - super(Topic, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Topic, self).__init__(session_factory, client, data, query) self._id = data['TopicArn'].split(':', 5)[5] @@ -76,14 +76,14 @@ def arn(self): return self.data.get('SubscriptionArn') @classmethod - def enumerate(cls, arn, region, account, resource_id=None, **kwargs): + def enumerate(cls, session_factory, arn, resource_id=None): resources = super(Subscription, cls).enumerate( - arn, region, account, resource_id, **kwargs) + session_factory, arn, resource_id) return [r for r in resources if r.id not in cls.invalid_arns] - def __init__(self, client, data, query=None): - super(Subscription, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Subscription, self).__init__(session_factory, client, data, query) if data['SubscriptionArn'] in self.invalid_arns: self._id = 'PendingConfirmation' diff --git a/skew/resources/aws/sqs.py b/skew/resources/aws/sqs.py index 9517bcb..4f6f5d9 100644 --- a/skew/resources/aws/sqs.py +++ b/skew/resources/aws/sqs.py @@ -29,8 +29,8 @@ class Meta(object): date = None dimension = 'QueueName' - def __init__(self, client, data, query=None): - super(Queue, self).__init__(client, data, query) + def __init__(self, session_factory, client, data, query=None): + super(Queue, self).__init__(session_factory, client, data, query) self.data = {self.Meta.id: data, 'QueueName': data.split('/')[-1]} self._id = self.data['QueueName'] diff --git a/skew/resources/resource.py b/skew/resources/resource.py index 92514cd..ec76dc1 100644 --- a/skew/resources/resource.py +++ b/skew/resources/resource.py @@ -24,10 +24,11 @@ class Resource(object): + flyweight = True + @classmethod - def enumerate(cls, arn, region, account, resource_id=None, **kwargs): - client = skew.awsclient.get_awsclient( - cls.Meta.service, region, account, **kwargs) + def enumerate(cls, session_factory, arn, resource_id=None): + client = session_factory.get_client(cls.Meta.service) kwargs = {} do_client_side_filtering = False if resource_id and resource_id != '*': @@ -66,7 +67,10 @@ def enumerate(cls, arn, region, account, resource_id=None, **kwargs): # resource ID we are looking for. if not cls.filter(arn, resource_id, d): continue - resources.append(cls(client, d, arn.query)) + if cls.flyweight: + resources.append(cls(session_factory, client, d, arn.query)) + else: + resources.append(d) return resources class Meta(object): @@ -77,7 +81,8 @@ class Meta(object): date = None name = None - def __init__(self, client, data): + def __init__(self, session_factory, client, data): + self._session_factory = session_factory self._client = client if data is None: data = {} diff --git a/tests/unit/test_resource.py b/tests/unit/test_resource.py index b7326f7..9c92133 100644 --- a/tests/unit/test_resource.py +++ b/tests/unit/test_resource.py @@ -47,7 +47,7 @@ def tearDown(self): def test_resource(self): client = skew.awsclient.get_awsclient( 'ec2', 'us-east-1', '123456789012') - resource = FooResource(client, data={'bar': 'bar'}) + resource = FooResource(None, client, data={'bar': 'bar'}) self.assertEqual(resource.id, 'bar') self.assertEqual(resource.__repr__(), 'arn:aws:ec2:us-east-1:123456789012:foo/bar')