Skip to content

Commit ca328df

Browse files
committed
feat: add new lambda for collections
1 parent 630bed5 commit ca328df

File tree

10 files changed

+251
-20
lines changed

10 files changed

+251
-20
lines changed

cumulus_lambda_functions/cumulus_collections_dapa/__init__.py

Whitespace-only changes.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import os
2+
3+
from cumulus_lambda_functions.cumulus_wrapper.query_collections import CollectionsQuery
4+
from cumulus_lambda_functions.lib.lambda_logger_generator import LambdaLoggerGenerator
5+
6+
LOGGER = LambdaLoggerGenerator.get_logger(__name__, LambdaLoggerGenerator.get_level_from_env())
7+
8+
9+
class CumulusCollectionsDapa:
10+
def __init__(self, event):
11+
LOGGER.info(f'event: {event}')
12+
self.__event = event
13+
self.__jwt_token = 'NA'
14+
self.__limit = 10
15+
self.__offset = 0
16+
self.__page_number = (self.__offset // self.__limit) + 1
17+
if 'CUMULUS_BASE' not in os.environ:
18+
raise EnvironmentError('missing key: CUMULUS_BASE')
19+
if 'CUMULUS_LAMBDA_PREFIX' not in os.environ:
20+
raise EnvironmentError('missing key: CUMULUS_LAMBDA_PREFIX')
21+
22+
self.__cumulus_base = os.getenv('CUMULUS_BASE')
23+
self.__cumulus_lambda_prefix = os.getenv('CUMULUS_LAMBDA_PREFIX')
24+
25+
self.__cumulus = CollectionsQuery(self.__cumulus_base, self.__jwt_token)
26+
self.__cumulus.with_limit(self.__limit)
27+
self.__cumulus.with_page_number(self.__page_number)
28+
29+
def __assign_values(self):
30+
if 'queryStringParameters' not in self.__event:
31+
return self
32+
query_str_dict = self.__event['queryStringParameters']
33+
if 'limit' in query_str_dict:
34+
self.__limit = int(query_str_dict['limit'])
35+
if 'offset' in query_str_dict:
36+
self.__offset = int(query_str_dict['offset'])
37+
return self
38+
39+
def start(self):
40+
try:
41+
cumulus_result = self.__cumulus.query_direct_to_private_api(self.__cumulus_lambda_prefix)
42+
except Exception as e:
43+
return {
44+
'statusCode': 500,
45+
'body': {'message': f'unpredicted error: {str(e)}'}
46+
}
47+
if 'server_error' in cumulus_result:
48+
return {
49+
'statusCode': 500,
50+
'body': {'message': cumulus_result['server_error']}
51+
}
52+
if 'client_error' in cumulus_result:
53+
return {
54+
'statusCode': 400,
55+
'body': {'message': cumulus_result['client_error']}
56+
}
57+
return {
58+
'statusCode': 200,
59+
'body': json.dumps({'features': cumulus_result['results']})
60+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from cumulus_lambda_functions.cumulus_collections_dapa.cumulus_collections_dapa import CumulusCollectionsDapa
2+
from cumulus_lambda_functions.lib.lambda_logger_generator import LambdaLoggerGenerator
3+
4+
5+
def lambda_handler(event, context):
6+
"""
7+
{'cma': {'task_config': {'bucket': '{$.meta.buckets.internal.name}', 'collection': '{$.meta.collection}', 'cumulus_message': {'outputs': [{'source': '{$.files}', 'destination': '{$.payload}'}]}}, 'event': {'cumulus_meta': {'cumulus_version': '10.0.1', 'execution_name': 'c6d885dc-b4b2-4eb0-b22e-b6f58a7a0870', 'message_source': 'sfn', 'queueExecutionLimits': {'https://sqs.us-west-2.amazonaws.com/884500545225/am-uds-dev-cumulus-backgroundProcessing': 5}, 'state_machine': 'arn:aws:states:us-west-2:884500545225:stateMachine:am-uds-dev-cumulus-IngestGranule', 'system_bucket': 'am-uds-dev-cumulus-internal', 'workflow_start_time': 1646785175509, 'parentExecutionArn': 'arn:aws:states:us-west-2:884500545225:execution:am-uds-dev-cumulus-DiscoverGranules:885483b4-ba55-4db1-b197-661e1e595a45', 'queueUrl': 'arn:aws:sqs:us-west-2:884500545225:am-uds-dev-cumulus-startSF'}, 'exception': 'None', 'meta': {'buckets': {'internal': {'name': 'am-uds-dev-cumulus-internal', 'type': 'internal'}, 'protected': {'name': 'am-uds-dev-cumulus-protected', 'type': 'protected'}}, 'cmr': {'clientId': 'CHANGEME', 'cmrEnvironment': 'UAT', 'cmrLimit': 100, 'cmrPageSize': 50, 'oauthProvider': 'earthdata', 'passwordSecretName': 'am-uds-dev-cumulus-message-template-cmr-password20220216072916956000000002', 'provider': 'CHANGEME', 'username': 'username'}, 'collection': {'name': 'ATMS_SCIENCE_Group_2011', 'version': '001', 'process': 'modis', 'granuleId': '^P[0-9]{3}[0-9]{4}[A-Z]{13}T[0-9]{12}0$', 'granuleIdExtraction': '(P[0-9]{3}[0-9]{4}[A-Z]{13}T[0-9]{12}0).+', 'sampleFileName': 'P1570515ATMSSCIENCEAXT11344000000001.PDS', 'duplicateHandling': 'replace', 'url_path': '{cmrMetadata.Granule.Collection.ShortName}___{cmrMetadata.Granule.Collection.VersionId}', 'provider_path': '/data/SNPP_ATMS_Level0_T/ATMS_SCIENCE_Group/2011/', 'files': [{'bucket': 'internal', 'regex': '^P[0-9]{3}[0-9]{4}[A-Z]{13}T[0-9]{12}00\\.PDS$', 'sampleFileName': 'P1570515ATMSSCIENCEAXT11344000000000.PDS', 'type': 'data'}, {'bucket': 'internal', 'regex': '^P[0-9]{3}[0-9]{4}[A-Z]{13}T[0-9]{12}01\\.PDS$', 'sampleFileName': 'P1570515ATMSSCIENCEAXT11344000000001.PDS', 'type': 'metadata'}, {'bucket': 'internal', 'regex': '^P[0-9]{3}[0-9]{4}[A-Z]{13}T[0-9]{12}01\\.PDS\\.xml$', 'sampleFileName': 'P1570515ATMSSCIENCEAXT11344000000001.PDS.xml', 'type': 'metadata'}, {'bucket': 'internal', 'regex': '^P[0-9]{3}[0-9]{4}[A-Z]{13}T[0-9]{12}0\\.cmr\\.xml$', 'sampleFileName': 'P1570515ATMSSCIENCEAXT11344000000001.PDS.xml', 'type': 'metadata'}], 'updatedAt': 1646326197526, 'createdAt': 1646258167624}, 'distribution_endpoint': 's3://am-uds-dev-cumulus-internal/', 'launchpad': {'api': 'launchpadApi', 'certificate': 'launchpad.pfx', 'passphraseSecretName': ''}, 'provider': {'password': 'AQICAHhSagsGDAl5tQWM010IEvxKgj2LcsNub5v5FHoRpOjXcQHFbE4iMnF/W0Y/NrsYvrfHAAAAajBoBgkqhkiG9w0BBwagWzBZAgEAMFQGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMLaH13SdxPXREjXLtAgEQgCfA+lEu2c/xLTGwJsbtKlXJbKDy4pwV+rS3BnJqgBoLLMQZqOdoFhk=', 'host': 'snppl0.gesdisc.eosdis.nasa.gov', 'updatedAt': 1646244053419, 'protocol': 'https', 'createdAt': 1646244053419, 'encrypted': True, 'username': 'AQICAHhSagsGDAl5tQWM010IEvxKgj2LcsNub5v5FHoRpOjXcQGRoY5EBMpvvyMASUowBM61AAAAYzBhBgkqhkiG9w0BBwagVDBSAgEAME0GCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM9OhRHwTuxiz74q4UAgEQgCDEHOhsVG6+LqXfnlw+Z3Wg9MDOCd9/K5/X5j3tPJYkaA==', 'allowedRedirects': ['https://urs.earthdata.nasa.gov', 'urs.earthdata.nasa.gov'], 'id': 'snpp_provider_02', 'globalConnectionLimit': 10}, 'stack': 'am-uds-dev-cumulus', 'template': 's3://am-uds-dev-cumulus-internal/am-uds-dev-cumulus/workflow_template.json', 'workflow_name': 'IngestGranule', 'workflow_tasks': {'SyncGranule': {'name': 'am-uds-dev-cumulus-SyncGranule', 'version': '$LATEST', 'arn': 'arn:aws:lambda:us-west-2:884500545225:function:am-uds-dev-cumulus-SyncGranule'}}, 'staticValue': 'aStaticValue', 'interpolatedValueStackName': 'am-uds-dev-cumulus', 'input_granules': [{'granuleId': 'P1570515ATMSSCIENCEAXT1134912000000', 'dataType': 'ATMS_SCIENCE_Group_2011', 'version': '001', 'files': [{'bucket': 'am-uds-dev-cumulus-internal', 'key': 'file-staging/am-uds-dev-cumulus/ATMS_SCIENCE_Group_2011___001/P1570515ATMSSCIENCEAXT11349120000000.PDS', 'source': 'data/SNPP_ATMS_Level0_T/ATMS_SCIENCE_Group/2011/349//P1570515ATMSSCIENCEAXT11349120000000.PDS', 'fileName': 'P1570515ATMSSCIENCEAXT11349120000000.PDS', 'type': 'data', 'size': 744}, {'bucket': 'am-uds-dev-cumulus-internal', 'key': 'file-staging/am-uds-dev-cumulus/ATMS_SCIENCE_Group_2011___001/P1570515ATMSSCIENCEAXT11349120000001.PDS', 'source': 'data/SNPP_ATMS_Level0_T/ATMS_SCIENCE_Group/2011/349//P1570515ATMSSCIENCEAXT11349120000001.PDS', 'fileName': 'P1570515ATMSSCIENCEAXT11349120000001.PDS', 'type': 'metadata', 'size': 18084600}, {'bucket': 'am-uds-dev-cumulus-internal', 'key': 'file-staging/am-uds-dev-cumulus/ATMS_SCIENCE_Group_2011___001/P1570515ATMSSCIENCEAXT11349120000001.PDS.xml', 'source': 'data/SNPP_ATMS_Level0_T/ATMS_SCIENCE_Group/2011/349//P1570515ATMSSCIENCEAXT11349120000001.PDS.xml', 'fileName': 'P1570515ATMSSCIENCEAXT11349120000001.PDS.xml', 'type': 'metadata', 'size': 9526}], 'sync_granule_duration': 9822, 'createdAt': 1647386972717}], 'process': 'modis'}, 'payload': {}, 'replace': {'Bucket': 'am-uds-dev-cumulus-internal', 'Key': 'events/5d8edf37-0a18-4af5-a76f-7c2091cdd1e2', 'TargetPath': '$.payload'}}}}
8+
:param event:
9+
:param context:
10+
:return:
11+
"""
12+
LambdaLoggerGenerator.remove_default_handlers()
13+
# TODO implement
14+
return CumulusCollectionsDapa(event).start()

cumulus_lambda_functions/cumulus_wrapper/cumulus_base.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import boto3
2+
import json
3+
14
from abc import ABC
25
from copy import deepcopy
36

@@ -22,6 +25,17 @@ def with_limit(self, limit: int):
2225
def get_base_headers(self):
2326
return deepcopy(self.__base_headers)
2427

28+
def _invoke_api(self, payload, private_api_prefix: str):
29+
"""Function to invoke cumulus api via aws lambda"""
30+
client = boto3.client('lambda')
31+
response = client.invoke(
32+
FunctionName=f'{private_api_prefix}-PrivateApiLambda',
33+
Payload=json.dumps(payload),
34+
)
35+
json_response_payload = response.get('Payload').read().decode('utf-8')
36+
response_data = json.loads(json_response_payload)
37+
return response_data
38+
2539
@property
2640
def cumulus_base(self):
2741
return self.__cumulus_base
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import json
2+
3+
import requests
4+
from cumulus_lambda_functions.cumulus_stac.collection_transformer import CollectionTransformer
5+
6+
from cumulus_lambda_functions.cumulus_wrapper.cumulus_base import CumulusBase
7+
from cumulus_lambda_functions.lib.lambda_logger_generator import LambdaLoggerGenerator
8+
9+
LOGGER = LambdaLoggerGenerator.get_logger(__name__, LambdaLoggerGenerator.get_level_from_env())
10+
11+
12+
class CollectionsQuery(CumulusBase):
13+
__collections_key = 'collections'
14+
15+
def __init__(self, cumulus_base: str, cumulus_token: str):
16+
super().__init__(cumulus_base, cumulus_token)
17+
18+
def query_direct_to_private_api(self, private_api_prefix: str):
19+
payload = {
20+
'httpMethod': 'GET',
21+
'resource': '/{proxy+}',
22+
'path': f'/{self.__collections_key}',
23+
'queryStringParameters': {k[0]: k[1] for k in [k1.split('=') for k1 in self._conditions]},
24+
}
25+
LOGGER.debug(f'payload: {payload}')
26+
try:
27+
query_result = self._invoke_api(payload, private_api_prefix)
28+
"""
29+
{'statusCode': 200, 'body': '{"meta":{"name":"cumulus-api","stack":"am-uds-dev-cumulus","table":"granule","limit":3,"page":1,"count":0},"results":[]}', 'headers': {'x-powered-by': 'Express', 'access-control-allow-origin': '*', 'strict-transport-security': 'max-age=31536000; includeSubDomains', 'content-type': 'application/json; charset=utf-8', 'content-length': '120', 'etag': 'W/"78-YdHqDNIH4LuOJMR39jGNA/23yOQ"', 'date': 'Tue, 07 Jun 2022 22:30:44 GMT', 'connection': 'close'}, 'isBase64Encoded': False}
30+
"""
31+
if query_result['statusCode'] >= 500:
32+
LOGGER.error(f'server error status code: {query_result.statusCode}. details: {query_result}')
33+
return {'server_error': query_result}
34+
if query_result['statusCode'] >= 400:
35+
LOGGER.error(f'client error status code: {query_result.statusCode}. details: {query_result}')
36+
return {'client_error': query_result}
37+
query_result = json.loads(query_result['body'])
38+
LOGGER.info(f'json query_result: {query_result}')
39+
if 'results' not in query_result:
40+
LOGGER.error(f'missing key: results. invalid response json: {query_result}')
41+
return {'server_error': f'missing key: results. invalid response json: {query_result}'}
42+
query_result = query_result['results']
43+
stac_list = [CollectionTransformer().to_stac(k) for k in query_result]
44+
except Exception as e:
45+
LOGGER.exception('error while invoking')
46+
return {'server_error': f'error while invoking:{str(e)}'}
47+
return {'results': stac_list}
48+
49+
def query(self):
50+
conditions_str = '&'.join(self._conditions)
51+
LOGGER.info(f'cumulus_base: {self.cumulus_base}')
52+
LOGGER.info(f'get_base_headers: {self.get_base_headers()}')
53+
try:
54+
query_result = requests.get(url=f'{self.cumulus_base}/{self.__collections_key}?{conditions_str}', headers=self.get_base_headers())
55+
LOGGER.info(f'query_result: {query_result}')
56+
if query_result.status_code >= 500:
57+
return {'server_error': query_result.text}
58+
if query_result.status_code >= 400:
59+
return {'client_error': query_result.text}
60+
query_result = json.loads(query_result.content.decode())
61+
LOGGER.info(f'query_result: {query_result}')
62+
if 'results' not in query_result:
63+
return {'server_error': f'missing key: results. invalid response json: {query_result}'}
64+
query_result = query_result['results']
65+
except Exception as e:
66+
LOGGER.exception('error during cumulus query')
67+
return {'server_error': str(e)}
68+
return {'results': [CollectionTransformer().to_stac(k) for k in query_result]}

cumulus_lambda_functions/cumulus_wrapper/query_granules.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,6 @@ def with_time_range(self, from_time, to_time):
5151
self._conditions.append(f'{self.__beginning_time_key}__to={to_time}')
5252
return self
5353

54-
def __invoke_api(self, payload, private_api_prefix: str):
55-
"""Function to invoke cumulus api via aws lambda"""
56-
57-
client = boto3.client('lambda')
58-
response = client.invoke(
59-
FunctionName=f'{private_api_prefix}-PrivateApiLambda',
60-
Payload=json.dumps(payload),
61-
)
62-
json_response_payload = response.get('Payload').read().decode('utf-8')
63-
response_data = json.loads(json_response_payload)
64-
65-
return response_data
66-
6754
def query_direct_to_private_api(self, private_api_prefix: str):
6855
payload = {
6956
'httpMethod': 'GET',
@@ -78,7 +65,7 @@ def query_direct_to_private_api(self, private_api_prefix: str):
7865
}
7966
LOGGER.debug(f'payload: {payload}')
8067
try:
81-
query_result = self.__invoke_api(payload, private_api_prefix)
68+
query_result = self._invoke_api(payload, private_api_prefix)
8269
"""
8370
{'statusCode': 200, 'body': '{"meta":{"name":"cumulus-api","stack":"am-uds-dev-cumulus","table":"granule","limit":3,"page":1,"count":0},"results":[]}', 'headers': {'x-powered-by': 'Express', 'access-control-allow-origin': '*', 'strict-transport-security': 'max-age=31536000; includeSubDomains', 'content-type': 'application/json; charset=utf-8', 'content-length': '120', 'etag': 'W/"78-YdHqDNIH4LuOJMR39jGNA/23yOQ"', 'date': 'Tue, 07 Jun 2022 22:30:44 GMT', 'connection': 'close'}, 'isBase64Encoded': False}
8471
"""

etc/Unity-API-Gateway-dev-swagger-apigateway-am-uds-dapa.yaml

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ paths:
3232
in: "query"
3333
required: false
3434
type: "string"
35-
- name: "Authorization"
36-
in: "header"
37-
required: false
38-
type: "string"
3935
responses:
4036
"200":
4137
description: "200 response"
@@ -55,7 +51,75 @@ paths:
5551
securityDefinitions:
5652
Unity_API_Gateway_Lambda_WPST_UI_Demo_Authorizer_Node:
5753
type: "apiKey"
58-
name: "Authorization"
54+
name: "Authorization"---
55+
swagger: "2.0"
56+
info:
57+
description: "Unity API Gateway"
58+
version: "2022-05-04T20:23:33Z"
59+
title: "Unity API Gateway"
60+
host: "k3a3qmarxh.execute-api.us-west-2.amazonaws.com"
61+
basePath: "/dev"
62+
schemes:
63+
- "https"
64+
paths:
65+
/am-uds-dapa/collections/{collectionId}/observation/items:
66+
get:
67+
produces:
68+
- "application/json"
69+
parameters:
70+
- name: "collectionId"
71+
in: "path"
72+
- name: "datetime"
73+
in: "query"
74+
required: false
75+
type: "string"
76+
- name: "limit"
77+
in: "query"
78+
required: false
79+
type: "string"
80+
- name: "offset"
81+
in: "query"
82+
required: false
83+
type: "string"
84+
- name: "bbox"
85+
in: "query"
86+
required: false
87+
type: "string"
88+
responses:
89+
"200":
90+
description: "200 response"
91+
schema:
92+
$ref: "#/definitions/Empty"
93+
x-amazon-apigateway-request-validator: "Validate body, query string parameters,\
94+
\ and headers"
95+
x-amazon-apigateway-integration:
96+
type: "aws_proxy"
97+
httpMethod: "POST"
98+
uri: "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:884500545225:function:am-uds-dapa-test-1/invocations"
99+
responses:
100+
default:
101+
statusCode: "200"
102+
passthroughBehavior: "when_no_match"
103+
contentHandling: "CONVERT_TO_TEXT"
104+
securityDefinitions:
105+
Unity_API_Gateway_Lambda_WPST_UI_Demo_Authorizer_Node:
106+
type: "apiKey"
107+
name: "Authorization"
108+
in: "header"
109+
x-amazon-apigateway-authtype: "custom"
110+
x-amazon-apigateway-authorizer:
111+
type: "token"
112+
authorizerUri: "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:884500545225:function:cs-token-auth-wpst-demo-ui/invocations"
113+
authorizerResultTtlInSeconds: 0
114+
definitions:
115+
Empty:
116+
type: "object"
117+
title: "Empty Schema"
118+
x-amazon-apigateway-request-validators:
119+
Validate body, query string parameters, and headers:
120+
validateRequestParameters: true
121+
validateRequestBody: true
122+
59123
in: "header"
60124
x-amazon-apigateway-authtype: "custom"
61125
x-amazon-apigateway-authorizer:

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
setup(
1818
name="cumulus_lambda_functions",
19-
version="1.2.3",
19+
version="1.3.3",
2020
packages=find_packages(),
2121
install_requires=install_requires,
2222
tests_require=['mock', 'nose', 'sphinx', 'sphinx_rtd_theme', 'coverage'],

tf-module/unity-cumulus/main.tf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@ resource "aws_lambda_function" "cumulus_granules_dapa" {
6868
}
6969
}
7070

71+
vpc_config {
72+
subnet_ids = var.cumulus_lambda_subnet_ids
73+
security_group_ids = local.security_group_ids_set ? var.security_group_ids : [aws_security_group.unity_cumulus_lambda_sg[0].id]
74+
}
75+
tags = var.tags
76+
}
77+
78+
resource "aws_lambda_function" "cumulus_granules_dapa" {
79+
filename = local.lambda_file_name
80+
function_name = "${var.prefix}-cumulus_collections_dapa"
81+
role = data.aws_iam_role.unity_cumulus_lambda_role.arn
82+
handler = "cumulus_lambda_functions.cumulus_collections_dapa.lambda_function.lambda_handler"
83+
runtime = "python3.7"
84+
timeout = 300
85+
86+
environment {
87+
variables = {
88+
CUMULUS_BASE = var.cumulus_base
89+
CUMULUS_LAMBDA_PREFIX = var.prefix
90+
}
91+
}
92+
7193
vpc_config {
7294
subnet_ids = var.cumulus_lambda_subnet_ids
7395
security_group_ids = local.security_group_ids_set ? var.security_group_ids : [aws_security_group.unity_cumulus_lambda_sg[0].id]

tf-module/unity-cumulus/terraform.tfvars.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@ system_bucket = "am-uds-dev-cumulus-internal"
3333
cumulus_lambda_vpc_id = "vpc-06e627ef021d1854e"
3434
security_group_ids = ["sg-045f9c24c760940b6"]
3535
aws_region = "us-west-2"
36+
aws_region = "us-west-2"
37+
cumulus_base = "https://axhmoecy02.execute-api.us-west-2.amazonaws.com/dev"

0 commit comments

Comments
 (0)