• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2015 Amazon.com, Inc. or its affiliates.  All Rights Reserved
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the
5# "Software"), to deal in the Software without restriction, including
6# without limitation the rights to use, copy, modify, merge, publish, dis-
7# tribute, sublicense, and/or sell copies of the Software, and to permit
8# persons to whom the Software is furnished to do so, subject to the fol-
9# lowing conditions:
10#
11# The above copyright notice and this permission notice shall be included
12# in all copies or substantial portions of the Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20# IN THE SOFTWARE.
21#
22import os
23
24from boto.compat import json
25from boto.exception import JSONResponseError
26from boto.connection import AWSAuthConnection
27from boto.regioninfo import RegionInfo
28from boto.awslambda import exceptions
29
30
31class AWSLambdaConnection(AWSAuthConnection):
32    """
33    AWS Lambda
34    **Overview**
35
36    This is the AWS Lambda API Reference. The AWS Lambda Developer
37    Guide provides additional information. For the service overview,
38    go to `What is AWS Lambda`_, and for information about how the
39    service works, go to `AWS LambdaL How it Works`_ in the AWS Lambda
40    Developer Guide.
41    """
42    APIVersion = "2014-11-11"
43    DefaultRegionName = "us-east-1"
44    DefaultRegionEndpoint = "lambda.us-east-1.amazonaws.com"
45    ResponseError = JSONResponseError
46
47    _faults = {
48        "InvalidRequestContentException": exceptions.InvalidRequestContentException,
49        "ResourceNotFoundException": exceptions.ResourceNotFoundException,
50        "InvalidParameterValueException": exceptions.InvalidParameterValueException,
51        "ServiceException": exceptions.ServiceException,
52    }
53
54
55    def __init__(self, **kwargs):
56        region = kwargs.get('region')
57        if not region:
58            region = RegionInfo(self, self.DefaultRegionName,
59                                self.DefaultRegionEndpoint)
60        else:
61            del kwargs['region']
62        kwargs['host'] = region.endpoint
63        super(AWSLambdaConnection, self).__init__(**kwargs)
64        self.region = region
65
66    def _required_auth_capability(self):
67        return ['hmac-v4']
68
69    def add_event_source(self, event_source, function_name, role,
70                         batch_size=None, parameters=None):
71        """
72        Identifies an Amazon Kinesis stream as the event source for an
73        AWS Lambda function. AWS Lambda invokes the specified function
74        when records are posted to the stream.
75
76        This is the pull model, where AWS Lambda invokes the function.
77        For more information, go to `AWS LambdaL How it Works`_ in the
78        AWS Lambda Developer Guide.
79
80        This association between an Amazon Kinesis stream and an AWS
81        Lambda function is called the event source mapping. You
82        provide the configuration information (for example, which
83        stream to read from and which AWS Lambda function to invoke)
84        for the event source mapping in the request body.
85
86        This operation requires permission for the `iam:PassRole`
87        action for the IAM role. It also requires permission for the
88        `lambda:AddEventSource` action.
89
90        :type event_source: string
91        :param event_source: The Amazon Resource Name (ARN) of the Amazon
92            Kinesis stream that is the event source. Any record added to this
93            stream causes AWS Lambda to invoke your Lambda function. AWS Lambda
94            POSTs the Amazon Kinesis event, containing records, to your Lambda
95            function as JSON.
96
97        :type function_name: string
98        :param function_name: The Lambda function to invoke when AWS Lambda
99            detects an event on the stream.
100
101        :type role: string
102        :param role: The ARN of the IAM role (invocation role) that AWS Lambda
103            can assume to read from the stream and invoke the function.
104
105        :type batch_size: integer
106        :param batch_size: The largest number of records that AWS Lambda will
107            give to your function in a single event. The default is 100
108            records.
109
110        :type parameters: map
111        :param parameters: A map (key-value pairs) defining the configuration
112            for AWS Lambda to use when reading the event source. Currently, AWS
113            Lambda supports only the `InitialPositionInStream` key. The valid
114            values are: "TRIM_HORIZON" and "LATEST". The default value is
115            "TRIM_HORIZON". For more information, go to `ShardIteratorType`_ in
116            the Amazon Kinesis Service API Reference.
117
118        """
119
120        uri = '/2014-11-13/event-source-mappings/'
121        params = {
122            'EventSource': event_source,
123            'FunctionName': function_name,
124            'Role': role,
125        }
126        headers = {}
127        query_params = {}
128        if batch_size is not None:
129            params['BatchSize'] = batch_size
130        if parameters is not None:
131            params['Parameters'] = parameters
132        return self.make_request('POST', uri, expected_status=200,
133                                 data=json.dumps(params), headers=headers,
134                                 params=query_params)
135
136    def delete_function(self, function_name):
137        """
138        Deletes the specified Lambda function code and configuration.
139
140        This operation requires permission for the
141        `lambda:DeleteFunction` action.
142
143        :type function_name: string
144        :param function_name: The Lambda function to delete.
145
146        """
147
148        uri = '/2014-11-13/functions/{0}'.format(function_name)
149        return self.make_request('DELETE', uri, expected_status=204)
150
151    def get_event_source(self, uuid):
152        """
153        Returns configuration information for the specified event
154        source mapping (see AddEventSource).
155
156        This operation requires permission for the
157        `lambda:GetEventSource` action.
158
159        :type uuid: string
160        :param uuid: The AWS Lambda assigned ID of the event source mapping.
161
162        """
163
164        uri = '/2014-11-13/event-source-mappings/{0}'.format(uuid)
165        return self.make_request('GET', uri, expected_status=200)
166
167    def get_function(self, function_name):
168        """
169        Returns the configuration information of the Lambda function
170        and a presigned URL link to the .zip file you uploaded with
171        UploadFunction so you can download the .zip file. Note that
172        the URL is valid for up to 10 minutes. The configuration
173        information is the same information you provided as parameters
174        when uploading the function.
175
176        This operation requires permission for the
177        `lambda:GetFunction` action.
178
179        :type function_name: string
180        :param function_name: The Lambda function name.
181
182        """
183
184        uri = '/2014-11-13/functions/{0}'.format(function_name)
185        return self.make_request('GET', uri, expected_status=200)
186
187    def get_function_configuration(self, function_name):
188        """
189        Returns the configuration information of the Lambda function.
190        This the same information you provided as parameters when
191        uploading the function by using UploadFunction.
192
193        This operation requires permission for the
194        `lambda:GetFunctionConfiguration` operation.
195
196        :type function_name: string
197        :param function_name: The name of the Lambda function for which you
198            want to retrieve the configuration information.
199
200        """
201
202        uri = '/2014-11-13/functions/{0}/configuration'.format(function_name)
203        return self.make_request('GET', uri, expected_status=200)
204
205    def invoke_async(self, function_name, invoke_args):
206        """
207        Submits an invocation request to AWS Lambda. Upon receiving
208        the request, Lambda executes the specified function
209        asynchronously. To see the logs generated by the Lambda
210        function execution, see the CloudWatch logs console.
211
212        This operation requires permission for the
213        `lambda:InvokeAsync` action.
214
215        :type function_name: string
216        :param function_name: The Lambda function name.
217
218        :type invoke_args: blob
219        :param invoke_args: JSON that you want to provide to your Lambda
220            function as input.
221
222        """
223        uri = '/2014-11-13/functions/{0}/invoke-async/'.format(function_name)
224        headers = {}
225        query_params = {}
226        try:
227            content_length = str(len(invoke_args))
228        except (TypeError, AttributeError):
229            # If a file like object is provided and seekable, try to retrieve
230            # the file size via fstat.
231            try:
232                invoke_args.tell()
233            except (AttributeError, OSError, IOError):
234                raise TypeError(
235                    "File-like object passed to parameter "
236                    "``invoke_args`` must be seekable."
237                )
238            content_length = str(os.fstat(invoke_args.fileno()).st_size)
239        headers['Content-Length'] = content_length
240        return self.make_request('POST', uri, expected_status=202,
241                                 data=invoke_args, headers=headers,
242                                 params=query_params)
243
244    def list_event_sources(self, event_source_arn=None, function_name=None,
245                           marker=None, max_items=None):
246        """
247        Returns a list of event source mappings. For each mapping, the
248        API returns configuration information (see AddEventSource).
249        You can optionally specify filters to retrieve specific event
250        source mappings.
251
252        This operation requires permission for the
253        `lambda:ListEventSources` action.
254
255        :type event_source_arn: string
256        :param event_source_arn: The Amazon Resource Name (ARN) of the Amazon
257            Kinesis stream.
258
259        :type function_name: string
260        :param function_name: The name of the AWS Lambda function.
261
262        :type marker: string
263        :param marker: Optional string. An opaque pagination token returned
264            from a previous `ListEventSources` operation. If present, specifies
265            to continue the list from where the returning call left off.
266
267        :type max_items: integer
268        :param max_items: Optional integer. Specifies the maximum number of
269            event sources to return in response. This value must be greater
270            than 0.
271
272        """
273
274        uri = '/2014-11-13/event-source-mappings/'
275        params = {}
276        headers = {}
277        query_params = {}
278        if event_source_arn is not None:
279            query_params['EventSource'] = event_source_arn
280        if function_name is not None:
281            query_params['FunctionName'] = function_name
282        if marker is not None:
283            query_params['Marker'] = marker
284        if max_items is not None:
285            query_params['MaxItems'] = max_items
286        return self.make_request('GET', uri, expected_status=200,
287                                 data=json.dumps(params), headers=headers,
288                                 params=query_params)
289
290    def list_functions(self, marker=None, max_items=None):
291        """
292        Returns a list of your Lambda functions. For each function,
293        the response includes the function configuration information.
294        You must use GetFunction to retrieve the code for your
295        function.
296
297        This operation requires permission for the
298        `lambda:ListFunctions` action.
299
300        :type marker: string
301        :param marker: Optional string. An opaque pagination token returned
302            from a previous `ListFunctions` operation. If present, indicates
303            where to continue the listing.
304
305        :type max_items: integer
306        :param max_items: Optional integer. Specifies the maximum number of AWS
307            Lambda functions to return in response. This parameter value must
308            be greater than 0.
309
310        """
311
312        uri = '/2014-11-13/functions/'
313        params = {}
314        headers = {}
315        query_params = {}
316        if marker is not None:
317            query_params['Marker'] = marker
318        if max_items is not None:
319            query_params['MaxItems'] = max_items
320        return self.make_request('GET', uri, expected_status=200,
321                                 data=json.dumps(params), headers=headers,
322                                 params=query_params)
323
324    def remove_event_source(self, uuid):
325        """
326        Removes an event source mapping. This means AWS Lambda will no
327        longer invoke the function for events in the associated
328        source.
329
330        This operation requires permission for the
331        `lambda:RemoveEventSource` action.
332
333        :type uuid: string
334        :param uuid: The event source mapping ID.
335
336        """
337
338        uri = '/2014-11-13/event-source-mappings/{0}'.format(uuid)
339        return self.make_request('DELETE', uri, expected_status=204)
340
341    def update_function_configuration(self, function_name, role=None,
342                                      handler=None, description=None,
343                                      timeout=None, memory_size=None):
344        """
345        Updates the configuration parameters for the specified Lambda
346        function by using the values provided in the request. You
347        provide only the parameters you want to change. This operation
348        must only be used on an existing Lambda function and cannot be
349        used to update the function's code.
350
351        This operation requires permission for the
352        `lambda:UpdateFunctionConfiguration` action.
353
354        :type function_name: string
355        :param function_name: The name of the Lambda function.
356
357        :type role: string
358        :param role: The Amazon Resource Name (ARN) of the IAM role that Lambda
359            will assume when it executes your function.
360
361        :type handler: string
362        :param handler: The function that Lambda calls to begin executing your
363            function. For Node.js, it is the module-name.export value in your
364            function.
365
366        :type description: string
367        :param description: A short user-defined function description. Lambda
368            does not use this value. Assign a meaningful description as you see
369            fit.
370
371        :type timeout: integer
372        :param timeout: The function execution time at which Lambda should
373            terminate the function. Because the execution time has cost
374            implications, we recommend you set this value based on your
375            expected execution time. The default is 3 seconds.
376
377        :type memory_size: integer
378        :param memory_size: The amount of memory, in MB, your Lambda function
379            is given. Lambda uses this memory size to infer the amount of CPU
380            allocated to your function. Your function use-case determines your
381            CPU and memory requirements. For example, a database operation
382            might need less memory compared to an image processing function.
383            The default value is 128 MB. The value must be a multiple of 64 MB.
384
385        """
386
387        uri = '/2014-11-13/functions/{0}/configuration'.format(function_name)
388        params = {}
389        headers = {}
390        query_params = {}
391        if role is not None:
392            query_params['Role'] = role
393        if handler is not None:
394            query_params['Handler'] = handler
395        if description is not None:
396            query_params['Description'] = description
397        if timeout is not None:
398            query_params['Timeout'] = timeout
399        if memory_size is not None:
400            query_params['MemorySize'] = memory_size
401        return self.make_request('PUT', uri, expected_status=200,
402                                 data=json.dumps(params), headers=headers,
403                                 params=query_params)
404
405    def upload_function(self, function_name, function_zip, runtime, role,
406                        handler, mode, description=None, timeout=None,
407                        memory_size=None):
408        """
409        Creates a new Lambda function or updates an existing function.
410        The function metadata is created from the request parameters,
411        and the code for the function is provided by a .zip file in
412        the request body. If the function name already exists, the
413        existing Lambda function is updated with the new code and
414        metadata.
415
416        This operation requires permission for the
417        `lambda:UploadFunction` action.
418
419        :type function_name: string
420        :param function_name: The name you want to assign to the function you
421            are uploading. The function names appear in the console and are
422            returned in the ListFunctions API. Function names are used to
423            specify functions to other AWS Lambda APIs, such as InvokeAsync.
424
425        :type function_zip: blob
426        :param function_zip: A .zip file containing your packaged source code.
427            For more information about creating a .zip file, go to `AWS LambdaL
428            How it Works`_ in the AWS Lambda Developer Guide.
429
430        :type runtime: string
431        :param runtime: The runtime environment for the Lambda function you are
432            uploading. Currently, Lambda supports only "nodejs" as the runtime.
433
434        :type role: string
435        :param role: The Amazon Resource Name (ARN) of the IAM role that Lambda
436            assumes when it executes your function to access any other Amazon
437            Web Services (AWS) resources.
438
439        :type handler: string
440        :param handler: The function that Lambda calls to begin execution. For
441            Node.js, it is the module-name . export value in your function.
442
443        :type mode: string
444        :param mode: How the Lambda function will be invoked. Lambda supports
445            only the "event" mode.
446
447        :type description: string
448        :param description: A short, user-defined function description. Lambda
449            does not use this value. Assign a meaningful description as you see
450            fit.
451
452        :type timeout: integer
453        :param timeout: The function execution time at which Lambda should
454            terminate the function. Because the execution time has cost
455            implications, we recommend you set this value based on your
456            expected execution time. The default is 3 seconds.
457
458        :type memory_size: integer
459        :param memory_size: The amount of memory, in MB, your Lambda function
460            is given. Lambda uses this memory size to infer the amount of CPU
461            allocated to your function. Your function use-case determines your
462            CPU and memory requirements. For example, database operation might
463            need less memory compared to image processing function. The default
464            value is 128 MB. The value must be a multiple of 64 MB.
465
466        """
467        uri = '/2014-11-13/functions/{0}'.format(function_name)
468        headers = {}
469        query_params = {}
470        if runtime is not None:
471            query_params['Runtime'] = runtime
472        if role is not None:
473            query_params['Role'] = role
474        if handler is not None:
475            query_params['Handler'] = handler
476        if mode is not None:
477            query_params['Mode'] = mode
478        if description is not None:
479            query_params['Description'] = description
480        if timeout is not None:
481            query_params['Timeout'] = timeout
482        if memory_size is not None:
483            query_params['MemorySize'] = memory_size
484
485        try:
486            content_length = str(len(function_zip))
487        except (TypeError, AttributeError):
488            # If a file like object is provided and seekable, try to retrieve
489            # the file size via fstat.
490            try:
491                function_zip.tell()
492            except (AttributeError, OSError, IOError):
493                raise TypeError(
494                    "File-like object passed to parameter "
495                    "``function_zip`` must be seekable."
496                )
497            content_length = str(os.fstat(function_zip.fileno()).st_size)
498        headers['Content-Length'] = content_length
499        return self.make_request('PUT', uri, expected_status=201,
500                                 data=function_zip, headers=headers,
501                                 params=query_params)
502
503    def make_request(self, verb, resource, headers=None, data='',
504                     expected_status=None, params=None):
505        if headers is None:
506            headers = {}
507        response = AWSAuthConnection.make_request(
508            self, verb, resource, headers=headers, data=data, params=params)
509        body = response.read().decode('utf-8')
510        if body:
511            body = json.loads(body)
512        if response.status == expected_status:
513            return body
514        else:
515            error_type = response.getheader('x-amzn-ErrorType').split(':')[0]
516            error_class = self._faults.get(error_type, self.ResponseError)
517            raise error_class(response.status, response.reason, body)
518