From d432633b69d5fc64fc3baf0e1c65ad49a6f8b4ce Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Thu, 13 Nov 2025 08:37:06 -0500 Subject: [PATCH 01/12] Update Requirements --- lambda_function/padre-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lambda_function/padre-requirements.txt b/lambda_function/padre-requirements.txt index 8f55b4b..af4f80f 100755 --- a/lambda_function/padre-requirements.txt +++ b/lambda_function/padre-requirements.txt @@ -2,4 +2,5 @@ sdc_aws_utils @ git+https://github.com/swxsoc/sdc_aws_utils.git metatracker @ git+https://github.com/swxsoc/MetaTracker.git padre_meddea @ git+https://github.com/PADRESat/padre_meddea.git padre_sharp @ git+https://github.com/PADRESat/padre_sharp.git +padre_craft @ git+https://github.com/PADRESat/padre_craft.git tenacity==9.1.2 \ No newline at end of file From 846060bd6ea0b8e9c526418965167655aa9ca187 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Thu, 13 Nov 2025 10:49:38 -0500 Subject: [PATCH 02/12] Add Details for Testing with Private Codebase --- README.md | 37 +++++++++++++++++-- lambda_function/Dockerfile | 4 ++ .../src/file_processor/file_processor.py | 36 ++++++++++-------- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b1dcc11..7c72d4f 100755 --- a/README.md +++ b/README.md @@ -13,11 +13,42 @@ The container will contain the latest release code as the production environment ### **Testing Locally (Using own Test Data)**: 1. Build the lambda container image (from within the lambda_function folder) you'd like to test: - `docker build -t processing_function:latest . --no-cache` +```sh +docker build -t processing_function:latest . --no-cache +``` + +**Note**: For Private Instrument Packages, you will need to pass in a GitHub Token as a build argument: + +```sh +docker build \ + --build-arg BASE_IMAGE=$BASE_IMAGE \ # Optional: specify base image + --build-arg REQUIREMENTS_FILE=$REQUIREMENTS_FILE \ # Optional: specify requirements file + --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \ # GitHub Personal Access Token for private repo access + -t sdc_aws_processing_lambda:latest . \ + --network host +``` 2. Run the lambda container image you've built, this will start the lambda runtime environment: - `docker run -p 9000:8080 -v :/test_data -e SDC_AWS_FILE_PATH=/test_data/ processing_function:latest` +```sh +docker run \ + -p 9000:8080 \ + -v :/test_data \ + -e SDC_AWS_FILE_PATH=/test_data/ \ + processing_function:latest` +``` + +**Note**: Again, for Private Instrument Packages, you will need to pass in a GitHub Token as an environment variable: + +```sh +docker run \ + -p 9000:8080 \ + -v :/test_data \ + -e SDC_AWS_FILE_PATH=/test_data/ \ + -e SWXSOC_MISSION=padre \ # Specify mission for instrument package + -e GITHUB_TOKEN=$GITHUB_TOKEN \ # GitHub Personal Access Token for + processing_function:latest +``` 3. From a `separate` terminal, make a curl request to the running lambda function: @@ -50,4 +81,4 @@ The container will contain the latest release code as the production environment ### **How this Lambda Function is deployed** -This lambda function is part of the main SWxSOC Pipeline ([Architecture Repo Link](https://github.com/HERMES-SOC/sdc_aws_pipeline_architecture)). It is deployed via AWS Codebuild within that repository. It is first built and tagged within the appropriate production or development repository (depending if it is a release or commit). View the Codebuild CI/CD file [here](buildspec.yml). \ No newline at end of file +This lambda function is part of the main SWxSOC Pipeline ([Architecture Repo Link](https://github.com/swxsoc/sdc_aws_architecture)). It is deployed via AWS Codebuild within that repository. It is first built and tagged within the appropriate production or development repository (depending if it is a release or commit). View the Codebuild CI/CD file [here](buildspec.yml). \ No newline at end of file diff --git a/lambda_function/Dockerfile b/lambda_function/Dockerfile index 407d0f6..6534cc2 100755 --- a/lambda_function/Dockerfile +++ b/lambda_function/Dockerfile @@ -7,6 +7,10 @@ FROM ${BASE_IMAGE} ARG ROOT="/" ARG FUNCTION_DIR="/lambda_function/" +# Set GitHub Token for private repo access +ARG GITHUB_TOKEN +RUN git config --global credential.helper '!f() { echo username=x-oauth-basic; echo password=$GITHUB_TOKEN; }; f' + # Set default values for requirements file ARG REQUIREMENTS_FILE="hermes-requirements.txt" diff --git a/lambda_function/src/file_processor/file_processor.py b/lambda_function/src/file_processor/file_processor.py index 054e18e..067e53f 100755 --- a/lambda_function/src/file_processor/file_processor.py +++ b/lambda_function/src/file_processor/file_processor.py @@ -65,6 +65,7 @@ def handle_event(event, context) -> dict: for s3_event in records: s3_bucket = s3_event["s3"]["bucket"]["name"] file_key = s3_event["s3"]["object"]["key"] + log.info(f"Processing for File Key: {file_key} in Bucket: {s3_bucket}") FileProcessor( s3_bucket=s3_bucket, file_key=file_key, environment=environment @@ -260,14 +261,17 @@ def _calibrate_file(instrument, file_path, dry_run=False): fromlist=["data"], ) # Get all files in test data directory - test_data_dir = Path(instr_pkg_data.__path__[0]) + test_data_dir = Path(instr_pkg_data.__path__[0]) / "test" + log.info(f"Test data directory: {test_data_dir}") test_data_files = list(test_data_dir.glob("**/*")) log.info(f"Found {len(test_data_files)} files in test data directory") log.info(f"Using {test_data_files} as test data") - # Get any files ending in .bin or .cdf and calibrate them + # Stub path list for calibrated files + path_list = [] + # Loop the test data files for calibration for test_data_file in test_data_files: - if test_data_file.suffix in [".bin", ".cdf", ".fits"]: - log.info(f"Calibrating {test_data_file}") + if test_data_file.suffix in [".bin", ".cdf", ".fits", ".csv"]: + log.info(f"Calibrating {test_data_file.name}") # Make /test_data directory if it doesn't exist Path("/test_data").mkdir(parents=True, exist_ok=True) # Copy file to /test_data directory using shutil @@ -275,18 +279,20 @@ def _calibrate_file(instrument, file_path, dry_run=False): file_path = Path(f"/test_data/{test_data_file_path.name}") shutil.copy(test_data_file_path, file_path) # Calibrate file - calibrated_filename = calibration.process_file(file_path)[0] - # Copy calibrated file to test data directory - calibrated_file_path = Path(calibrated_filename) - # Return name of calibrated file - log.info(f"Calibrated file saved as {calibrated_file_path}") + files_list = calibration.process_file(file_path) + + if len(files_list) == 0: + log.warning(f"No calibrated files generated for {file_path}") + continue + for generated_file in files_list: + # Copy calibrated file to test data directory + calibrated_file_path = Path(generated_file) + # Return name of calibrated file + log.info(f"Calibrated file saved as {calibrated_file_path}") + path_list.append(calibrated_file_path.name) + # Return list of calibrated files + return path_list - return calibrated_filename - - # If no files ending in .bin or .cdf are found, raise an error - raise FileNotFoundError( - "No files ending in .bin or .cdf found in test data directory" - ) log.info(f"Calibrating {file_path}") # Get name of new file files_list = calibration.process_file(Path(file_path)) From ff5dc8432440d77fa3d1eecea4a6a094be7ce04e Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:15:42 -0500 Subject: [PATCH 03/12] Remove Reference for Private Repos --- README.md | 24 ++++-------------------- lambda_function/Dockerfile | 4 ---- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 7c72d4f..ac53c4b 100755 --- a/README.md +++ b/README.md @@ -13,17 +13,10 @@ The container will contain the latest release code as the production environment ### **Testing Locally (Using own Test Data)**: 1. Build the lambda container image (from within the lambda_function folder) you'd like to test: -```sh -docker build -t processing_function:latest . --no-cache -``` - -**Note**: For Private Instrument Packages, you will need to pass in a GitHub Token as a build argument: - ```sh docker build \ --build-arg BASE_IMAGE=$BASE_IMAGE \ # Optional: specify base image --build-arg REQUIREMENTS_FILE=$REQUIREMENTS_FILE \ # Optional: specify requirements file - --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \ # GitHub Personal Access Token for private repo access -t sdc_aws_processing_lambda:latest . \ --network host ``` @@ -35,25 +28,16 @@ docker run \ -p 9000:8080 \ -v :/test_data \ -e SDC_AWS_FILE_PATH=/test_data/ \ - processing_function:latest` + sdc_aws_processing_lambda:latest` ``` -**Note**: Again, for Private Instrument Packages, you will need to pass in a GitHub Token as an environment variable: +3. From a `separate` terminal, make a curl request to the running lambda function: ```sh -docker run \ - -p 9000:8080 \ - -v :/test_data \ - -e SDC_AWS_FILE_PATH=/test_data/ \ - -e SWXSOC_MISSION=padre \ # Specify mission for instrument package - -e GITHUB_TOKEN=$GITHUB_TOKEN \ # GitHub Personal Access Token for - processing_function:latest +curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" \ + -d @lambda_function/tests/test_data/test_eea_event.json ``` -3. From a `separate` terminal, make a curl request to the running lambda function: - - `curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d @lambda_function/tests/test_data/test_eea_event.json` - 4. Close original terminal running the docker image. 5. Clean up dangling images and containers: diff --git a/lambda_function/Dockerfile b/lambda_function/Dockerfile index 6534cc2..407d0f6 100755 --- a/lambda_function/Dockerfile +++ b/lambda_function/Dockerfile @@ -7,10 +7,6 @@ FROM ${BASE_IMAGE} ARG ROOT="/" ARG FUNCTION_DIR="/lambda_function/" -# Set GitHub Token for private repo access -ARG GITHUB_TOKEN -RUN git config --global credential.helper '!f() { echo username=x-oauth-basic; echo password=$GITHUB_TOKEN; }; f' - # Set default values for requirements file ARG REQUIREMENTS_FILE="hermes-requirements.txt" From fb52f41dc422275ad0db095a9ab87c8f14448a43 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:16:49 -0500 Subject: [PATCH 04/12] Update Processing to support None returns --- .../src/file_processor/file_processor.py | 189 ++++++++++-------- 1 file changed, 110 insertions(+), 79 deletions(-) diff --git a/lambda_function/src/file_processor/file_processor.py b/lambda_function/src/file_processor/file_processor.py index 067e53f..6a4bf13 100755 --- a/lambda_function/src/file_processor/file_processor.py +++ b/lambda_function/src/file_processor/file_processor.py @@ -12,6 +12,7 @@ from itertools import combinations import shutil import traceback +from typing import Tuple import swxsoc @@ -165,10 +166,10 @@ def _process_file(self) -> None: ) FileProcessor._track_file_metatracker( - science_filename_parser, - Path(file_path), - self.file_key, - self.instrument_bucket_name, + science_filename_parser=science_filename_parser, + file_path=Path(file_path), + s3_key=self.file_key, + s3_bucket=self.instrument_bucket_name, status=status, ) @@ -187,11 +188,12 @@ def _process_file(self) -> None: total_time=total_time, ) + # Track the original science file as processed successfully science_file_id, science_product_id = FileProcessor._track_file_metatracker( - science_filename_parser, - Path(file_path), - self.file_key, - self.instrument_bucket_name, + science_filename_parser=science_filename_parser, + file_path=Path(file_path), + s3_key=self.file_key, + s3_bucket=self.instrument_bucket_name, status=status, ) @@ -204,6 +206,10 @@ def _process_file(self) -> None: } ) + # Filter out None values from calibrated filenames + calibrated_filenames = [ + fname for fname in calibrated_filenames if fname is not None + ] # Push file to S3 Bucket for calibrated_filename in calibrated_filenames: status = self.build_status( @@ -221,11 +227,11 @@ def _process_file(self) -> None: # Track the calibrated file in the CDF Tracker self._track_file_metatracker( - science_filename_parser, - Path("/tmp") / calibrated_filename, - calibrated_filename, - destination_bucket, - science_product_id, + science_filename_parser=science_filename_parser, + file_path=Path("/tmp") / calibrated_filename, + s3_key=calibrated_filename, + s3_bucket=destination_bucket, + science_product_id=science_product_id, status=status, ) @@ -280,9 +286,11 @@ def _calibrate_file(instrument, file_path, dry_run=False): shutil.copy(test_data_file_path, file_path) # Calibrate file files_list = calibration.process_file(file_path) - + if len(files_list) == 0: - log.warning(f"No calibrated files generated for {file_path}") + log.warning( + f"No calibrated files generated for {file_path}" + ) continue for generated_file in files_list: # Copy calibrated file to test data directory @@ -299,10 +307,15 @@ def _calibrate_file(instrument, file_path, dry_run=False): path_list = [] for generated_file in files_list: - new_file_path = Path(generated_file) - calibrated_filename = new_file_path.name - path_list.append(calibrated_filename) - log.info(f"Calibrated file saved as {calibrated_filename}") + if generated_file is not None: + new_file_path = Path(generated_file) + calibrated_filename = new_file_path.name + path_list.append(calibrated_filename) + log.info(f"Calibrated file saved as {calibrated_filename}") + else: + # We want to pass-through None values to indicate no file was created + path_list.append(None) + log.warning(f"'None' file generated for {file_path}") return path_list @@ -342,84 +355,102 @@ def _calibrate_file(instrument, file_path, dry_run=False): reraise=True, ) def _track_file_metatracker( - science_filename_parser, - file_path, - s3_key, - s3_bucket, - science_product_id=None, - status=None, - ) -> int: + science_filename_parser: callable, + file_path: Path, + s3_key: str, + s3_bucket: str, + science_product_id: int = None, + status: dict = None, + ) -> Tuple[int, int]: """ - Tracks processed science product in the CDF Tracker file database. + Tracks processed science product in the File Metadata tracker database. It involves initializing the database engine, setting up database tables, and tracking both the original and processed files. - :param science_filename_parser: The parser function to process file names. - :type science_filename_parser: function - :param file_path: The path of the original file. - :type file_path: Path + Parameters + ---------- + science_filename_parser : function + The parser function to process file names. + file_path : Path + The path of the file in the filesystem. + s3_key : str + The S3 key of the file. + s3_bucket : str + The S3 bucket of the file. + science_product_id : int, optional + The ID of the science product, by default None. + status : dict, optional + The status dictionary for tracking, by default None. + + Returns + ------- + Tuple[int, int] + A tuple containing the science file ID and science product ID. """ secret_arn = os.getenv("RDS_SECRET_ARN", None) - if secret_arn: - try: - # Validate file path - if not file_path or not isinstance(file_path, Path): - raise ValueError("Invalid file path provided.") - # Check if file exists - if not file_path.exists(): - raise FileNotFoundError(f"File not found: {file_path}") - - # Get Database Credentials - session = boto3.session.Session() - client = session.client(service_name="secretsmanager") - response = client.get_secret_value(SecretId=secret_arn) - secret = json.loads(response["SecretString"]) - connection_string = ( - f"postgresql://{secret['username']}:{secret['password']}@" - f"{secret['host']}:{secret['port']}/{secret['dbname']}" - ) + if not secret_arn: + log.error( + f"Failed to update MetaTracker for file {file_path}. No RDS Secret ARN found in environment variables." + ) + return None, None + + try: + # Validate file path + if not file_path or not isinstance(file_path, Path): + raise ValueError("Invalid file path provided.") + # Check if file exists + if not file_path.exists(): + raise FileNotFoundError(f"File not found: {file_path}") + + # Get Database Credentials + session = boto3.session.Session() + client = session.client(service_name="secretsmanager") + response = client.get_secret_value(SecretId=secret_arn) + secret = json.loads(response["SecretString"]) + connection_string = ( + f"postgresql://{secret['username']}:{secret['password']}@" + f"{secret['host']}:{secret['port']}/{secret['dbname']}" + ) - metatracker_config = FileProcessor.get_metatracker_config(swxsoc.config) + metatracker_config = FileProcessor.get_metatracker_config(swxsoc.config) - log.debug(swxsoc.config) + log.debug(swxsoc.config) - log.debug(metatracker_config) + log.debug(metatracker_config) - metatracker.set_config(metatracker_config) + metatracker.set_config(metatracker_config) - from metatracker.database import create_engine - from metatracker.database.tables import create_tables - from metatracker.tracker import tracker + from metatracker.database import create_engine + from metatracker.database.tables import create_tables + from metatracker.tracker import tracker - # Initialize the database engine - database_engine = create_engine(connection_string) + # Initialize the database engine + database_engine = create_engine(connection_string) - # Create tables if they do not exist - create_tables(database_engine) + # Create tables if they do not exist + create_tables(database_engine) - # Set tracker to MetaTracker - meta_tracker = tracker.MetaTracker( - database_engine, science_filename_parser - ) + # Set tracker to MetaTracker + meta_tracker = tracker.MetaTracker(database_engine, science_filename_parser) - if meta_tracker: - science_file_id, science_product_id = meta_tracker.track( - file_path, s3_key, s3_bucket, status=status - ) + if meta_tracker: + science_file_id, science_product_id = meta_tracker.track( + file_path, s3_key, s3_bucket, status=status + ) - return science_file_id, science_product_id + return science_file_id, science_product_id - return None + return None, None - except Exception as e: - log.error( - { - "status": "ERROR", - "message": str(e), - "traceback": traceback.format_exc(), - } - ) - return None + except Exception as e: + log.error( + { + "status": "ERROR", + "message": str(e), + "traceback": traceback.format_exc(), + } + ) + return None, None @staticmethod def get_metatracker_config(swxsoc_config: dict) -> dict: From c83750fcf50038394a7ae22952f75bc2ff44cf00 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:19:24 -0500 Subject: [PATCH 05/12] Clean up Log Statements --- lambda_function/src/file_processor/file_processor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lambda_function/src/file_processor/file_processor.py b/lambda_function/src/file_processor/file_processor.py index 6a4bf13..3262406 100755 --- a/lambda_function/src/file_processor/file_processor.py +++ b/lambda_function/src/file_processor/file_processor.py @@ -66,7 +66,6 @@ def handle_event(event, context) -> dict: for s3_event in records: s3_bucket = s3_event["s3"]["bucket"]["name"] file_key = s3_event["s3"]["object"]["key"] - log.info(f"Processing for File Key: {file_key} in Bucket: {s3_bucket}") FileProcessor( s3_bucket=s3_bucket, file_key=file_key, environment=environment From bdae6aac455d55fc38277c0491ea4f10054d387a Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:26:59 -0500 Subject: [PATCH 06/12] Formatting --- lambda_function/src/file_processor/file_processor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lambda_function/src/file_processor/file_processor.py b/lambda_function/src/file_processor/file_processor.py index 3262406..b8f837e 100755 --- a/lambda_function/src/file_processor/file_processor.py +++ b/lambda_function/src/file_processor/file_processor.py @@ -183,7 +183,7 @@ def _process_file(self) -> None: # If calibrated files are found, set status to success status = self.build_status( status=Status.SUCCESS, - message=f"File Processed Successfully", + message="File Processed Successfully", total_time=total_time, ) @@ -312,7 +312,7 @@ def _calibrate_file(instrument, file_path, dry_run=False): path_list.append(calibrated_filename) log.info(f"Calibrated file saved as {calibrated_filename}") else: - # We want to pass-through None values to indicate no file was created + # Pass-through None values to indicate no file was created path_list.append(None) log.warning(f"'None' file generated for {file_path}") @@ -389,7 +389,8 @@ def _track_file_metatracker( secret_arn = os.getenv("RDS_SECRET_ARN", None) if not secret_arn: log.error( - f"Failed to update MetaTracker for file {file_path}. No RDS Secret ARN found in environment variables." + f"Failed to update MetaTracker for file {file_path}. ", + "No RDS Secret ARN found in environment variables." ) return None, None From 02968580dfee101367d02cd6a1c660e605f9cb20 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:27:26 -0500 Subject: [PATCH 07/12] Formatting --- lambda_function/src/file_processor/file_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda_function/src/file_processor/file_processor.py b/lambda_function/src/file_processor/file_processor.py index b8f837e..46e4aa5 100755 --- a/lambda_function/src/file_processor/file_processor.py +++ b/lambda_function/src/file_processor/file_processor.py @@ -390,7 +390,7 @@ def _track_file_metatracker( if not secret_arn: log.error( f"Failed to update MetaTracker for file {file_path}. ", - "No RDS Secret ARN found in environment variables." + "No RDS Secret ARN found in environment variables.", ) return None, None From a2abf038d7f821c1095ed1f3964afd3aa76a1087 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:16:07 -0500 Subject: [PATCH 08/12] Update Processing for Local Files & Update Actions Workflow --- .github/workflows/calibration.yml | 17 ++++++++++++++--- .../src/file_processor/file_processor.py | 19 ++++++++++++------- ...S_APP_Data_1761936771334_1762106179414.csv | 11 +++++++++++ .../tests/test_data/test_craft_event.json | 15 +++++++++++++++ 4 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 lambda_function/tests/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_APP_Data_1761936771334_1762106179414.csv create mode 100644 lambda_function/tests/test_data/test_craft_event.json diff --git a/.github/workflows/calibration.yml b/.github/workflows/calibration.yml index ff3f24f..0b8ed5b 100644 --- a/.github/workflows/calibration.yml +++ b/.github/workflows/calibration.yml @@ -15,11 +15,22 @@ jobs: - name: Build Lambda Docker Image run: | cd lambda_function - docker build -t processing_function:latest . + export BASE_IMAGE=public.ecr.aws/w5r9l1c8/dev-padre-swsoc-docker-lambda-base:latest + export REQUIREMENTS_FILE=padre-requirements.txt + docker build \ + --build-arg BASE_IMAGE=$BASE_IMAGE \ + --build-arg REQUIREMENTS_FILE=$REQUIREMENTS_FILE \ + -t processing_function:latest . - name: Run Lambda Docker Container run: | - docker run -d --name processing_lambda -p 9000:8080 -e USE_INSTRUMENT_TEST_DATA=True -e SWXSOC_MISSION=hermes processing_function:latest + docker run -d \ + --name processing_lambda \ + -p 9000:8080 \ + -v lambda_function/tests/test_data/:/test_data \ + -e SWXSOC_MISSION=padre \ + -e SDC_AWS_FILE_PATH=/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_COMMON_Data_1762004752547_1762005892626.csv \ + processing_function:latest container_id=$(docker ps -qf "ancestor=processing_function:latest") echo "Container ID: $container_id" @@ -30,7 +41,7 @@ jobs: id: test-lambda run: | # Run curl and write the HTTP status code to a variable - HTTP_STATUS=$(curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d @lambda_function/tests/test_data/test_eea_event.json) + HTTP_STATUS=$(curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d @lambda_function/tests/test_data/test_craft_event.json) echo "HTTP Status: $HTTP_STATUS" # Grep the HTTP status code from the curl output for 200 (success) diff --git a/lambda_function/src/file_processor/file_processor.py b/lambda_function/src/file_processor/file_processor.py index 46e4aa5..0b295e0 100755 --- a/lambda_function/src/file_processor/file_processor.py +++ b/lambda_function/src/file_processor/file_processor.py @@ -292,11 +292,17 @@ def _calibrate_file(instrument, file_path, dry_run=False): ) continue for generated_file in files_list: - # Copy calibrated file to test data directory - calibrated_file_path = Path(generated_file) - # Return name of calibrated file - log.info(f"Calibrated file saved as {calibrated_file_path}") - path_list.append(calibrated_file_path.name) + if generated_file is not None: + new_file_path = Path(generated_file) + calibrated_filename = new_file_path.name + path_list.append(calibrated_filename) + log.info( + f"Calibrated file saved as {calibrated_filename}" + ) + else: + # Pass-through None values to indicate no file was created + path_list.append(None) + log.warning(f"'None' file generated for {file_path}") # Return list of calibrated files return path_list @@ -389,8 +395,7 @@ def _track_file_metatracker( secret_arn = os.getenv("RDS_SECRET_ARN", None) if not secret_arn: log.error( - f"Failed to update MetaTracker for file {file_path}. ", - "No RDS Secret ARN found in environment variables.", + f"Failed to update MetaTracker for file {file_path}. No RDS Secret ARN found in environment variables.", ) return None, None diff --git a/lambda_function/tests/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_APP_Data_1761936771334_1762106179414.csv b/lambda_function/tests/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_APP_Data_1761936771334_1762106179414.csv new file mode 100644 index 0000000..2af908a --- /dev/null +++ b/lambda_function/tests/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_APP_Data_1761936771334_1762106179414.csv @@ -0,0 +1,11 @@ +run_mode,control_mode,magnetic_control_timeout,estimator_main,estimator_backup,adcs_op_state,timestamp_ms +1,12,65535,6,1,0,1762106119422 +1,12,65535,6,1,0,1762106179414 +1,12,65535,6,1,0,1761936771334 +1,12,65535,6,1,0,1761936831407 +1,12,65535,6,1,0,1761936891419 +1,12,65535,6,1,0,1761936951483 +1,12,65535,6,1,0,1761937011552 +1,12,65535,6,1,0,1761937071617 +1,12,65535,6,1,0,1761937131524 +1,12,65535,6,1,0,1761937191508 \ No newline at end of file diff --git a/lambda_function/tests/test_data/test_craft_event.json b/lambda_function/tests/test_data/test_craft_event.json new file mode 100644 index 0000000..2a63504 --- /dev/null +++ b/lambda_function/tests/test_data/test_craft_event.json @@ -0,0 +1,15 @@ +{ + "Records": [ + { + "Sns": { + "Message": "{\r\n \"Records\": [\r\n {\r\n \"eventSource\": \"aws:s3\",\r\n \"awsRegion\": \"us-east-1\",\r\n \"eventTime\": \"2025-11-13T14:14:10.000Z\",\r\n \"eventName\": \"ObjectCreated:Put\",\r\n \"s3\": {\r\n \"bucket\": {\r\n \"name\": \"dev-padre-craft\"\r\n },\r\n \"object\": {\r\n \"key\": \"padre_get_CUBEADCS_GEN2_OP_STATUS_COMMON_Data_1762004752547_1762005892626.csv\",\r\n \"size\": 1485,\r\n \"eTag\": \"32d82e8a2e72af004c557c4e369e89ff\",\r\n \"sequencer\": \"0062DE63CC330B223E\"\r\n }\r\n }\r\n }\r\n ]\r\n}", + "MessageAttributes": { + "Test": { + "Type": "String", + "Value": "TestString" + } + } + } + } + ] +} From 0ea0ad70a64202accb2f0f59d314cceae25819b8 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:21:14 -0500 Subject: [PATCH 09/12] Update Volumne Mount in Workflow --- .github/workflows/calibration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/calibration.yml b/.github/workflows/calibration.yml index 0b8ed5b..fb4d3d6 100644 --- a/.github/workflows/calibration.yml +++ b/.github/workflows/calibration.yml @@ -27,7 +27,7 @@ jobs: docker run -d \ --name processing_lambda \ -p 9000:8080 \ - -v lambda_function/tests/test_data/:/test_data \ + -v $PWD/lambda_function/tests/test_data/:/test_data \ -e SWXSOC_MISSION=padre \ -e SDC_AWS_FILE_PATH=/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_COMMON_Data_1762004752547_1762005892626.csv \ processing_function:latest From 7319d359cdf1f53a6bb4401e69bf542aed38c367 Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:27:07 -0500 Subject: [PATCH 10/12] Update Filename --- lambda_function/tests/test_data/test_craft_event.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lambda_function/tests/test_data/test_craft_event.json b/lambda_function/tests/test_data/test_craft_event.json index 2a63504..0e2755d 100644 --- a/lambda_function/tests/test_data/test_craft_event.json +++ b/lambda_function/tests/test_data/test_craft_event.json @@ -2,7 +2,7 @@ "Records": [ { "Sns": { - "Message": "{\r\n \"Records\": [\r\n {\r\n \"eventSource\": \"aws:s3\",\r\n \"awsRegion\": \"us-east-1\",\r\n \"eventTime\": \"2025-11-13T14:14:10.000Z\",\r\n \"eventName\": \"ObjectCreated:Put\",\r\n \"s3\": {\r\n \"bucket\": {\r\n \"name\": \"dev-padre-craft\"\r\n },\r\n \"object\": {\r\n \"key\": \"padre_get_CUBEADCS_GEN2_OP_STATUS_COMMON_Data_1762004752547_1762005892626.csv\",\r\n \"size\": 1485,\r\n \"eTag\": \"32d82e8a2e72af004c557c4e369e89ff\",\r\n \"sequencer\": \"0062DE63CC330B223E\"\r\n }\r\n }\r\n }\r\n ]\r\n}", + "Message": "{\r\n \"Records\": [\r\n {\r\n \"eventSource\": \"aws:s3\",\r\n \"awsRegion\": \"us-east-1\",\r\n \"eventTime\": \"2025-11-13T14:14:10.000Z\",\r\n \"eventName\": \"ObjectCreated:Put\",\r\n \"s3\": {\r\n \"bucket\": {\r\n \"name\": \"dev-padre-craft\"\r\n },\r\n \"object\": {\r\n \"key\": \"padre_get_CUBEADCS_GEN2_OP_STATUS_APP_Data_1761936771334_1762106179414.csv\",\r\n \"size\": 1485,\r\n \"eTag\": \"32d82e8a2e72af004c557c4e369e89ff\",\r\n \"sequencer\": \"0062DE63CC330B223E\"\r\n }\r\n }\r\n }\r\n ]\r\n}", "MessageAttributes": { "Test": { "Type": "String", @@ -12,4 +12,4 @@ } } ] -} +} \ No newline at end of file From c99406f1647fd930b1e8bc664660fb9ec3b4ddaf Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:49:11 -0500 Subject: [PATCH 11/12] Update Volumn Mount --- .github/workflows/calibration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/calibration.yml b/.github/workflows/calibration.yml index fb4d3d6..1ff12d1 100644 --- a/.github/workflows/calibration.yml +++ b/.github/workflows/calibration.yml @@ -27,9 +27,9 @@ jobs: docker run -d \ --name processing_lambda \ -p 9000:8080 \ - -v $PWD/lambda_function/tests/test_data/:/test_data \ + -v "${{ github.workspace }}/lambda_function/tests/test_data/:/test_data" \ -e SWXSOC_MISSION=padre \ - -e SDC_AWS_FILE_PATH=/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_COMMON_Data_1762004752547_1762005892626.csv \ + -e SDC_AWS_FILE_PATH=/test_data/padre_get_CUBEADCS_GEN2_OP_STATUS_APP_Data_1761936771334_1762106179414.csv \ processing_function:latest container_id=$(docker ps -qf "ancestor=processing_function:latest") echo "Container ID: $container_id" From 31b84d4bb96d29fcb5d0ada5113441fa11e785eb Mon Sep 17 00:00:00 2001 From: Andrew Robbertz <24920994+Alrobbertz@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:19:51 -0500 Subject: [PATCH 12/12] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac53c4b..bd0c7b6 100755 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ docker run \ -p 9000:8080 \ -v :/test_data \ -e SDC_AWS_FILE_PATH=/test_data/ \ - sdc_aws_processing_lambda:latest` + sdc_aws_processing_lambda:latest ``` 3. From a `separate` terminal, make a curl request to the running lambda function: