Exemplo n.º 1
0
    def _evaluate_interval(self):
        """Get the interval at which this function is executing. This translates
        an AWS Rate Schedule Expression ('rate(2 hours)') into a second interval
        """
        rate_match = AWS_RATE_RE.match(self._schedule)

        if not rate_match:
            raise AppConfigError('Invalid \'rate\' interval value: '
                                 '{}'.format(self._schedule))

        value = rate_match.group(2) or rate_match.group(4)
        unit = rate_match.group(3) or rate_match.group(5).replace('s', '')

        translate_to_seconds = {
            'minute': 60,
            'hour': 60 * 60,
            'day': 60 * 60 * 24
        }

        interval = int(value) * translate_to_seconds[unit]

        LOGGER.debug('Evaluated rate interval: %d seconds', interval)

        # Get the total seconds that this rate evaluates to
        return interval
Exemplo n.º 2
0
    def _get_parameters(cls, *names):
        """Simple helper function to house the boto3 ssm client get_parameters operations

        Args:
            names (list): A list of parameter names to retrieve from the aws ssm
                parameter store

        Returns:
            tuple (dict, list): Dictionary with the load parameter names as keys
                and the actual parameter (as a dictionary) as the value. The seconary
                list that is returned contains any invalid parameters that were not loaded
        """
        # Create the ssm boto3 client that will be cached and used throughout this execution
        # if one does not exist already
        if AppConfig.SSM_CLIENT is None:
            boto_config = client.Config(connect_timeout=cls.BOTO_TIMEOUT,
                                        read_timeout=cls.BOTO_TIMEOUT)
            AppConfig.SSM_CLIENT = boto3.client('ssm', config=boto_config)

        LOGGER.debug('Retrieving values from parameter store with names: %s',
                     ', '.join('\'{}\''.format(name) for name in names))
        try:
            parameters = AppConfig.SSM_CLIENT.get_parameters(
                Names=list(names), WithDecryption=True)
        except ClientError as err:
            joined_names = ', '.join('\'{}\''.format(name) for name in names)
            raise AppConfigError(
                'Could not get parameter with names {}. Error: '
                '{}'.format(joined_names, err.response['Error']['Message']))

        decoded_params = {}
        for param in parameters['Parameters']:
            try:
                decoded_params[param['Name']] = json.loads(param['Value'])
            except ValueError:
                raise AppConfigError(
                    'Could not load value for parameter with '
                    'name \'{}\'. The value is not valid json: '
                    '\'{}\''.format(param['Name'], param['Value']))

        return decoded_params, parameters['InvalidParameters']
Exemplo n.º 3
0
    def _validate_event(cls, event):
        """Validate the top level of the config to make sure it has all the right keys

        Raises:
            AppConfigError: If the config is invalid, this exception is raised
        """
        event_key_diff = cls.required_event_keys().difference(set(event))
        if not event_key_diff:
            return

        missing_event_keys = ', '.join('\'{}\''.format(key)
                                       for key in event_key_diff)
        raise AppConfigError('App event is missing the following required '
                             'keys: {}'.format(missing_event_keys))
Exemplo n.º 4
0
    def load_config(cls, event, context):
        """Load the configuration for this app invocation

        Args:
            event (dict): The AWS Lambda input event, which is JSON serialized to a dictionary
            context (LambdaContext): The AWS LambdaContext object, passed in via the handler.

        Returns:
            AppConfig: Configuration for the running application
        """
        # Patch out the protected _remaining_ms method to the AWS timing function
        AppConfig.remaining_ms = context.get_remaining_time_in_millis
        func_name = context.function_name
        func_version = context.function_version

        # Get full parameter names for authentication and state parameters
        auth_param_name = '_'.join([func_name, cls.AUTH_CONFIG_SUFFIX])
        state_param_name = '_'.join([func_name, cls.STATE_CONFIG_SUFFIX])

        # Get the loaded parameters and a list of any invalid ones from parameter store
        params, invalid_params = cls._get_parameters(auth_param_name,
                                                     state_param_name)

        # Check to see if the authentication param is in the invalid params list
        if auth_param_name in invalid_params:
            raise AppConfigError(
                'Could not load authentication parameter required for this '
                'app: {}'.format(auth_param_name))

        LOGGER.debug('Retrieved parameters from parameter store: %s',
                     cls._scrub_auth_info(params, auth_param_name))
        LOGGER.debug(
            'Invalid parameters could not be retrieved from parameter store: %s',
            invalid_params)

        # Load the authentication info. This data can vary from service to service
        auth_config = {
            key: value.encode('utf-8') if isinstance(value, unicode) else value
            for key, value in params[auth_param_name].iteritems()
        }
        state_config = params.get(state_param_name, {})

        return AppConfig(auth_config, state_config, event, func_name,
                         func_version)