Example #1
0
    def __init__(self, endpoint='localhost', port=8000):
        """
        :param endpoint: Endpoint used to connect to IPC.
        :type endpoint: str

        :param port: Port number used to connect to the :code:`endpoint`.
        :type port: int
        """
        self.ipc = IPCClient(endpoint=endpoint, port=port)
    def __init__(self, endpoint='localhost', port=None):
        """
        :param endpoint: Endpoint used to connect to IPC.
        :type endpoint: str

        :param port: Deprecated. Will not be used.
        :type port: None
        """
        self.ipc = IPCClient(endpoint=endpoint)
    def __init__(self, endpoint='localhost', port=8000):
        """
        :param endpoint: Endpoint used to connect to IPC.
        :type endpoint: str

        :param port: Port number used to connect to the :code:`endpoint`.
        :type port: int
        """
        self.ipc = IPCClient(endpoint=endpoint, port=port)
class Client:
    def __init__(self, endpoint='localhost', port=8000):
        """
        :param endpoint: Endpoint used to connect to IPC.
        :type endpoint: str

        :param port: Port number used to connect to the :code:`endpoint`.
        :type port: int
        """
        self.ipc = IPCClient(endpoint=endpoint, port=port)

    def invoke(self, **kwargs):

        # FunctionName is a required parameter
        if 'FunctionName' not in kwargs:
            raise ValueError(
                '"FunctionName" argument of Lambda.Client.invoke is a required argument but was not provided.'
            )

        arn_fields = FunctionArnFields(kwargs['FunctionName'])
        arn_qualifier = arn_fields.qualifier

        # A Function qualifier can be provided as part of the ARN in FunctionName, or it can be provided here. The
        # behavior of the cloud is to throw an exception if both are specified but not equal
        extraneous_qualifier = kwargs.get('Qualifier', '')

        if extraneous_qualifier and arn_qualifier and arn_qualifier != extraneous_qualifier:
            raise ValueError('The derived qualifier from the function name does not match the specified qualifier.')

        final_qualifier = arn_qualifier if arn_qualifier else extraneous_qualifier

        function_arn = FunctionArnFields.build_arn_string(
            arn_fields.region, arn_fields.account_id, arn_fields.name, final_qualifier
        )

        # ClientContext must be base64 if given, but is an option parameter
        try:
            client_context = kwargs.get('ClientContext', b'').decode()
        except AttributeError as e:
            customer_logger.exception(e)
            raise ValueError(
                '"ClientContext" argument must be a byte string or support a decode method which returns a string'
            )

        if client_context:
            if not re.match(valid_base64_regex, client_context):
                raise ValueError('"ClientContext" argument of Lambda.Client.invoke must be base64 encoded.')

        # Payload is an optional parameter
        payload = kwargs.get('Payload', b'')
        invocation_type = kwargs.get('InvocationType', 'RequestResponse')
        customer_logger.info('Invoking local lambda "{}" with payload "{}" and client context "{}"'.format(
            function_arn, payload, client_context))

        # Post the work to IPC and return the result of that work
        return self._invoke_internal(function_arn, payload, client_context, invocation_type)

    @mock
    def _invoke_internal(self, function_arn, payload, client_context, invocation_type="RequestResponse"):
        """
        This private method is seperate from the main, public invoke method so that other code within this SDK can
        give this Lambda client a raw payload/client context to invoke with, rather than having it built for them.
        This lets you include custom ExtensionMap_ values like subject which are needed for our internal pinned Lambdas.
        """
        customer_logger.info('Invoking Lambda function "{}" with Greengrass Message "{}"'.format(function_arn, payload))

        try:
            invocation_id = self.ipc.post_work(function_arn, payload, client_context, invocation_type)

            if invocation_type == "Event":
                # TODO: Properly return errors based on BOTO response
                # https://boto3.readthedocs.io/en/latest/reference/services/lambda.html#Lambda.Client.invoke
                return {'Payload': b'', 'FunctionError': ''}

            work_result_output = self.ipc.get_work_result(function_arn, invocation_id)
            if not work_result_output.func_err:
                output_payload = StreamingBody(work_result_output.payload)
            else:
                output_payload = work_result_output.payload
            invoke_output = {
                'Payload': output_payload,
                'FunctionError': work_result_output.func_err,
            }
            return invoke_output
        except IPCException as e:
            customer_logger.exception(e)
            raise InvocationException('Failed to invoke function due to ' + str(e))
Example #5
0
class Client:
    def __init__(self, endpoint='localhost', port=8000):
        """
        :param endpoint: Endpoint used to connect to IPC.
        :type endpoint: str

        :param port: Port number used to connect to the :code:`endpoint`.
        :type port: int
        """
        self.ipc = IPCClient(endpoint=endpoint, port=port)

    def invoke(self, **kwargs):

        # FunctionName is a required parameter
        if 'FunctionName' not in kwargs:
            raise ValueError(
                '"FunctionName" argument of Lambda.Client.invoke is a required argument but was not provided.'
            )

        arn_fields = FunctionArnFields(kwargs['FunctionName'])
        arn_qualifier = arn_fields.qualifier

        # A Function qualifier can be provided as part of the ARN in FunctionName, or it can be provided here. The
        # behavior of the cloud is to throw an exception if both are specified but not equal
        extraneous_qualifier = kwargs.get('Qualifier', '')

        if extraneous_qualifier and arn_qualifier and arn_qualifier != extraneous_qualifier:
            raise ValueError(
                'The derived qualifier from the function name does not match the specified qualifier.'
            )

        final_qualifier = arn_qualifier if arn_qualifier else extraneous_qualifier

        function_arn = FunctionArnFields.build_arn_string(
            arn_fields.region, arn_fields.account_id, arn_fields.name,
            final_qualifier)

        # ClientContext must be base64 if given, but is an option parameter
        try:
            client_context = kwargs.get('ClientContext', b'').decode()
        except AttributeError as e:
            customer_logger.exception(e)
            raise ValueError(
                '"ClientContext" argument must be a byte string or support a decode method which returns a string'
            )

        if client_context:
            if not re.match(valid_base64_regex, client_context):
                raise ValueError(
                    '"ClientContext" argument of Lambda.Client.invoke must be base64 encoded.'
                )

        # Payload is an optional parameter
        payload = kwargs.get('Payload', b'')
        invocation_type = kwargs.get('InvocationType', 'RequestResponse')
        customer_logger.debug(
            'Invoking local lambda "{}" with payload "{}" and client context "{}"'
            .format(function_arn, payload, client_context))

        # Post the work to IPC and return the result of that work
        return self._invoke_internal(function_arn, payload, client_context,
                                     invocation_type)

    @mock
    def _invoke_internal(self,
                         function_arn,
                         payload,
                         client_context,
                         invocation_type="RequestResponse"):
        """
        This private method is seperate from the main, public invoke method so that other code within this SDK can
        give this Lambda client a raw payload/client context to invoke with, rather than having it built for them.
        This lets you include custom ExtensionMap_ values like subject which are needed for our internal pinned Lambdas.
        """
        customer_logger.debug(
            'Invoking Lambda function "{}" with Greengrass Message "{}"'.
            format(function_arn, payload))

        try:
            invocation_id = self.ipc.post_work(function_arn, payload,
                                               client_context, invocation_type)

            if invocation_type == "Event":
                # TODO: Properly return errors based on BOTO response
                # https://boto3.readthedocs.io/en/latest/reference/services/lambda.html#Lambda.Client.invoke
                return {'Payload': b'', 'FunctionError': ''}

            work_result_output = self.ipc.get_work_result(
                function_arn, invocation_id)
            if not work_result_output.func_err:
                output_payload = StreamingBody(work_result_output.payload)
            else:
                output_payload = work_result_output.payload
            invoke_output = {
                'Payload': output_payload,
                'FunctionError': work_result_output.func_err,
            }
            return invoke_output
        except IPCException as e:
            customer_logger.exception(e)
            raise InvocationException('Failed to invoke function due to ' +
                                      str(e))
class Client:
    def __init__(self, endpoint='localhost', port=None):
        """
        :param endpoint: Endpoint used to connect to IPC.
        :type endpoint: str

        :param port: Deprecated. Will not be used.
        :type port: None
        """
        self.ipc = IPCClient(endpoint=endpoint)

    def invoke(self, **kwargs):
        r"""
        Invokes Lambda function of the given name.

        :Keyword Arguments:
            * *ClientContext* (``bytes``) --
              Optional Base64-encoded data about the invoking client to pass to the Lambda function
            * *FunctionName* (``string``) --
              [REQUIRED]
              The Amazon Resource Name (ARN) of the Lambda function to invoke. Name formats:

              * Qualified ARN - The function ARN with the version suffix. e.g. arn:aws:lambda:aws-region:acct-id:function:helloworld:1
              * Unqualified ARN - The function ARN without the version suffix. e.g. arn:aws:lambda:aws-region:acct-id:function:helloworld
            * *InvocationType* (``string``) --
              Choose from the following options.

              * ``RequestResponse`` (default) - Invoke the Lambda synchronously. Block until the function returns a response or times out.
              * ``Event`` - Invoke the Lambda asynchronously. The response only includes empty payload.
            * *Payload* (``bytes``) --
              Optional input for the Lambda function to invoke.
            * *Qualifier* (``string``) --
              Optional parameter to specify a Lambda function version if it was not included in the FunctionName field.
              If you specify a function version, the API uses the qualified function ARN to invoke a specific Lambda function.
        :returns: (``dict``) --
            * *FunctionError* (``string``) --
              If present, indicates that an error occurred while executing the Lambda function. If an error occurred,
              this field will have one of two values, ``Handled`` or ``Unhandled``. ``Handled`` errors are errors that are reported by the function
              while the ``Unhandled`` errors are those detected and reported by Greengrass Core.
              ``Unhandled`` errors include out of memory errors and function timeouts. Error details are provided in the Payload.
            * *Payload* (``bytes or StreamingBody object``) --
              It is the result returned by the Lambda function. This is present only if the invocation type is ``RequestResponse``.
              In the event of a function error this field contains a message describing the error.
        """

        # FunctionName is a required parameter
        if 'FunctionName' not in kwargs:
            raise ValueError(
                '"FunctionName" argument of Lambda.Client.invoke is a required argument but was not provided.'
            )

        arn_fields = FunctionArnFields(kwargs['FunctionName'])
        arn_qualifier = arn_fields.qualifier

        # A Function qualifier can be provided as part of the ARN in FunctionName, or it can be provided here. The
        # behavior of the cloud is to throw an exception if both are specified but not equal
        extraneous_qualifier = kwargs.get('Qualifier', '')

        if extraneous_qualifier and arn_qualifier and arn_qualifier != extraneous_qualifier:
            raise ValueError(
                'The derived qualifier from the function name does not match the specified qualifier.'
            )

        final_qualifier = arn_qualifier if arn_qualifier else extraneous_qualifier

        try:
            # GGC v1.9.0 or newer
            function_arn = FunctionArnFields.build_function_arn(
                arn_fields.unqualified_arn, final_qualifier)
        except AttributeError:
            # older GGC version
            raise AttributeError(
                'class FunctionArnFields has no attribute \'build_function_arn\'. build_function_arn '
                'is introduced in GGC v1.9.0. Please check your GGC version.')

        # ClientContext must be base64 if given, but is an option parameter
        try:
            client_context = kwargs.get('ClientContext', b'').decode()
        except AttributeError as e:
            customer_logger.exception(e)
            raise ValueError(
                '"ClientContext" argument must be a byte string or support a decode method which returns a string'
            )

        if client_context:
            if not re.match(valid_base64_regex, client_context):
                raise ValueError(
                    '"ClientContext" argument of Lambda.Client.invoke must be base64 encoded.'
                )

        # Payload is an optional parameter
        payload = kwargs.get('Payload', b'')
        invocation_type = kwargs.get('InvocationType', 'RequestResponse')
        customer_logger.debug(
            'Invoking local lambda "{}" with payload "{}" and client context "{}"'
            .format(function_arn, payload, client_context))

        # Post the work to IPC and return the result of that work
        return self._invoke_internal(function_arn, payload, client_context,
                                     invocation_type)

    @mock
    def _invoke_internal(self,
                         function_arn,
                         payload,
                         client_context,
                         invocation_type="RequestResponse"):
        """
        This private method is seperate from the main, public invoke method so that other code within this SDK can
        give this Lambda client a raw payload/client context to invoke with, rather than having it built for them.
        This lets you include custom ExtensionMap_ values like subject which are needed for our internal pinned Lambdas.
        """
        customer_logger.debug(
            'Invoking Lambda function "{}" with Greengrass Message "{}"'.
            format(function_arn, payload))

        try:
            invocation_id = self.ipc.post_work(function_arn, payload,
                                               client_context, invocation_type)

            if invocation_type == "Event":
                # TODO: Properly return errors based on BOTO response
                # https://boto3.readthedocs.io/en/latest/reference/services/lambda.html#Lambda.Client.invoke
                return {'Payload': b'', 'FunctionError': ''}

            work_result_output = self.ipc.get_work_result(
                function_arn, invocation_id)
            if not work_result_output.func_err:
                output_payload = StreamingBody(work_result_output.payload)
            else:
                output_payload = work_result_output.payload
            invoke_output = {
                'Payload': output_payload,
                'FunctionError': work_result_output.func_err,
            }
            return invoke_output
        except IPCException as e:
            customer_logger.exception(e)
            raise InvocationException('Failed to invoke function due to ' +
                                      str(e))