Skip to content

Commit a64e0c0

Browse files
authored
Merge fc188a1 into f10f913
2 parents f10f913 + fc188a1 commit a64e0c0

File tree

25 files changed

+806
-47
lines changed

25 files changed

+806
-47
lines changed

.github/workflows/dockerbuild.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
- uses: actions/checkout@v3
1616
- uses: actions/setup-python@v3
1717
with:
18-
python-version: '3.7'
18+
python-version: '3.9'
1919
- run: |
2020
# make file runnable, might not be necessary
2121
chmod +x "${GITHUB_WORKSPACE}/ci.cd/store_version.sh"

.github/workflows/makefile.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Makefile CI
22

33
on:
44
push:
5-
branches: [ main ]
6-
# pull_request:
7-
# branches: [ main ]
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ develop ]
88

99
env:
1010
ARTIFACT_BASE_NAME: cumulus_lambda_functions
@@ -17,7 +17,7 @@ jobs:
1717
- uses: actions/checkout@v3
1818
- uses: actions/setup-python@v3
1919
with:
20-
python-version: '3.7'
20+
python-version: '3.9'
2121
- run: |
2222
python3 "${GITHUB_WORKSPACE}/setup.py" install
2323
- run: |
@@ -52,7 +52,7 @@ jobs:
5252
prerelease: false
5353
- name: Create PreRelease
5454
id: create_prerelease
55-
if: ${{ contains(github.ref, 'main') }}
55+
# if: ${{ contains(github.ref, 'main') }}
5656
uses: actions/create-release@v1
5757
env:
5858
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
@@ -66,7 +66,7 @@ jobs:
6666
prerelease: true
6767
- name: Upload PreRelease Asset 1
6868
id: upload-prerelease-asset-1
69-
if: ${{ contains(github.ref, 'main') }}
69+
# if: ${{ contains(github.ref, 'main') }}
7070
uses: actions/upload-release-asset@v1
7171
env:
7272
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -77,7 +77,7 @@ jobs:
7777
asset_content_type: application/zip
7878
- name: Upload PreRelease Asset 2
7979
id: upload-prerelease-asset-2
80-
if: ${{ contains(github.ref, 'main') }}
80+
# if: ${{ contains(github.ref, 'main') }}
8181
uses: actions/upload-release-asset@v1
8282
env:
8383
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

ci.cd/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ update_lambda_function_2:
2525
aws --profile saml-pub lambda update-function-code --s3-key unity_cumulus_lambda/cumulus_lambda_functions_deployment.zip --s3-bucket am-uds-dev-cumulus-tf-state --function-name arn:aws:lambda:us-west-2:884500545225:function:am-uds-dev-cumulus-cumulus_granules_dapa --publish &>/dev/null
2626
update_lambda_function_3:
2727
aws --profile saml-pub lambda update-function-code --s3-key unity_cumulus_lambda/cumulus_lambda_functions_deployment.zip --s3-bucket am-uds-dev-cumulus-tf-state --function-name arn:aws:lambda:us-west-2:884500545225:function:am-uds-dev-cumulus-cumulus_collections_ingest_cnm_dapa --publish &>/dev/null
28+
update_lambda_function_4:
29+
aws --profile saml-pub lambda update-function-code --s3-key unity_cumulus_lambda/cumulus_lambda_functions_deployment.zip --s3-bucket am-uds-dev-cumulus-tf-state --function-name arn:aws:lambda:us-west-2:884500545225:function:am-uds-dev-cumulus-cumulus_collections_creation_dapa --publish &>/dev/null
30+
update_lambda_function_5:
31+
aws --profile saml-pub lambda update-function-code --s3-key unity_cumulus_lambda/cumulus_lambda_functions_deployment.zip --s3-bucket am-uds-dev-cumulus-tf-state --function-name arn:aws:lambda:us-west-2:884500545225:function:am-uds-dev-cumulus-cumulus_collections_creation_dapa_facade --publish &>/dev/null

ci.cd/create_aws_lambda_zip.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ cp ${zip_file} build/
2222
cd $project_root_dir/tf-module/unity-cumulus
2323
zip -9 ${terraform_zip_file} * **/*
2424

25+
# github.job
26+
github_branch=${GITHUB_REF##*/}
27+
software_version_trailing=""
28+
main_branch="main"
29+
if [ "$github_branch" = "$main_branch" ];
30+
then
31+
software_version=""
32+
else
33+
software_version_trailing="-${github_branch}-${GITHUB_RUN_ID}"
34+
fi
2535
software_version=`python3 ${project_root_dir}/setup.py --version`
26-
echo "software_version=${software_version}" >> ${GITHUB_ENV}
36+
echo "software_version=${software_version}${software_version_trailing}" >> ${GITHUB_ENV}
2737
cat ${GITHUB_ENV}

cumulus_lambda_functions/cumulus_collections_dapa/cumulus_collections_dapa.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ def start(self):
6161
if 'server_error' in cumulus_result:
6262
return {
6363
'statusCode': 500,
64-
'body': {'message': cumulus_result['server_error']}
64+
'body': json.dumps({'message': cumulus_result['server_error']})
6565
}
6666
if 'client_error' in cumulus_result:
6767
return {
6868
'statusCode': 400,
69-
'body': {'message': cumulus_result['client_error']}
69+
'body': json.dumps({'message': cumulus_result['client_error']})
7070
}
7171
cumulus_size = self.__get_size()
7272
return {
@@ -84,5 +84,5 @@ def start(self):
8484
LOGGER.exception(f'unexpected error')
8585
return {
8686
'statusCode': 500,
87-
'body': {'message': f'unpredicted error: {str(e)}'}
87+
'body': json.dumps({'message': f'unpredicted error: {str(e)}'})
8888
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import json
2+
import os
3+
4+
import pystac
5+
6+
from cumulus_lambda_functions.cumulus_stac.collection_transformer import CollectionTransformer
7+
from cumulus_lambda_functions.cumulus_wrapper.query_collections import CollectionsQuery
8+
from cumulus_lambda_functions.lib.aws.aws_lambda import AwsLambda
9+
from cumulus_lambda_functions.lib.lambda_logger_generator import LambdaLoggerGenerator
10+
11+
LOGGER = LambdaLoggerGenerator.get_logger(__name__, LambdaLoggerGenerator.get_level_from_env())
12+
13+
14+
class CumulusCreateCollectionDapa:
15+
def __init__(self, event):
16+
required_env = ['CUMULUS_LAMBDA_PREFIX', 'CUMULUS_WORKFLOW_SQS_URL']
17+
if not all([k in os.environ for k in required_env]):
18+
raise EnvironmentError(f'one or more missing env: {required_env}')
19+
self.__event = event
20+
self.__request_body = None
21+
self.__cumulus_collection_query = CollectionsQuery('', '')
22+
self.__cumulus_lambda_prefix = os.getenv('CUMULUS_LAMBDA_PREFIX')
23+
self.__ingest_sqs_url = os.getenv('CUMULUS_WORKFLOW_SQS_URL')
24+
self.__workflow_name = os.getenv('CUMULUS_WORKFLOW_NAME', 'CatalogGranule')
25+
self.__provider_id = '' # TODO. need this?
26+
self.__collection_creation_lambda_name = os.environ.get('COLLECTION_CREATION_LAMBDA_NAME', '').strip()
27+
28+
def execute_creation(self):
29+
try:
30+
cumulus_collection_doc = CollectionTransformer().from_stac(self.__request_body)
31+
creation_result = self.__cumulus_collection_query.create_collection(cumulus_collection_doc, self.__cumulus_lambda_prefix)
32+
if 'status' not in creation_result:
33+
LOGGER.error(f'status not in creation_result: {creation_result}')
34+
return {
35+
'statusCode': 500,
36+
'body': json.dumps({
37+
'message': creation_result
38+
})
39+
}
40+
rule_creation_result = self.__cumulus_collection_query.create_sqs_rules(
41+
cumulus_collection_doc,
42+
self.__cumulus_lambda_prefix,
43+
self.__ingest_sqs_url,
44+
self.__provider_id,
45+
self.__workflow_name,
46+
)
47+
if 'status' not in rule_creation_result:
48+
# 'TODO' delete collection
49+
LOGGER.error(f'status not in rule_creation_result: {rule_creation_result}')
50+
return {
51+
'statusCode': 500,
52+
'body': json.dumps({
53+
'message': {rule_creation_result},
54+
})
55+
}
56+
except Exception as e:
57+
LOGGER.exception('error while creating new collection in Cumulus')
58+
return {
59+
'statusCode': 500,
60+
'body': json.dumps({
61+
'message': f'error while creating new collection in Cumulus. check details',
62+
'details': str(e)
63+
})
64+
}
65+
LOGGER.info(f'creation_result: {creation_result}')
66+
return {
67+
'statusCode': 200,
68+
'body': json.dumps({
69+
'message': creation_result
70+
})
71+
}
72+
73+
def start(self):
74+
if 'body' not in self.__event:
75+
raise ValueError(f'missing body in {self.__event}')
76+
self.__request_body = json.loads(self.__event['body'])
77+
LOGGER.debug(f'request body: {self.__request_body}')
78+
validation_result = pystac.Collection.from_dict(self.__request_body).validate()
79+
if not isinstance(validation_result, list):
80+
LOGGER.error(f'request body is not valid STAC collection: {validation_result}')
81+
return {
82+
'statusCode': 500,
83+
'body': json.dumps({'message': f'request body is not valid STAC Collection schema. check details',
84+
'details': validation_result})
85+
}
86+
if self.__collection_creation_lambda_name != '':
87+
response = AwsLambda().invoke_function(
88+
function_name=self.__collection_creation_lambda_name,
89+
payload=self.__event,
90+
)
91+
LOGGER.debug(f'async function started: {response}')
92+
return {
93+
'statusCode': 202,
94+
'body': json.dumps({
95+
'message': 'processing'
96+
})
97+
}
98+
LOGGER.debug(f'creating collection.')
99+
return self.execute_creation()

cumulus_lambda_functions/cumulus_collections_dapa/lambda_function.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from cumulus_lambda_functions.cumulus_collections_dapa.cumulus_collections_dapa import CumulusCollectionsDapa
2+
from cumulus_lambda_functions.cumulus_collections_dapa.cumulus_create_collection_dapa import CumulusCreateCollectionDapa
23
from cumulus_lambda_functions.lib.lambda_logger_generator import LambdaLoggerGenerator
34

45

@@ -12,3 +13,8 @@ def lambda_handler(event, context):
1213
LambdaLoggerGenerator.remove_default_handlers()
1314
# TODO implement
1415
return CumulusCollectionsDapa(event).start()
16+
17+
18+
def lambda_handler_ingestion(event, context):
19+
LambdaLoggerGenerator.remove_default_handlers()
20+
return CumulusCreateCollectionDapa(event).start()

cumulus_lambda_functions/cumulus_granules_dapa/cumulus_granules_dapa.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,12 @@ def start(self):
110110
if 'server_error' in cumulus_result:
111111
return {
112112
'statusCode': 500,
113-
'body': {'message': cumulus_result['server_error']}
113+
'body': json.dumps({'message': cumulus_result['server_error']})
114114
}
115115
if 'client_error' in cumulus_result:
116116
return {
117117
'statusCode': 400,
118-
'body': {'message': cumulus_result['client_error']}
118+
'body': json.dumps({'message': cumulus_result['client_error']})
119119
}
120120
cumulus_size = self.__get_size()
121121
return {
@@ -133,5 +133,5 @@ def start(self):
133133
LOGGER.exception(f'unexpected error')
134134
return {
135135
'statusCode': 500,
136-
'body': {'message': f'unpredicted error: {str(e)}'}
136+
'body': json.dumps({'message': f'unpredicted error: {str(e)}'})
137137
}

cumulus_lambda_functions/cumulus_granules_dapa_ingest_cnm/cumulus_granules_dapa_ingest_cnm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,5 @@ def start(self):
193193
}
194194
return {
195195
'statusCode': 500,
196-
'body': {'message': f'failed {len(error_list)}/{len(self.__request_body["features"])}', 'details': error_list}
196+
'body': json.dumps({'message': f'failed {len(error_list)}/{len(self.__request_body["features"])}', 'details': error_list})
197197
}

cumulus_lambda_functions/cumulus_stac/collection_transformer.py

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import json
22
from datetime import datetime
3-
from urllib.parse import quote_plus
3+
from urllib.parse import quote_plus, urlparse, unquote_plus
44

5+
import pystac
6+
from pystac import Link
57

68
from cumulus_lambda_functions.cumulus_stac.stac_transformer_abstract import StacTransformerAbstract
9+
from cumulus_lambda_functions.lib.time_utils import TimeUtils
710

811
STAC_COLLECTION_SCHEMA = '''{
912
"$schema": "http://json-schema.org/draft-07/schema#",
@@ -281,11 +284,21 @@
281284

282285

283286
class CollectionTransformer(StacTransformerAbstract):
284-
def __init__(self):
287+
def __init__(self, report_to_ems:bool = True, include_date_range=False):
285288
self.__stac_collection_schema = json.loads(STAC_COLLECTION_SCHEMA)
286289
self.__cumulus_collection_schema = {}
290+
self.__report_to_ems = report_to_ems
291+
self.__include_date_range = include_date_range
287292

288-
def __convert_to_stac_links(self, collection_file_obj: dict):
293+
def generate_target_link_url(self, regex: str = None, bucket: str = None):
294+
href_link = ['unknown_bucket', 'unknown_regex']
295+
if regex is not None and regex != '':
296+
href_link[1] = regex
297+
if bucket is not None and bucket != '':
298+
href_link[0] = bucket
299+
return f"./collection.json?bucket={href_link[0]}&regex={quote_plus(href_link[1])}"
300+
301+
def __convert_to_stac_links(self, collection_file_obj: dict, rel_type: str = 'item'):
289302
"""
290303
expected output
291304
{
@@ -310,18 +323,16 @@ def __convert_to_stac_links(self, collection_file_obj: dict):
310323
if collection_file_obj is None:
311324
return {}
312325
stac_link = {
313-
'rel': 'item',
326+
'rel': rel_type,
314327
}
315328
if 'type' in collection_file_obj:
316329
stac_link['type'] = collection_file_obj['type']
317330
if 'sampleFileName' in collection_file_obj:
318331
stac_link['title'] = collection_file_obj['sampleFileName']
319-
href_link = ['unknown_bucket', 'unknown_regex']
320-
if 'bucket' in collection_file_obj:
321-
href_link[0] = collection_file_obj['bucket']
322-
if 'regex' in collection_file_obj:
323-
href_link[1] = collection_file_obj['regex']
324-
stac_link['href'] = f"./collection.json?bucket={href_link[0]}&regex={quote_plus(href_link[1])}"
332+
stac_link['href'] = self.generate_target_link_url(
333+
collection_file_obj['regex'] if 'regex' in collection_file_obj else None,
334+
collection_file_obj['bucket'] if 'bucket' in collection_file_obj else None,
335+
)
325336
return stac_link
326337

327338
# def to_pystac_link_obj(self, input_dict: dict):
@@ -418,14 +429,77 @@ def to_stac(self, source: dict) -> dict:
418429
"process": [source['process'] if 'process' in source else ''],
419430
"totalGranules": [source['total_size'] if 'total_size' in source else -1],
420431
},
421-
"links": [{
422-
"rel": "root",
423-
"type": "application/json",
424-
"title": f"{source['name']}___{source['version']}",
425-
"href": "./collection.json"
426-
}] + [self.__convert_to_stac_links(k) for k in source['files']],
432+
"links": [self.__convert_to_stac_links({
433+
"regex": source['url_path'] if 'url_path' in source else './collection.json',
434+
"sampleFileName": source['sampleFileName'],
435+
"type": "application/json",
436+
437+
}, 'root')] + [self.__convert_to_stac_links(k) for k in source['files']],
427438
}
428439
return stac_collection
429440

441+
def get_href(self, input_href: str):
442+
parse_result = urlparse(input_href)
443+
if parse_result.query == '':
444+
return ''
445+
query_dict = [k.split('=') for k in parse_result.query.split('&')]
446+
query_dict = {k[0]: unquote_plus(k[1]) for k in query_dict}
447+
return query_dict
448+
449+
def __convert_from_stac_links(self, link_obj: dict):
450+
output_file_object = {
451+
'reportToEms': self.__report_to_ems
452+
}
453+
if 'type' in link_obj:
454+
output_file_object['type'] = link_obj['type']
455+
if 'title' in link_obj:
456+
output_file_object['sampleFileName'] = link_obj['title']
457+
if 'href' in link_obj:
458+
href_dict = self.get_href(link_obj['href'])
459+
if 'bucket' in href_dict:
460+
output_file_object['bucket'] = href_dict['bucket']
461+
if 'regex' in href_dict:
462+
output_file_object['regex'] = href_dict['regex']
463+
return output_file_object
464+
430465
def from_stac(self, source: dict) -> dict:
431-
return {}
466+
input_dapa_collection = pystac.Collection.from_dict(source)
467+
if not input_dapa_collection.validate():
468+
raise ValueError(f'invalid source dapa: {input_dapa_collection}')
469+
output_collection_cumulus = {
470+
# "createdAt": 1647992847582,
471+
"reportToEms": self.__report_to_ems,
472+
"duplicateHandling": "skip",
473+
# "updatedAt": 1647992847582,
474+
# "timestamp": 1647992849273
475+
}
476+
summaries = input_dapa_collection.summaries.lists
477+
if 'granuleId' in summaries:
478+
output_collection_cumulus['granuleId'] = summaries['granuleId'][0]
479+
if 'granuleIdExtraction' in summaries:
480+
output_collection_cumulus['granuleIdExtraction'] = summaries['granuleIdExtraction'][0]
481+
if 'process' in summaries:
482+
output_collection_cumulus['process'] = summaries['process'][0]
483+
name_version = input_dapa_collection.id.split('___')
484+
output_collection_cumulus['name'] = name_version[0]
485+
output_collection_cumulus['version'] = name_version[1]
486+
output_files = []
487+
for each_link_obj in input_dapa_collection.links:
488+
each_link_obj: Link = each_link_obj
489+
each_file_obj = self.__convert_from_stac_links(each_link_obj.to_dict())
490+
if each_link_obj.rel == 'root':
491+
if 'regex' in each_file_obj:
492+
output_collection_cumulus['url_path'] = each_file_obj['regex']
493+
if 'sampleFileName' in each_file_obj:
494+
output_collection_cumulus['sampleFileName'] = each_file_obj['sampleFileName']
495+
else:
496+
output_files.append(each_file_obj)
497+
output_collection_cumulus['files'] = output_files
498+
if len(input_dapa_collection.extent.temporal.intervals) > 0:
499+
date_interval = input_dapa_collection.extent.temporal.intervals[0]
500+
if len(date_interval) == 2 and self.__include_date_range is True:
501+
if date_interval[0] is not None:
502+
output_collection_cumulus['dateFrom'] = date_interval[0].strftime(TimeUtils.MMDD_FORMAT)
503+
if date_interval[1] is not None:
504+
output_collection_cumulus['dateTo'] = date_interval[1].strftime(TimeUtils.MMDD_FORMAT)
505+
return output_collection_cumulus

0 commit comments

Comments
 (0)