Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/0.10.0 #129

Open
wants to merge 118 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
19b9c70
Feature/update add collection test (#94)
sliu008 Nov 6, 2023
efa2115
/version 0.7.0a24
Nov 6, 2023
f63db11
Update uat_associations.txt with new collections
jonathansmolenski Nov 6, 2023
461995b
Update uat_associations.txt with new collections
jonathansmolenski Nov 6, 2023
50190f5
Update uat_associations.txt with new collections
jonathansmolenski Nov 6, 2023
bd6bcda
Feature/update add collection test (#95)
sliu008 Nov 6, 2023
7fff1af
/version 0.7.0a25
Nov 6, 2023
0f77a7d
Update uat_associations.txt with new collections
jonathansmolenski Nov 7, 2023
8230bf3
Update uat_associations.txt with new collections
jonathansmolenski Nov 7, 2023
885c385
Update uat_associations.txt with new collections
jonathansmolenski Nov 7, 2023
820ffdd
Update uat_associations.txt with new collections
jonathansmolenski Nov 7, 2023
df32c06
Merge branch 'main' into develop
jamesfwood Nov 10, 2023
8c4618e
/version 0.8.0a1
Nov 10, 2023
a66474e
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
6df14ec
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
e517fe0
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
b6f6d5a
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
60fbb6b
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
7ef8263
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
a85bb08
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
c166f5a
Update ops_associations.txt with new collections
jonathansmolenski Nov 15, 2023
361119b
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
7e7f564
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
3212658
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
1440a5c
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
861a8ce
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
5f0405f
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
4e0a6e3
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
ca0e397
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
ccb3d6c
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
6e5bcaa
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
5cd88ca
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
ad91fe7
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
74d05e0
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
2a29cc9
Update ops_associations.txt with new collections
jonathansmolenski Dec 6, 2023
ae0c882
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
b937944
Update uat_associations.txt with new collections
jonathansmolenski Dec 6, 2023
2bc73bb
Bump jinja2 from 3.1.2 to 3.1.3 (#99)
dependabot[bot] Jan 16, 2024
e7fbcce
Using cmr-umm-updater default branch (develop)
jamesfwood Jan 16, 2024
67d63a4
use develop
jamesfwood Jan 16, 2024
6336fc5
/version 0.8.0a2
Jan 16, 2024
35c8c3c
Update CONTRIBUTING.md
frankinspace Jan 19, 2024
f9ac10c
/version 0.8.0a3
Jan 19, 2024
6d52072
Update uat_associations.txt with new collections
jonathansmolenski Jan 19, 2024
3c106cb
Update uat_associations.txt with new collections
jonathansmolenski Jan 19, 2024
a99f090
Update uat_associations.txt with new collections
jonathansmolenski Jan 19, 2024
4cfe63c
Update uat_associations.txt with new collections
jonathansmolenski Jan 19, 2024
f1cfe54
Update uat_associations.txt with new collections
jonathansmolenski Jan 19, 2024
0a38fd1
Update uat_associations.txt with new collections
jonathansmolenski Jan 19, 2024
a86899b
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
83006d4
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
8074ecc
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
f644022
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
8418f31
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
b4a42d1
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
6d02bde
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
3bbff2f
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
b3663c0
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
7549e5b
Update uat_associations.txt with new collections
jonathansmolenski Feb 6, 2024
9322713
Update uat_associations.txt with new collections
jonathansmolenski Feb 7, 2024
ba7294c
Update uat_associations.txt with new collections
jonathansmolenski Feb 7, 2024
bc6b376
Update ops_associations.txt with new collections
jonathansmolenski Feb 7, 2024
47399a9
Update ops_associations.txt with new collections
jonathansmolenski Feb 7, 2024
7c1404f
Update ops_associations.txt with new collections
jonathansmolenski Feb 7, 2024
2ab503f
Update ops_associations.txt with new collections
jonathansmolenski Feb 7, 2024
e685f55
Update uat_associations.txt with new collections
jonathansmolenski Feb 8, 2024
a1283a5
Update uat_associations.txt with new collections
jonathansmolenski Feb 8, 2024
5d9ed39
Update uat_associations.txt with new collections
jonathansmolenski Feb 8, 2024
31d1346
Update uat_associations.txt with new collections
jonathansmolenski Feb 9, 2024
854cc41
Update ops_associations.txt with new collections
jonathansmolenski Feb 9, 2024
1239557
Update ops_associations.txt with new collections
jonathansmolenski Feb 9, 2024
a749e96
Update ops_associations.txt with new collections
jonathansmolenski Feb 9, 2024
0103b4d
Update ops_associations.txt with new collections
jonathansmolenski Feb 9, 2024
23b4480
Update ops_associations.txt with new collections
jonathansmolenski Feb 9, 2024
5885e5e
Update ops_associations.txt with new collections
jonathansmolenski Feb 14, 2024
448dbc6
Update ops_associations.txt with new collections
jonathansmolenski Feb 14, 2024
1bc6eb6
Update ops_associations.txt with new collections
jonathansmolenski Feb 14, 2024
95892f2
Update ops_associations.txt with new collections
jonathansmolenski Feb 14, 2024
6fdeeb2
Issue #96: ensure the created dimension is sorted (#101)
ank1m Feb 14, 2024
643e088
/version 0.8.0a4
Feb 14, 2024
4861dcc
Merge branch 'main' into develop
Mar 1, 2024
4353bf4
/version 0.9.0a1
Mar 1, 2024
d77e96b
Bump idna from 3.4 to 3.7 (#108)
dependabot[bot] May 6, 2024
8def2fe
Bump tqdm from 4.66.1 to 4.66.3 (#109)
dependabot[bot] May 6, 2024
51cfba4
/version 0.9.0a2
May 6, 2024
19d9cdc
Bump jinja2 from 3.1.3 to 3.1.4 (#110)
dependabot[bot] May 13, 2024
826e4a8
/version 0.9.0a3
May 13, 2024
2b2ae35
Feature/cleanup tests (#112)
jamesfwood May 15, 2024
619b1b6
/version 0.9.0a4
May 15, 2024
9e4a089
add type annotations and args to docstrings (#115)
danielfromearth May 24, 2024
e9a7860
/version 0.9.0a5
May 24, 2024
bc7d9de
Merge branch 'main' into develop
Jun 10, 2024
3cea513
/version 0.10.0a1
Jun 10, 2024
0e2b72e
Bump urllib3 from 1.26.18 to 1.26.19 (#119)
dependabot[bot] Jun 27, 2024
55b3132
/version 0.10.0a2
Jun 27, 2024
3e93b87
Bump aiohttp from 3.9.5 to 3.10.2 (#127)
dependabot[bot] Aug 12, 2024
728b57c
/version 0.10.0a3
Aug 12, 2024
58aba18
Fix Merging of variables (#128)
sliu008 Aug 15, 2024
ea3a3dd
/version 0.10.0a4
Aug 15, 2024
e075f16
release 0.10.0
Aug 16, 2024
6f9dfb8
/version 0.10.0rc1
Aug 16, 2024
2dd2c50
update versions
Aug 16, 2024
726ab3f
/version 0.10.0rc2
Aug 16, 2024
90a6878
update deps
Oct 24, 2024
fee14ca
disabled some linting
Nov 7, 2024
6fd4d59
/version 0.10.0rc3
Nov 7, 2024
73ca798
deploy
Nov 7, 2024
6a2f170
/version 0.10.0rc4
Nov 7, 2024
0c52464
Feature/issue 117 improve name of output file (#121)
danielfromearth Nov 14, 2024
f667850
/version 0.10.0a5
Nov 14, 2024
cff80c1
Merge branch 'develop' into release/0.10.0
Dec 2, 2024
b6eb801
updated harmony lib version
Dec 2, 2024
ed68654
/version 0.10.0rc5
Dec 2, 2024
dcbfbb6
Feature/update error logging (#138)
sliu008 Dec 6, 2024
9ecc008
/version 0.10.0a6
Dec 6, 2024
077062c
Merge branch 'develop' into release/0.10.0
Dec 6, 2024
602dd68
renamed back to harmony
Dec 6, 2024
e0704aa
/version 0.10.0rc6
Dec 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/build-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,29 @@ jobs:
pull: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Deploy Harmony
env:
ENV: ${{ env.venue }}
CMR_USER: ${{ secrets.CMR_USER }}
CMR_PASS: ${{ secrets.CMR_PASS }}
if: |
github.ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/release')
working-directory: deployment
run:
poetry run python harmony_deploy.py --tag ${{ env.software_version }}
- name: Create Release
id: create_release
if: |
github.ref == 'refs/heads/main'
uses: softprops/action-gh-release@v2
with:
tag_name: "${{ env.software_version }}" # Use the tag that triggered the action
release_name: Release v{{ env.software_version }}
draft: false
generate_release_notes: true
token: ${{ secrets.GITHUB_TOKEN }}

# As of 2023/01/23 these steps below for scanning the Docker image with Snyk are failing. I've tried both the official Snyk
# action https://github.com/snyk/actions/tree/master/docker and this method below of manually calling the CLI.
# The error when using the official Snyk action is
Expand Down
3 changes: 2 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,8 @@ disable=raw-checker-failed,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
too-many-arguments
too-many-arguments,
too-many-positional-arguments

# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
Expand Down
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed


## [0.10.0]

### Added
- Update Github Actions
- Added harmony deployment into github actions.
### Changed
- [issue #117](https://github.com/podaac/concise/issues/117): Add part of URL to output file name
- Update python libraries
- Update harmony service lib that changed project structure
- Add Concise exception to propogate up to harmony api calls
### Deprecated
### Removed
### Fixed
- Variable Merging
- Fixed way we merge variables when granules in a collection have varying variables.


## [0.9.0]

### Added
### Changed
- Updated python libraries
- [issue #114](https://github.com/podaac/concise/issues/114): add type annotations
### Deprecated
### Removed
- Removed CMR testing. Now done in [concise-autotest](https://github.com/podaac/concise-autotest) repo
- Moved add_collection_test.py test to verify_collection.py (in concise-autotest repo)
### Fixed


## [0.9.0]

### Added
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2024 California Institute of Technology

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
67 changes: 67 additions & 0 deletions deployment/harmony_deploy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
import requests
import json
import logging
import argparse
from requests.auth import HTTPBasicAuth

# Environment variables
ENV = os.getenv('ENV')
CMR_USER = os.getenv('CMR_USER')
CMR_PASS = os.getenv('CMR_PASS')

def bearer_token() -> str:
tokens = []
headers = {'Accept': 'application/json'}
url = f"https://{'uat.' if ENV == 'uat' else ''}urs.earthdata.nasa.gov/api/users"

# First just try to get a token that already exists
try:
resp = requests.get(url + "/tokens", headers=headers, auth=HTTPBasicAuth(CMR_USER, CMR_PASS))
response_content = json.loads(resp.content)

for x in response_content:
tokens.append(x['access_token'])

except Exception: # noqa E722
logging.warning("Error getting the token - check user name and password", exc_info=True)

# No tokens exist, try to create one
if not tokens:
try:
resp = requests.post(url + "/token", headers=headers, auth=HTTPBasicAuth(CMR_USER, CMR_PASS))
response_content = json.loads(resp.content)
tokens.append(response_content['access_token'])
except Exception: # noqa E722
logging.warning("Error getting the token - check user name and password", exc_info=True)

# If still no token, then we can't do anything
if not tokens:
raise RuntimeError("Unable to get bearer token from EDL")

return next(iter(tokens))

if __name__ == "__main__":

parser = argparse.ArgumentParser(description="Update the service image tag.")
parser.add_argument("--tag", help="The new tag version to update.", required=True)
args = parser.parse_args()

url = f"https://harmony.{'uat.' if ENV == 'uat' else ''}earthdata.nasa.gov/service-image-tag/podaac-concise"
token = bearer_token()

headers = {
"Authorization": f"Bearer {token}",
"Content-type": "application/json"
}
data = {
"tag": args.tag
}

response = requests.put(url, headers=headers, json=data)

print(response.status_code)
try:
print(response.json())
except json.JSONDecodeError:
print("Response content is not in JSON format")
2 changes: 1 addition & 1 deletion podaac/merger/harmony/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""A Harmony CLI wrapper around Concise"""

from argparse import ArgumentParser
import harmony
import harmony_service_lib as harmony
from podaac.merger.harmony.service import ConciseService


Expand Down
4 changes: 2 additions & 2 deletions podaac/merger/harmony/download_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import re
from urllib.parse import urlparse

from harmony.logging import build_logger
from harmony.util import download
from harmony_service_lib.logging import build_logger
from harmony_service_lib.util import download


def multi_core_download(urls, destination_dir, access_token, cfg, process_count=None):
Expand Down
150 changes: 96 additions & 54 deletions podaac/merger/harmony/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
from shutil import copyfile
from urllib.parse import urlsplit
from uuid import uuid4
import traceback
import sys

from harmony.adapter import BaseHarmonyAdapter
from harmony.util import bbox_to_geometry, stage
from harmony_service_lib.adapter import BaseHarmonyAdapter
from harmony_service_lib.util import bbox_to_geometry, stage
from harmony_service_lib.exceptions import HarmonyException
from pystac import Catalog, Item
from pystac.item import Asset

Expand All @@ -20,6 +23,37 @@
NETCDF4_MIME = 'application/x-netcdf4' # pylint: disable=invalid-name


class ConciseException(HarmonyException):
"""Concise Exception class for custom error messages to see in harmony api calls."""
def __init__(self, original_exception):
# Ensure we can extract traceback information
if original_exception.__traceback__ is None:
# Capture the current traceback if not already present
try:
raise original_exception
except type(original_exception):
original_exception.__traceback__ = sys.exc_info()[2]

# Extract the last traceback entry (most recent call) for the error location
tb = traceback.extract_tb(original_exception.__traceback__)[-1]

# Get the error details: file, line, function, and message
filename = tb.filename
lineno = tb.lineno
funcname = tb.name
error_msg = str(original_exception)

# Format the error message to be more readable
readable_message = (f"Error in file '{filename}', line {lineno}, in function '{funcname}': "
f"{error_msg}")

# Call the parent class constructor with the formatted message and category
super().__init__(readable_message, 'podaac/concise')

# Store the original exception for potential further investigation
self.original_exception = original_exception


class ConciseService(BaseHarmonyAdapter):
"""
A harmony-service-lib wrapper around the Concise module. This wrapper does
Expand All @@ -32,7 +66,7 @@ def invoke(self):
Primary entrypoint into the service wrapper. Overrides BaseHarmonyAdapter.invoke
"""
if not self.catalog:
# Message-only support is being depreciated in Harmony so we should expect to
# Message-only support is being depreciated in Harmony, so we should expect to
# only see requests with catalogs when invoked with a newer Harmony instance
# https://github.com/nasa/harmony-service-lib-py/blob/21bcfbda17caf626fb14d2ac4f8673be9726b549/harmony/adapter.py#L71
raise RuntimeError('Invoking CONCISE without a STAC catalog is not supported')
Expand All @@ -42,7 +76,7 @@ def invoke(self):
def process_catalog(self, catalog: Catalog):
"""
Recursively process a catalog and all its children. Adapted from
BaseHarmonyAdapter._process_catalog_recursive to specfifically
BaseHarmonyAdapter._process_catalog_recursive to specifically
support our particular use case for many-to-one

Parameters
Expand All @@ -55,60 +89,68 @@ def process_catalog(self, catalog: Catalog):
pystac.Catalog
A new catalog containing the results from the merge
"""
result = catalog.clone()
result.id = str(uuid4())
result.clear_children()

# Get all the items from the catalog, including from child or linked catalogs
items = list(self.get_all_catalog_items(catalog))
try:
result = catalog.clone()
result.id = str(uuid4())
result.clear_children()

# Get all the items from the catalog, including from child or linked catalogs
items = list(self.get_all_catalog_items(catalog))

# Quick return if catalog contains no items
if len(items) == 0:
return result

# -- Process metadata --
bbox = []
granule_urls = []
datetimes = [
datetime.max.replace(tzinfo=timezone.utc), # start
datetime.min.replace(tzinfo=timezone.utc) # end
]

for item in items:
get_bbox(item, bbox)
get_granule_url(item, granule_urls)
get_datetime(item, datetimes)

# Items did not have a bbox; valid under spec
if len(bbox) == 0:
bbox = None

# -- Perform merging --
collection = self._get_item_source(items[0]).collection
first_granule_url = []
get_granule_url(items[0], first_granule_url)
first_url_name = Path(first_granule_url[0]).stem
filename = f'{first_url_name}_{datetimes[1].strftime("%Y%m%dT%H%M%SZ")}_{collection}_merged.nc4'

with TemporaryDirectory() as temp_dir:
self.logger.info('Starting granule downloads')
input_files = multi_core_download(granule_urls, temp_dir, self.message.accessToken, self.config)
self.logger.info('Finished granule downloads')

output_path = Path(temp_dir).joinpath(filename).resolve()
merge_netcdf_files(input_files, output_path, granule_urls, logger=self.logger)
staged_url = self._stage(str(output_path), filename, NETCDF4_MIME)

# -- Output to STAC catalog --
result.clear_items()
properties = {
"start_datetime": datetimes[0].isoformat(),
"end_datetime": datetimes[1].isoformat()
}

item = Item(str(uuid4()), bbox_to_geometry(bbox), bbox, None, properties)
asset = Asset(staged_url, title=filename, media_type=NETCDF4_MIME, roles=['data'])
item.add_asset('data', asset)
result.add_item(item)

# Quick return if catalog contains no items
if len(items) == 0:
return result

# -- Process metadata --
bbox = []
granule_urls = []
datetimes = [
datetime.max.replace(tzinfo=timezone.utc), # start
datetime.min.replace(tzinfo=timezone.utc) # end
]

for item in items:
get_bbox(item, bbox)
get_granule_url(item, granule_urls)
get_datetime(item, datetimes)

# Items did not have a bbox; valid under spec
if len(bbox) == 0:
bbox = None

# -- Perform merging --
collection = self._get_item_source(items[0]).collection
filename = f'{collection}_merged.nc4'

with TemporaryDirectory() as temp_dir:
self.logger.info('Starting granule downloads')
input_files = multi_core_download(granule_urls, temp_dir, self.message.accessToken, self.config)
self.logger.info('Finished granule downloads')

output_path = Path(temp_dir).joinpath(filename).resolve()
merge_netcdf_files(input_files, output_path, granule_urls, logger=self.logger)
staged_url = self._stage(str(output_path), filename, NETCDF4_MIME)

# -- Output to STAC catalog --
result.clear_items()
properties = {
"start_datetime": datetimes[0].isoformat(),
"end_datetime": datetimes[1].isoformat()
}

item = Item(str(uuid4()), bbox_to_geometry(bbox), bbox, None, properties)
asset = Asset(staged_url, title=filename, media_type=NETCDF4_MIME, roles=['data'])
item.add_asset('data', asset)
result.add_item(item)

return result
except Exception as ex:
raise ConciseException(ex) from ex

def _stage(self, local_filename, remote_filename, mime):
"""
Expand Down
2 changes: 1 addition & 1 deletion podaac/merger/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def is_file_empty(parent_group: nc.Dataset | nc.Group) -> bool:
return True


def merge_netcdf_files(original_input_files: list[Path], # pylint: disable=too-many-locals
def merge_netcdf_files(original_input_files: list[Path], # pylint: disable=too-many-locals,too-many-positional-arguments
output_file: str,
granule_urls,
logger=getLogger(__name__),
Expand Down
1 change: 1 addition & 0 deletions podaac/merger/merge_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def max_var_memory(file_list: list[Path], var_info: dict, max_dims) -> int:
return max_var_mem


# pylint: disable=too-many-positional-arguments
def run_merge(merged_dataset: nc.Dataset,
file_list: list[Path],
var_info: dict,
Expand Down
Loading