def get_time(self, config_id, ds):
        key = self._key(config_id, ds)
        cycletime = (ds.cycletime / 60) * 60

        # never collect older than 30 minutes ago.
        min_timestamp = iso8601(seconds_ago=30*60)

        timestamp = self._track.get(key)

        if timestamp is None:
            # start with cycletime * 4 ago
            return iso8601(seconds_ago=cycletime * 4)

        if timestamp_from_cloudwatch(timestamp) < timestamp_from_cloudwatch(min_timestamp):
            return min_timestamp
        else:
            return timestamp
    def collect(self, config):
        ds0 = config.datasources[0]
        log.debug("Collect for AmazonCloudWatch (%d)" % ds0.zAWSCloudWatchMaxParallel)

        results = []

        if not config.datasources[0].component:
            log.warn("Amazon CloudWatch data source type "
                     "not suitable to use on device level")
            defer.returnValue(results)
            return

        # Static for performance collection
        httpVerb = 'GET'
        uriRequest = '/'

        baseRequest = {}
        baseRequest['SignatureMethod'] = 'HmacSHA256'
        baseRequest['SignatureVersion'] = '2'

        deferreds = []

        for ds in config.datasources:
            # CloudWatch only accepts periods that are evenly divisible by 60.
            cycletime = (ds.cycletime / 60) * 60

            hostHeader = lookup_cwregion(ds.params['region'])

            monitorRequest = baseRequest.copy()
            monitorRequest['Action'] = 'GetMetricStatistics'
            monitorRequest['Version'] = '2010-08-01'
            monitorRequest['Period'] = cycletime
            monitorRequest['StartTime'] = self.lastsuccess.get_time(config.id, ds)
            monitorRequest['EndTime'] = iso8601()
            monitorRequest['Namespace'] = ds.params['namespace']
            monitorRequest['MetricName'] = ds.params['metric']
            monitorRequest['Statistics.member.1'] = ds.params['statistic']

            if ds.params['dimension']:
                dim_group = ds.params['dimension'].split(';')

                i = 0
                for dim_name, dim_value in [x.split('=') for x in dim_group]:
                    i += 1
                    monitorRequest['Dimensions.member.%d.Name' % i] = dim_name
                    monitorRequest['Dimensions.member.%d.Value' % i] = dim_value

            getURL = awsUrlSign(
                httpVerb,
                hostHeader,
                uriRequest,
                monitorRequest,
                (ds.ec2accesskey, ds.ec2secretkey))

            getURL = '{0}://{1}'.format(
                ('https' if ds.zAWSCloudWatchSSL else 'http'), getURL
            )

            log.debug(
                "doQuery [%s] StartTime=%s, EndTime=%s",
                self.ds_description(config, ds),
                monitorRequest['StartTime'],
                monitorRequest['EndTime'])

            d = self.doQuery(config, getURL, ds, monitorRequest['StartTime'])
            deferreds.append(d)

        # allow all the requests to complete.
        results = yield defer.DeferredList(deferreds, consumeErrors=True)

        # and return their results
        defer.returnValue([x[1] for x in results])
    def collect(self, config):
        log.debug("Collect for AWS")
        results = []

        ds0 = config.datasources[0]
        accesskey = ds0.ec2accesskey
        secretkey = ds0.ec2secretkey

        # CloudWatch only accepts periods that are evenly divisible by 60.
        cycletime = (ds0.cycletime / 60) * 60

        # Static for performance collection
        httpVerb = 'GET'
        uriRequest = '/'

        baseRequest = {}
        baseRequest['SignatureMethod'] = 'HmacSHA256'
        baseRequest['SignatureVersion'] = '2'

        def sleep(secs):
            d = defer.Deferred()
            reactor.callLater(secs, d.callback, None)
            return d

        for ds in config.datasources:
            hostHeader = lookup_cwregion(ds.params['region'])

            monitorRequest = baseRequest.copy()
            monitorRequest['Action'] = 'GetMetricStatistics'
            monitorRequest['Version'] = '2010-08-01'
            monitorRequest['Period'] = cycletime
            monitorRequest['StartTime'] = iso8601(seconds_ago=(cycletime * 2))
            monitorRequest['EndTime'] = iso8601()
            monitorRequest['Namespace'] = ds.params['namespace']
            monitorRequest['MetricName'] = ds.params['metric']
            monitorRequest['Statistics.member.1'] = ds.params['statistic']

            if ds.params['dimension']:
                dim_name, dim_value = ds.params['dimension'].split('=')

                monitorRequest['Dimensions.member.1.Name'] = dim_name
                monitorRequest['Dimensions.member.1.Value'] = dim_value

            getURL = awsUrlSign(
                httpVerb,
                hostHeader,
                uriRequest,
                monitorRequest,
                (accesskey, secretkey))

            getURL = 'http://%s' % getURL

            # Incremental backoff as outlined by AWS.
            # http://aws.amazon.com/articles/1394
            for retry in xrange(MAX_RETRIES + 1):
                if retry > 0:
                    delay = (random.random() * pow(4, retry)) / 10.0
                    log.debug(
                        '%s (%s): retry %s backoff is %s seconds',
                        config.id, ds.params['region'], retry, delay)

                    wait = yield sleep(delay)

                try:
                    log.debug(
                        '%s (%s): requesting %s %s/%s for %s',
                        config.id,
                        ds.params['region'],
                        ds.params['statistic'],
                        ds.params['namespace'],
                        ds.params['metric'],
                        ds.params['dimension'] or 'region')

                    result = yield getPage(getURL)

                except Exception, ex:
                    code = getattr(ex, 'status', None)
                    if code in ('500', '503'):
                        continue

                    raise

                else:
                    results.append((ds, result))
                    break

            if ds.params['metric'] == 'VolumeTotalWriteTime':
                # Get Volume Status
                volumeRequest = baseRequest.copy()
                volumeRequest['Action'] = 'DescribeVolumeStatus'
                volumeRequest['Version'] = '2013-02-01'
                volumeRequest['VolumeId.1'] = dim_value
                hostHeader = 'ec2.amazonaws.com'

                getURL = awsUrlSign(
                        httpVerb,
                        hostHeader,
                        uriRequest,
                        volumeRequest,
                        [accesskey, secretkey])

                getURL = 'http://%s' % getURL

                log.debug('Get Volume Information: %s', getURL)

                result = yield getPage(getURL)
                results.append(('volumestatus', result))