diff --git a/lambda/transfer-medpass-data/main.py b/lambda/transfer-medpass-data/main.py index efb7e42c..096d36a5 100644 --- a/lambda/transfer-medpass-data/main.py +++ b/lambda/transfer-medpass-data/main.py @@ -8,13 +8,14 @@ import pyzipper from pyzipper.zipfile import BadZipFile # 環境変数 -# mbj-newdwh2021-staging-data DATA_IMPORT_BUCKET = os.environ["DATA_IMPORT_BUCKET"] -# mbj-newdwh2021-staging-backup-medpass -MEDPASS_BACKUP_BUCKET = os.environ["MEDPASS_BACKUP_BUCKET"] -MEDPASS_TARGET_FOLDER = os.environ["MEDPASS_TARGET_FOLDER"] # medpass/target -# /staging/s3/medpassZipExtractPassword +HCP_WEB_TARGET_FOLDER = os.environ["HCP_WEB_TARGET_FOLDER"] +HCP_WEB_BACKUP_BUCKET = os.environ["HCP_WEB_BACKUP_BUCKET"] +BACKUP_ZIPFILE_FOLDER = os.environ["BACKUP_ZIPFILE_FOLDER"] +BACKUP_DATA_IMPORT_FOLDER = os.environ["BACKUP_DATA_IMPORT_FOLDER"] +DATA_IMPORT_FILENAME = os.environ["DATA_IMPORT_FILENAME"] MEDPASS_ZIP_PASSWORD_PARAMETER_STORE_KEY = os.environ["MEDPASS_ZIP_PASSWORD_PARAMETER_STORE_KEY"] + LOG_LEVEL = os.environ["LOG_LEVEL"] TZ = os.environ["TZ"] @@ -55,13 +56,15 @@ if not isinstance(level, int): logger.setLevel(level) -def extract_zip_with_password(zip_filepath: str, extract_to_folder: str, password: str): +def extract_zip_with_password(zip_filepath: str, extract_to_folder: str, password: str) -> os.path: """ 暗号化ZIPを解凍する。 :param zip_filepath: ZIPファイルが保管されているフォルダパス :param extract_to_folder: ZIPファイルの解凍先フォルダ :param password: ZIPパスワード + + :return 解凍されたファイルパス """ # ZIPを解凍 try: @@ -69,40 +72,45 @@ def extract_zip_with_password(zip_filepath: str, extract_to_folder: str, passwor # ZIP内のファイルは1つのみ inner_filename = z.filelist[0].filename z.extractall(path=extract_to_folder, pwd=password.encode()) - except BadZipFile as e: - pass except Exception as e: - pass + raise e - logger.info(f'解凍先フォルダ: {os.listdir("/tmp")}') - logger.info(f'解凍ファイルパス: {os.path.join(extract_to_folder, inner_filename)}') return os.path.join(extract_to_folder, inner_filename) -def get_s3_event_parameter(event: dict): +def get_s3_event_parameter(event: dict) -> tuple[str, str, str, str]: s3_event = event["Records"][0]["s3"] - event_bucket_name = s3_event["bucket"]["name"] - event_object_key = s3_event["object"]["key"] - event_file_name = os.path.basename(event_object_key) - event_folder_name = os.path.dirname(event_object_key).split('/')[0] + event_bucket_name: str = s3_event["bucket"]["name"] + event_object_key: str = s3_event["object"]["key"] + event_file_name: str = os.path.basename(event_object_key) + event_folder_name: str = os.path.dirname(event_object_key).split('/')[0] return event_bucket_name, event_object_key, event_file_name, event_folder_name -def get_ssm_params(parameter_key: str, with_decryption: bool = True): +def get_ssm_params(parameter_key: str, with_decryption: bool = True) -> str: + """SSMパラメータストアから指定されたパラメータ名の値を取得する""" response = ssm_client.get_parameter( Name=parameter_key, WithDecryption=with_decryption) - parameter_value = response['Parameter']['Value'] + parameter_value: str = response['Parameter']['Value'] return parameter_value -def delete_doing_file(event_bucket_name: str, event_object_key: str): +def delete_doing_file(event: dict) -> None: + """.doingファイルをバケット上から削除する""" + # イベント情報を取得 + ( + event_bucket_name, + event_object_key, + _, + _ + ) = get_s3_event_parameter(event) # ⑨ メモリに保持したバケット名/フォルダ名内の「受信データファイル名.doing」ファイルを削除する s3_client.delete_object( Bucket=event_bucket_name, Key=f'{event_object_key}{EXCLUSIVE_CONTROL_FILE_EXT}') -def handler(event, context): +def handler(event, context) -> None: try: # ① 処理開始ログを出力する logger.info('I-01-01 処理開始 medパスデータ解凍・復号化・転送処理') @@ -141,7 +149,8 @@ def handler(event, context): logger.info('I-04-02 暗号化ZIPファイルをダウンロードしました') except Exception as e: logger.exception(f'E-04-01 暗号化ZIPファイルのダウンロードに失敗しました エラー内容:{e}') - raise e + delete_doing_file(event) + return # ⑤ ZIP解凍パスワードをSSM パラメータストアから取得する try: @@ -151,54 +160,78 @@ def handler(event, context): MEDPASS_ZIP_PASSWORD_PARAMETER_STORE_KEY) except Exception as e: logger.exception(f'E-05-01 ZIP解凍パスワードの読み込みに失敗しました エラー内容:{e}') - raise e + delete_doing_file(event) + return # ⑥ ZIPファイルを解凍してローカルに保存 try: - logger.info(f'I-06-01 ZIP解凍開始') + logger.info(f'I-05-02 ZIP解凍開始') extracted_zip_file_path = extract_zip_with_password( os.path.join(PATH_TMP, event_file_name), PATH_TMP, zip_password) - except Exception as e: - logger.exception(f'E-06-01 ZIPの解凍に失敗しました エラー内容:{e}') - raise e - logger.info(f'I-06-02 ZIP解凍成功') - # ⑦ バックアップS3バケットにコピー - copy_source = {'Bucket': event_bucket_name, 'Key': event_object_key} - execute_date_yyyymm = datetime.date.today().strftime('%Y/%m/%d') + except RuntimeError as e: + if 'password' in str(e).lower(): + # パスワードが間違っている場合のエラー + logger.exception( + f'E-05-02 ZIPのパスワードが不正のため、解凍に失敗しました エラー内容:{e}') + delete_doing_file(event) + return + else: + # 想定外のエラー + raise e + # ZIPファイルが壊れている場合のエラー + except BadZipFile as e: + logger.exception(f'E-05-03 ZIPの形式が不正のため、解凍に失敗しました エラー内容:{e}') + delete_doing_file(event) + return + + # データ登録用にファイルをリネーム + # ZIPファイル名がyyyymmdd.zipのため、年月日部分をデータ登録用ファイル名の末尾につけ、拡張子をCSVに変更 + data_import_file_name = f'{DATA_IMPORT_FILENAME}_{event_file_name.replace(ZIP_FILE_EXT, CSV_FILE_EXT)}' + logger.info(f'I-05-03 ZIP解凍成功') + + # ⑥ 受信した暗号化ZIPファイルと解凍後のファイルをバックアップする + backup_copy_source = { + 'Bucket': event_bucket_name, 'Key': event_object_key} + execute_date_yyyymmdd = datetime.date.today().strftime('%Y/%m/%d') + + # ZIPファイルのバックアップ s3_client.copy_object( - Bucket=MEDPASS_BACKUP_BUCKET, - Key=f'{execute_date_yyyymm}/{event_file_name}', - CopySource=copy_source + Bucket=HCP_WEB_BACKUP_BUCKET, + Key=f'{BACKUP_ZIPFILE_FOLDER}/{execute_date_yyyymmdd}/{event_file_name}', + CopySource=backup_copy_source ) logger.info( - f'I-07-01 medパス受信データのバックアップ完了:{MEDPASS_BACKUP_BUCKET}/{execute_date_yyyymm}/{event_file_name}') + f'I-06-01 medパス受信データのバックアップ完了:{BACKUP_ZIPFILE_FOLDER}/{HCP_WEB_BACKUP_BUCKET}/{execute_date_yyyymmdd}/{event_file_name}') - # ⑧ データ登録S3バケットにアップロード - csv_file_name = extracted_zip_file_path.split('/')[-1] - logger.info(csv_file_name) + # 解凍後ファイルのバックアップ s3_client.upload_file( extracted_zip_file_path, + Bucket=HCP_WEB_BACKUP_BUCKET, + Key=f'{HCP_WEB_TARGET_FOLDER}/{data_import_file_name}' + ) + logger.info( + f'I-06-02 medパス解凍後データのバックアップ完了:{BACKUP_DATA_IMPORT_FOLDER}/{HCP_WEB_BACKUP_BUCKET}/{execute_date_yyyymmdd}/{data_import_file_name}') + + # ⑦ 解凍後のファイルをデータ登録バケットに転送する + data_import_copy_source = {'Bucket': HCP_WEB_BACKUP_BUCKET, + 'Key': f'{BACKUP_DATA_IMPORT_FOLDER}/{execute_date_yyyymmdd}/{data_import_file_name}'} + s3_client.copy_object( Bucket=DATA_IMPORT_BUCKET, - Key=f'{MEDPASS_TARGET_FOLDER}/{csv_file_name}' + Key=f'{HCP_WEB_TARGET_FOLDER}/{data_import_file_name}', + CopySource=data_import_copy_source ) # アップロード後、元のバケットからは削除する s3_client.delete_object(Bucket=event_bucket_name, Key=event_object_key) logger.info( - f'I-08-01 Encise受信データの転送完了:{DATA_IMPORT_BUCKET}/{MEDPASS_TARGET_FOLDER}/{csv_file_name}') + f'I-07-01 medパス解凍後データの転送完了:{DATA_IMPORT_BUCKET}/{HCP_WEB_TARGET_FOLDER}/{data_import_file_name}') - # ⑨ メモリに保持したバケット名/フォルダ名内の「受信データファイル名.doing」ファイルを削除する - delete_doing_file(event_bucket_name, event_object_key) + # ⑧ メモリに保持したバケット名/フォルダ名内の「受信データファイル名.doing」ファイルを削除する + delete_doing_file(event) - logger.info('I-08-09 処理終了 Medpass受信データ転送処理') + logger.info('I-08-01 処理終了 medパスデータ解凍・復号化・転送処理') except Exception as e: logger.exception(f'想定外のエラーが発生しました。処理を終了します。 例外内容:{e}') - ( - event_bucket_name, - event_object_key, - _, - _ - ) = get_s3_event_parameter(event) - delete_doing_file(event_bucket_name, event_object_key) + delete_doing_file(event) raise e