Merge pull request #37 feature-NEWDWH2021-541 into develop-8sap
This commit is contained in:
commit
2452f302ec
4
.gitignore
vendored
4
.gitignore
vendored
@ -3,6 +3,8 @@ lambda/mbj-newdwh2021-staging-NoticeToSlack/node_modules/*
|
|||||||
lambda/mbj-newdwh2021-staging-PublishFromLog/package-lock.json
|
lambda/mbj-newdwh2021-staging-PublishFromLog/package-lock.json
|
||||||
lambda/mbj-newdwh2021-staging-PublishFromLog/node_modules/*
|
lambda/mbj-newdwh2021-staging-PublishFromLog/node_modules/*
|
||||||
|
|
||||||
# Pythonの仮想環境
|
# ローカルの環境変数
|
||||||
|
.env
|
||||||
|
# Python関連
|
||||||
.venv
|
.venv
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|||||||
14
lambda/check-view-security-option/Dockerfile
Normal file
14
lambda/check-view-security-option/Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.9
|
||||||
|
|
||||||
|
ENV WORKDIR /function/
|
||||||
|
ENV TZ="Asia/Tokyo"
|
||||||
|
WORKDIR ${WORKDIR}
|
||||||
|
|
||||||
|
COPY Pipfile Pipfile.lock ${WORKDIR}
|
||||||
|
RUN pip install pipenv --no-cache-dir && \
|
||||||
|
pipenv install --system --deploy && \
|
||||||
|
pip uninstall -y pipenv virtualenv-clone virtualenv
|
||||||
|
COPY check-view-option ./
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/python", "-m", "awslambdaric" ]
|
||||||
|
CMD [ "main.handler" ]
|
||||||
16
lambda/check-view-security-option/Pipfile
Normal file
16
lambda/check-view-security-option/Pipfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
awslambdaric = "*"
|
||||||
|
boto3 = "*"
|
||||||
|
pymysql = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
autopep8 = "*"
|
||||||
|
flake8 = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.9"
|
||||||
209
lambda/check-view-security-option/Pipfile.lock
generated
Normal file
209
lambda/check-view-security-option/Pipfile.lock
generated
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "9521eb0e33f733846811775b587cd94d7660f2e612b8efcbd622fd4d19122916"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.9"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"awslambdaric": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:059c7a66d4470169e01620d93f07424b80d302e3736cd11e68373f293a41e396",
|
||||||
|
"sha256:0e90053614f0e5e5d6d6ae6d164412ce95b5d549c6fb0f6ff4290d77c5e9d3e5",
|
||||||
|
"sha256:11a365164efec105aa670259dfe473d9609da8f6f2e468790b2dfc24969bfff1",
|
||||||
|
"sha256:19da28e8c892b1c52a9db4d2b986af303932e3a4c4632eb0c5d5eb6a673c6022",
|
||||||
|
"sha256:2eb2fdb1ae0f84669d37f193f247fa115a282a7777e051ced3a33620d6280646",
|
||||||
|
"sha256:2efff2292fc8f8484eb094ffd77808a67815353be898a7f0b33ce51b841af691",
|
||||||
|
"sha256:387b94cb0358662ae2b203f0aa2af25e80c6a2019a6b569f733ecd993a4f53d2",
|
||||||
|
"sha256:38f8ae67ecb5b4e9f7fc42746ee39765dd7ddab359cb7e8ebfda1de0f0c0b059",
|
||||||
|
"sha256:3fd0e1b3891987fa7ebb0c08d24c76af5fc17466f6efdfa9a59848dfb23930ec",
|
||||||
|
"sha256:63a82d21d66146b3fde7eb6086abd058b75bdcab4a02b02afe0e8e4a45edfb5b",
|
||||||
|
"sha256:676a741ad8f3aa27d651bcf3a2b83d5cee815f99c8b2b9abef3cb22ca7b29698",
|
||||||
|
"sha256:9b0781bd41c20a2f2a0b018464a1daa376f663bd5eb7b0b6ba78f483681b1519",
|
||||||
|
"sha256:bad98f2f94cecc90b89ac4e1d4feed96eb664e13c29b7ce232444cc9358e0d36",
|
||||||
|
"sha256:d64dcba8da9dbea62644133a48c75376a37bfe0f84096ad73bf7fc5b2eb31fc7",
|
||||||
|
"sha256:d8f280b25d8a7ae6b6ff92a9bbc6567b984264be8ef3e0fcb0402a1247f6c75d",
|
||||||
|
"sha256:dad646f566aa7ec9b7179f16ca6741a2bea148abec6ed5947f86d00607e0a9a2",
|
||||||
|
"sha256:dc7072f642fdd215387d4921bbd5ac91b96a4a705bce5e7853622d09fe59f57d",
|
||||||
|
"sha256:fbbd24446ce2f876335b178f04aa4ec7ec480afc0f9621ebfdd5f55ad4b7c06e",
|
||||||
|
"sha256:fe76893a1b42bcee4c91c6456092d2a42455818756e8f62d50e8c5adb22fa9e7"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.0.4"
|
||||||
|
},
|
||||||
|
"boto3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4a7cf5fddb1626d25c5935c5a82afdff9c7fe2faac2a68d37edf0264b3a85127",
|
||||||
|
"sha256:bd0b94428ae7cc57904d3c903d9393bdf4dd2b1274d1c51749f27f5bd76953e1"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.24.18"
|
||||||
|
},
|
||||||
|
"botocore": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:20a866351f9f65cfe27edc21d755de60e17a1fbb1273d73fc0006ed0d6f8ef86",
|
||||||
|
"sha256:74426179c75debd77c6dcc2d66cfd506e52962e605d2b9f2dbca290474539c8b"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==1.27.18"
|
||||||
|
},
|
||||||
|
"jmespath": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980",
|
||||||
|
"sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==1.0.1"
|
||||||
|
},
|
||||||
|
"pymysql": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:41fc3a0c5013d5f039639442321185532e3e2c8924687abe6537de157d403641",
|
||||||
|
"sha256:816927a350f38d56072aeca5dfb10221fe1dc653745853d30a216637f5d7ad36"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.2"
|
||||||
|
},
|
||||||
|
"python-dateutil": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
|
||||||
|
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.8.2"
|
||||||
|
},
|
||||||
|
"s3transfer": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:06176b74f3a15f61f1b4f25a1fc29a4429040b7647133a463da8fa5bd28d5ecd",
|
||||||
|
"sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==0.6.0"
|
||||||
|
},
|
||||||
|
"simplejson": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:034550078a11664d77bc1a8364c90bb7eef0e44c2dbb1fd0a4d92e3997088667",
|
||||||
|
"sha256:05b43d568300c1cd43f95ff4bfcff984bc658aa001be91efb3bb21df9d6288d3",
|
||||||
|
"sha256:0dd9d9c738cb008bfc0862c9b8fa6743495c03a0ed543884bf92fb7d30f8d043",
|
||||||
|
"sha256:10fc250c3edea4abc15d930d77274ddb8df4803453dde7ad50c2f5565a18a4bb",
|
||||||
|
"sha256:2862beabfb9097a745a961426fe7daf66e1714151da8bb9a0c430dde3d59c7c0",
|
||||||
|
"sha256:292c2e3f53be314cc59853bd20a35bf1f965f3bc121e007ab6fd526ed412a85d",
|
||||||
|
"sha256:2d3eab2c3fe52007d703a26f71cf649a8c771fcdd949a3ae73041ba6797cfcf8",
|
||||||
|
"sha256:2e7b57c2c146f8e4dadf84977a83f7ee50da17c8861fd7faf694d55e3274784f",
|
||||||
|
"sha256:311f5dc2af07361725033b13cc3d0351de3da8bede3397d45650784c3f21fbcf",
|
||||||
|
"sha256:344e2d920a7f27b4023c087ab539877a1e39ce8e3e90b867e0bfa97829824748",
|
||||||
|
"sha256:3fabde09af43e0cbdee407555383063f8b45bfb52c361bc5da83fcffdb4fd278",
|
||||||
|
"sha256:42b8b8dd0799f78e067e2aaae97e60d58a8f63582939af60abce4c48631a0aa4",
|
||||||
|
"sha256:4b3442249d5e3893b90cb9f72c7d6ce4d2ea144d2c0d9f75b9ae1e5460f3121a",
|
||||||
|
"sha256:55d65f9cc1b733d85ef95ab11f559cce55c7649a2160da2ac7a078534da676c8",
|
||||||
|
"sha256:5c659a0efc80aaaba57fcd878855c8534ecb655a28ac8508885c50648e6e659d",
|
||||||
|
"sha256:72d8a3ffca19a901002d6b068cf746be85747571c6a7ba12cbcf427bfb4ed971",
|
||||||
|
"sha256:75ecc79f26d99222a084fbdd1ce5aad3ac3a8bd535cd9059528452da38b68841",
|
||||||
|
"sha256:76ac9605bf2f6d9b56abf6f9da9047a8782574ad3531c82eae774947ae99cc3f",
|
||||||
|
"sha256:7d276f69bfc8c7ba6c717ba8deaf28f9d3c8450ff0aa8713f5a3280e232be16b",
|
||||||
|
"sha256:7f10f8ba9c1b1430addc7dd385fc322e221559d3ae49b812aebf57470ce8de45",
|
||||||
|
"sha256:8042040af86a494a23c189b5aa0ea9433769cc029707833f261a79c98e3375f9",
|
||||||
|
"sha256:813846738277729d7db71b82176204abc7fdae2f566e2d9fcf874f9b6472e3e6",
|
||||||
|
"sha256:845a14f6deb124a3bcb98a62def067a67462a000e0508f256f9c18eff5847efc",
|
||||||
|
"sha256:869a183c8e44bc03be1b2bbcc9ec4338e37fa8557fc506bf6115887c1d3bb956",
|
||||||
|
"sha256:8acf76443cfb5c949b6e781c154278c059b09ac717d2757a830c869ba000cf8d",
|
||||||
|
"sha256:8f713ea65958ef40049b6c45c40c206ab363db9591ff5a49d89b448933fa5746",
|
||||||
|
"sha256:934115642c8ba9659b402c8bdbdedb48651fb94b576e3b3efd1ccb079609b04a",
|
||||||
|
"sha256:9551f23e09300a9a528f7af20e35c9f79686d46d646152a0c8fc41d2d074d9b0",
|
||||||
|
"sha256:9a2b7543559f8a1c9ed72724b549d8cc3515da7daf3e79813a15bdc4a769de25",
|
||||||
|
"sha256:a55c76254d7cf8d4494bc508e7abb993a82a192d0db4552421e5139235604625",
|
||||||
|
"sha256:ad8f41c2357b73bc9e8606d2fa226233bf4d55d85a8982ecdfd55823a6959995",
|
||||||
|
"sha256:af4868da7dd53296cd7630687161d53a7ebe2e63814234631445697bd7c29f46",
|
||||||
|
"sha256:afebfc3dd3520d37056f641969ce320b071bc7a0800639c71877b90d053e087f",
|
||||||
|
"sha256:b59aa298137ca74a744c1e6e22cfc0bf9dca3a2f41f51bc92eb05695155d905a",
|
||||||
|
"sha256:bc00d1210567a4cdd215ac6e17dc00cb9893ee521cee701adfd0fa43f7c73139",
|
||||||
|
"sha256:c1cb29b1fced01f97e6d5631c3edc2dadb424d1f4421dad079cb13fc97acb42f",
|
||||||
|
"sha256:c94dc64b1a389a416fc4218cd4799aa3756f25940cae33530a4f7f2f54f166da",
|
||||||
|
"sha256:ceaa28a5bce8a46a130cd223e895080e258a88d51bf6e8de2fc54a6ef7e38c34",
|
||||||
|
"sha256:cff6453e25204d3369c47b97dd34783ca820611bd334779d22192da23784194b",
|
||||||
|
"sha256:d0b64409df09edb4c365d95004775c988259efe9be39697d7315c42b7a5e7e94",
|
||||||
|
"sha256:d4813b30cb62d3b63ccc60dd12f2121780c7a3068db692daeb90f989877aaf04",
|
||||||
|
"sha256:da3c55cdc66cfc3fffb607db49a42448785ea2732f055ac1549b69dcb392663b",
|
||||||
|
"sha256:e058c7656c44fb494a11443191e381355388443d543f6fc1a245d5d238544396",
|
||||||
|
"sha256:fed0f22bf1313ff79c7fc318f7199d6c2f96d4de3234b2f12a1eab350e597c06",
|
||||||
|
"sha256:ffd4e4877a78c84d693e491b223385e0271278f5f4e1476a4962dca6824ecfeb"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.5' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==3.17.2"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||||
|
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==1.16.0"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
|
||||||
|
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||||
|
"version": "==1.26.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"autopep8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979",
|
||||||
|
"sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.6.0"
|
||||||
|
},
|
||||||
|
"flake8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d",
|
||||||
|
"sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.0.1"
|
||||||
|
},
|
||||||
|
"mccabe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||||
|
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||||
|
],
|
||||||
|
"version": "==0.6.1"
|
||||||
|
},
|
||||||
|
"pycodestyle": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20",
|
||||||
|
"sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
|
"version": "==2.8.0"
|
||||||
|
},
|
||||||
|
"pyflakes": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c",
|
||||||
|
"sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.4.0"
|
||||||
|
},
|
||||||
|
"toml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||||
|
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==0.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import boto3
|
||||||
|
import environments
|
||||||
|
from constants import AWS_RESOURCE_S3, S3_RESPONSE_BODY, UTF8
|
||||||
|
|
||||||
|
|
||||||
|
class S3Resource:
|
||||||
|
|
||||||
|
def __init__(self, bucket_name: str) -> None:
|
||||||
|
self.__s3_resource = boto3.resource(AWS_RESOURCE_S3)
|
||||||
|
self.__s3_bucket = self.__s3_resource.Bucket(bucket_name)
|
||||||
|
|
||||||
|
def get_object(self, object_key: str):
|
||||||
|
s3_object = self.__s3_bucket.Object(object_key)
|
||||||
|
response = s3_object.get()
|
||||||
|
return response[S3_RESPONSE_BODY].read().decode(UTF8)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigBucket:
|
||||||
|
__s3_resource: S3Resource = None
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.__s3_resource = S3Resource(environments.CONFIG_BUCKET_NAME)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def check_target_schema_names(self):
|
||||||
|
return self.__s3_resource.get_object(environments.CHECK_TARGET_SCHEMA_NAMES_PATH)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def notice_mail_title_template(self):
|
||||||
|
return self.__s3_resource.get_object(environments.NOTICE_MAIL_TITLE_TEMPLATE_PATH)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def notice_mail_body_template(self):
|
||||||
|
return self.__s3_resource.get_object(environments.NOTICE_MAIL_BODY_TEMPLATE_PATH)
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import boto3
|
||||||
|
import environments
|
||||||
|
from constants import AWS_RESOURCE_SNS
|
||||||
|
|
||||||
|
|
||||||
|
class SNSClient:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.__sns_client = boto3.client(AWS_RESOURCE_SNS)
|
||||||
|
|
||||||
|
def publish(self, sns_topic_arn: str, subject: str, message: str) -> None:
|
||||||
|
publish_params = {
|
||||||
|
'TopicArn': sns_topic_arn,
|
||||||
|
'Subject': subject.rstrip('\n'),
|
||||||
|
'Message': message
|
||||||
|
}
|
||||||
|
self.__sns_client.publish(**publish_params)
|
||||||
|
|
||||||
|
|
||||||
|
class SNSNotifier:
|
||||||
|
__sns_client: SNSClient = None
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.__sns_client = SNSClient()
|
||||||
|
|
||||||
|
def publish_to_mbj(self, subject: str, message: str):
|
||||||
|
self.__sns_client.publish(environments.MBJ_NOTICE_TOPIC, subject, message)
|
||||||
|
|
||||||
|
def publish_to_nds(self, error_id: str, exception: Exception):
|
||||||
|
error_message = f'{error_id} のエラーが発生しました。ご確認ください\n詳細:{exception}'
|
||||||
|
self.__sns_client.publish(environments.NDS_NOTICE_TOPIC, environments.NDS_NOTICE_TITLE, error_message)
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import boto3
|
||||||
|
import environments
|
||||||
|
from constants import (AWS_RESOURCE_SSM, SSM_PARAMETER_RESPONSE,
|
||||||
|
SSM_PARAMETER_VALUE)
|
||||||
|
|
||||||
|
|
||||||
|
class SSMClient:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.__ssm_client = boto3.client(AWS_RESOURCE_SSM)
|
||||||
|
|
||||||
|
def get_ssm_params(self, parameter_key: str, with_decryption: bool):
|
||||||
|
response = self.__ssm_client.get_parameter(Name=parameter_key, WithDecryption=with_decryption)
|
||||||
|
parameter_value = response[SSM_PARAMETER_RESPONSE][SSM_PARAMETER_VALUE]
|
||||||
|
return parameter_value
|
||||||
|
|
||||||
|
|
||||||
|
class SSMParameterStore:
|
||||||
|
__ssm_client: SSMClient = None
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.__ssm_client = SSMClient()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_host(self):
|
||||||
|
return self.__ssm_client.get_ssm_params(environments.PARAM_NAME_DB_HOST, True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_user_name(self):
|
||||||
|
return self.__ssm_client.get_ssm_params(environments.PARAM_NAME_DB_USER_NAME, True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_user_password(self):
|
||||||
|
return self.__ssm_client.get_ssm_params(environments.PARAM_NAME_DB_USER_PASSWORD, True)
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
# logger
|
||||||
|
LOG_FORMAT = '[%(levelname)s]\t%(asctime)s\t%(message)s\n'
|
||||||
|
LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||||
|
LOG_LEVEL_INFO = 'INFO'
|
||||||
|
|
||||||
|
# environments
|
||||||
|
CHECK_TARGET_SCHEMA_NAMES_PATH = 'CHECK_TARGET_SCHEMA_NAMES_PATH'
|
||||||
|
CONFIG_BUCKET_NAME = 'CONFIG_BUCKET_NAME'
|
||||||
|
LOG_LEVEL = 'LOG_LEVEL'
|
||||||
|
MBJ_NOTICE_TOPIC = 'MBJ_NOTICE_TOPIC'
|
||||||
|
NDS_NOTICE_TOPIC = 'NDS_NOTICE_TOPIC'
|
||||||
|
NDS_NOTICE_TITLE = 'NDS_NOTICE_TITLE'
|
||||||
|
NOTICE_MAIL_BODY_TEMPLATE_PATH = 'NOTICE_MAIL_BODY_TEMPLATE_PATH'
|
||||||
|
NOTICE_MAIL_TITLE_TEMPLATE_PATH = 'NOTICE_MAIL_TITLE_TEMPLATE_PATH'
|
||||||
|
PARAM_NAME_DB_HOST = 'PARAM_NAME_DB_HOST'
|
||||||
|
PARAM_NAME_DB_USER_NAME = 'PARAM_NAME_DB_USER_NAME'
|
||||||
|
PARAM_NAME_DB_USER_PASSWORD = 'PARAM_NAME_DB_USER_PASSWORD'
|
||||||
|
TZ = 'TZ'
|
||||||
|
|
||||||
|
# aws
|
||||||
|
AWS_RESOURCE_S3 = 's3'
|
||||||
|
AWS_RESOURCE_SSM = 'ssm'
|
||||||
|
AWS_RESOURCE_SNS = 'sns'
|
||||||
|
S3_RESPONSE_BODY = 'Body'
|
||||||
|
SSM_PARAMETER_RESPONSE = 'Parameter'
|
||||||
|
SSM_PARAMETER_NAME = 'Name'
|
||||||
|
SSM_PARAMETER_VALUE = 'Value'
|
||||||
|
RESPONSE_ERROR = 'Error'
|
||||||
|
RESPONSE_ERROR_CODE = 'Code'
|
||||||
|
RESPONSE_CODE_NO_SUCH_KEY = 'NoSuchKey'
|
||||||
|
RESPONSE_CODE_PARAMETER_NOT_FOUND = 'ParameterNotFound'
|
||||||
|
|
||||||
|
# sql
|
||||||
|
DEFAULT_SCHEMA = 'INFORMATION_SCHEMA'
|
||||||
|
INFORMATION_SCHEMA_SECURITY_TYPE_INVOKER = 'INVOKER'
|
||||||
|
CONNECTION_TIMEOUT = 5
|
||||||
|
|
||||||
|
# system var
|
||||||
|
UTF8 = 'utf-8'
|
||||||
|
LAUNCH_ON_LOCAL = 'local'
|
||||||
|
CHECK_TARGET_SCHEMAS = 'check_target_schemas'
|
||||||
|
# メール本文に出力する不足ファイル名一覧のインデント
|
||||||
|
MAIL_INDENT = '\n '
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import contextlib
|
||||||
|
|
||||||
|
import pymysql
|
||||||
|
from pymysql.constants import CLIENT
|
||||||
|
|
||||||
|
from constants import CONNECTION_TIMEOUT, DEFAULT_SCHEMA
|
||||||
|
|
||||||
|
|
||||||
|
class Database:
|
||||||
|
|
||||||
|
__connection: pymysql.Connection = None
|
||||||
|
__host: str = None
|
||||||
|
__user: str = None
|
||||||
|
__password: str = None
|
||||||
|
__database: str = None
|
||||||
|
|
||||||
|
def __init__(self, host: str, user: str, password: str) -> None:
|
||||||
|
self.__host = host
|
||||||
|
self.__user = user
|
||||||
|
self.__password = password
|
||||||
|
self.__database = DEFAULT_SCHEMA
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
connection = pymysql.connect(host=self.__host, user=self.__user, passwd=self.__password,
|
||||||
|
database=self.__database, connect_timeout=CONNECTION_TIMEOUT,
|
||||||
|
client_flag=CLIENT.MULTI_STATEMENTS)
|
||||||
|
self.__connection = connection
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def query(self, query: str):
|
||||||
|
if self.__connection is None:
|
||||||
|
raise Exception('データベースに接続されていません')
|
||||||
|
|
||||||
|
with self.__connection.cursor() as cursor:
|
||||||
|
cursor.execute(query)
|
||||||
|
yield cursor
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.__connection.close()
|
||||||
|
self.__connection = None
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NoSecurityOptionView:
|
||||||
|
schema_name: str
|
||||||
|
table_name: str
|
||||||
|
definer: str
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from constants import (CHECK_TARGET_SCHEMA_NAMES_PATH, CONFIG_BUCKET_NAME,
|
||||||
|
LOG_LEVEL, LOG_LEVEL_INFO, MBJ_NOTICE_TOPIC,
|
||||||
|
NDS_NOTICE_TITLE, NDS_NOTICE_TOPIC,
|
||||||
|
NOTICE_MAIL_BODY_TEMPLATE_PATH,
|
||||||
|
NOTICE_MAIL_TITLE_TEMPLATE_PATH, PARAM_NAME_DB_HOST,
|
||||||
|
PARAM_NAME_DB_USER_NAME, PARAM_NAME_DB_USER_PASSWORD,
|
||||||
|
TZ)
|
||||||
|
|
||||||
|
LOG_LEVEL = os.environ.get(LOG_LEVEL, LOG_LEVEL_INFO)
|
||||||
|
CHECK_TARGET_SCHEMA_NAMES_PATH = os.environ[CHECK_TARGET_SCHEMA_NAMES_PATH]
|
||||||
|
CONFIG_BUCKET_NAME = os.environ[CONFIG_BUCKET_NAME]
|
||||||
|
MBJ_NOTICE_TOPIC = os.environ[MBJ_NOTICE_TOPIC]
|
||||||
|
NDS_NOTICE_TOPIC = os.environ[NDS_NOTICE_TOPIC]
|
||||||
|
NDS_NOTICE_TITLE = os.environ[NDS_NOTICE_TITLE]
|
||||||
|
NOTICE_MAIL_BODY_TEMPLATE_PATH = os.environ[NOTICE_MAIL_BODY_TEMPLATE_PATH]
|
||||||
|
NOTICE_MAIL_TITLE_TEMPLATE_PATH = os.environ[NOTICE_MAIL_TITLE_TEMPLATE_PATH]
|
||||||
|
|
||||||
|
PARAM_NAME_DB_HOST = os.environ[PARAM_NAME_DB_HOST]
|
||||||
|
PARAM_NAME_DB_USER_NAME = os.environ[PARAM_NAME_DB_USER_NAME]
|
||||||
|
PARAM_NAME_DB_USER_PASSWORD = os.environ[PARAM_NAME_DB_USER_PASSWORD]
|
||||||
|
|
||||||
|
TZ = os.environ[TZ]
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
from abc import ABCMeta
|
||||||
|
|
||||||
|
|
||||||
|
class MeDaCaException(Exception, metaclass=ABCMeta):
|
||||||
|
"""MeDaCaシステム固有のカスタムエラークラス"""
|
||||||
|
|
||||||
|
def __init__(self, error_id: str, message) -> None:
|
||||||
|
super().__init__(message)
|
||||||
|
self.error_id = error_id
|
||||||
|
|
||||||
|
|
||||||
|
class FileNotFoundException(MeDaCaException):
|
||||||
|
"""S3のファイルが見つからない場合の例外"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterNotFoundException(MeDaCaException):
|
||||||
|
"""パラメータストアのキーが見つからない場合の例外"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseConnectionException(MeDaCaException):
|
||||||
|
"""データベース接続に失敗した場合の例外"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class QueryExecutionException(MeDaCaException):
|
||||||
|
"""クエリ実行に失敗した場合の例外"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SNSPublishException(MeDaCaException):
|
||||||
|
"""AmazonSNSへの通知に失敗した場合の例外"""
|
||||||
|
pass
|
||||||
282
lambda/check-view-security-option/check-view-option/main.py
Normal file
282
lambda/check-view-security-option/check-view-option/main.py
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
"""
|
||||||
|
Viewセキュリティオプション付与チェック用Lambda関数のエントリーポイント
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import botocore
|
||||||
|
|
||||||
|
from aws.s3 import ConfigBucket
|
||||||
|
from aws.sns import SNSNotifier
|
||||||
|
from aws.ssm import SSMParameterStore
|
||||||
|
from constants import (CHECK_TARGET_SCHEMAS,
|
||||||
|
INFORMATION_SCHEMA_SECURITY_TYPE_INVOKER, MAIL_INDENT,
|
||||||
|
RESPONSE_CODE_NO_SUCH_KEY,
|
||||||
|
RESPONSE_CODE_PARAMETER_NOT_FOUND, RESPONSE_ERROR,
|
||||||
|
RESPONSE_ERROR_CODE)
|
||||||
|
from database import Database
|
||||||
|
from dto.no_security_option_view import NoSecurityOptionView
|
||||||
|
from environments import (CONFIG_BUCKET_NAME, MBJ_NOTICE_TOPIC,
|
||||||
|
NDS_NOTICE_TOPIC, NOTICE_MAIL_BODY_TEMPLATE_PATH,
|
||||||
|
NOTICE_MAIL_TITLE_TEMPLATE_PATH)
|
||||||
|
from exceptions import (DatabaseConnectionException, FileNotFoundException,
|
||||||
|
MeDaCaException, ParameterNotFoundException,
|
||||||
|
QueryExecutionException, SNSPublishException)
|
||||||
|
from medaca_logger import MeDaCaLogger
|
||||||
|
|
||||||
|
logger = MeDaCaLogger.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
def handler(event, context):
|
||||||
|
try:
|
||||||
|
# ① 処理開始ログを出力する
|
||||||
|
logger.info('I-01-01', '処理開始 Viewセキュリティオプション付与チェック')
|
||||||
|
# ② 設定ファイル[チェック対象スキーマ名ファイル]を読み込む
|
||||||
|
logger.info('I-02-01', 'チェック対象スキーマ名ファイルを読み込み 開始')
|
||||||
|
check_target_schemas = read_check_target_schemas()
|
||||||
|
logger.info('I-02-02', f'チェック対象スキーマ名ファイルを読み込み 終了 チェック対象スキーマ名:{check_target_schemas}')
|
||||||
|
# ③ データベースに接続する
|
||||||
|
logger.info('I-03-01', 'データベースへの接続開始 開始')
|
||||||
|
# DB接続のためのパラメータ取得
|
||||||
|
db_host, db_user_name, db_user_password = read_db_param_from_parameter_store()
|
||||||
|
connection = connection_database(db_host, db_user_name, db_user_password)
|
||||||
|
logger.info('I-03-02', 'データベースへの接続開始 成功')
|
||||||
|
# ④ Viewのオプションを確認するため、データを取得する
|
||||||
|
logger.info('I-04-01', 'Viewセキュリティオプション チェック開始')
|
||||||
|
check_result = fetch_view_security_options(connection, check_target_schemas)
|
||||||
|
logger.debug('D-04-01', f'取得データ:{check_result}')
|
||||||
|
if len(check_result) == 0:
|
||||||
|
logger.info('I-04-02', 'Viewセキュリティオプション 未設定のViewはありません。処理を終了します。')
|
||||||
|
return
|
||||||
|
logger.info('I-05-01', 'Viewセキュリティオプション 未設定のViewがあるため、メール送信処理を開始します。')
|
||||||
|
# ⑤ 取得できたデータをもとに、メール通知する文言を作成する
|
||||||
|
no_security_option_views = [NoSecurityOptionView(*row) for row in check_result]
|
||||||
|
logger.info(
|
||||||
|
'I-05-02', f'通知メール(タイトル)テンプレートファイル読込 読込元:{CONFIG_BUCKET_NAME}/{NOTICE_MAIL_TITLE_TEMPLATE_PATH}')
|
||||||
|
mail_title = read_mail_title()
|
||||||
|
logger.info(
|
||||||
|
'I-05-03', '通知メール(タイトル)テンプレートファイルを読み込みました')
|
||||||
|
logger.info(
|
||||||
|
'I-05-04', f'通知メール(本文)テンプレートファイル読込 読込元:{CONFIG_BUCKET_NAME}/{NOTICE_MAIL_BODY_TEMPLATE_PATH}')
|
||||||
|
mail_body_template = read_mail_body_template()
|
||||||
|
logger.info(
|
||||||
|
'I-05-05', '通知メール(本文)テンプレートファイルを読み込みました')
|
||||||
|
mail_body = make_notice_mail_body(no_security_option_views, mail_body_template)
|
||||||
|
|
||||||
|
logger.info('I-05-06', f'メール送信指示をします 送信先トピック:{MBJ_NOTICE_TOPIC}')
|
||||||
|
notice_to_mbj(mail_title, mail_body)
|
||||||
|
logger.info('I-05-07', 'メール送信指示をしました')
|
||||||
|
|
||||||
|
except MeDaCaException as e:
|
||||||
|
logger.exception(e.error_id, e)
|
||||||
|
logger.error('E-ERR-01', f'処理異常通知の送信指示をしました 通知先トピック:{NDS_NOTICE_TOPIC}')
|
||||||
|
notice_to_nds(e.error_id, e)
|
||||||
|
raise e
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception('E-99', f'想定外のエラーが発生しました エラー内容:{e}')
|
||||||
|
logger.error('E-ERR-01', f'処理異常通知の送信指示をしました 通知先トピック:{NDS_NOTICE_TOPIC}')
|
||||||
|
notice_to_nds('E-99', e)
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
# ⑥ 処理終了ログを出力する
|
||||||
|
logger.info('I-06-01', '処理終了 Viewセキュリティオプション付与チェック')
|
||||||
|
|
||||||
|
|
||||||
|
def read_check_target_schemas() -> list:
|
||||||
|
"""設定ファイル[チェック対象スキーマ名ファイル]を読み込む
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FileNotFoundException: ファイルが読み込めなかったエラー
|
||||||
|
Exception: 想定外のエラー
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: チェック対象のスキーマ名のリスト
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
config_bucket = ConfigBucket()
|
||||||
|
check_target_schema_names = config_bucket.check_target_schema_names
|
||||||
|
return json.loads(check_target_schema_names)[CHECK_TARGET_SCHEMAS]
|
||||||
|
except botocore.exceptions.ClientError as e:
|
||||||
|
if e.response[RESPONSE_ERROR][RESPONSE_ERROR_CODE] == RESPONSE_CODE_NO_SUCH_KEY:
|
||||||
|
raise FileNotFoundException('E-02-01', f'チェック対象スキーマ名ファイルの読み込みに失敗しました エラー内容:{e}')
|
||||||
|
else:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
|
||||||
|
def read_db_param_from_parameter_store() -> tuple:
|
||||||
|
"""パラメータストアからDB接続情報を取得する
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ParameterNotFoundException: 指定されたパラメータが存在しないエラー
|
||||||
|
Exception: 想定外のエラー
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: DB接続情報
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
parameter_store = SSMParameterStore()
|
||||||
|
db_host = parameter_store.db_host
|
||||||
|
db_user_name = parameter_store.db_user_name
|
||||||
|
db_user_password = parameter_store.db_user_password
|
||||||
|
return db_host, db_user_name, db_user_password
|
||||||
|
except botocore.exceptions.ClientError as e:
|
||||||
|
if e.response[RESPONSE_ERROR][RESPONSE_ERROR_CODE] == RESPONSE_CODE_PARAMETER_NOT_FOUND:
|
||||||
|
raise ParameterNotFoundException('E-03-01', f'パラメータストアの取得に失敗しました エラー内容:{e}')
|
||||||
|
else:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
|
||||||
|
def connection_database(host: str, user_name: str, password: str) -> Database:
|
||||||
|
"""データベース接続
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host (str): DBホスト
|
||||||
|
user_name (str): DBユーザー名
|
||||||
|
password (str): DBパスワード
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
DatabaseConnectionException: データベースへの接続に失敗したエラー
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Database: データベース操作クラス
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
database = Database(host, user_name, password)
|
||||||
|
database.connect()
|
||||||
|
return database
|
||||||
|
except Exception as e:
|
||||||
|
raise DatabaseConnectionException('E-03-02', f'データベースへの接続に失敗しました エラー内容:{e}')
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_view_security_options(connection: Database, check_target_schemas: list) -> tuple:
|
||||||
|
"""SECURITY INVOKERのついていないViewの一覧を取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection (Database): 接続済みDB操作クラス
|
||||||
|
check_target_schemas (str): チェック対象のスキーマ一覧
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
QueryExecutionException: クエリ実行エラー
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: クエリ実行結果
|
||||||
|
"""
|
||||||
|
|
||||||
|
select_view_security_option_sql = f"""
|
||||||
|
SELECT
|
||||||
|
TABLE_SCHEMA,
|
||||||
|
TABLE_NAME,
|
||||||
|
DEFINER
|
||||||
|
FROM
|
||||||
|
INFORMATION_SCHEMA.VIEWS
|
||||||
|
WHERE
|
||||||
|
TABLE_SCHEMA IN (
|
||||||
|
{','.join([f"'{schema_name}'" for schema_name in check_target_schemas])}
|
||||||
|
)
|
||||||
|
AND SECURITY_TYPE <> '{INFORMATION_SCHEMA_SECURITY_TYPE_INVOKER}'
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with connection.query(select_view_security_option_sql) as cursor:
|
||||||
|
result = cursor.fetchall()
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
raise QueryExecutionException('E-04-01', f'Viewセキュリティオプションチェックに失敗しました エラー内容:{e}')
|
||||||
|
|
||||||
|
|
||||||
|
def make_notice_mail_body(no_security_option_views: list[NoSecurityOptionView], mail_body_template: str) -> tuple[str]:
|
||||||
|
"""メール本文を生成します
|
||||||
|
|
||||||
|
Args:
|
||||||
|
view_security_options (list[NoSecurityOptionView]): チェック対象のビュー一覧
|
||||||
|
mail_body_template (str): メール本文のテンプレート
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[str]: メール本文
|
||||||
|
"""
|
||||||
|
mail_message = MAIL_INDENT.join(
|
||||||
|
[f'{option.schema_name}.{option.table_name}' for option in no_security_option_views])
|
||||||
|
mail_body = mail_body_template.format(no_option_views=mail_message)
|
||||||
|
return mail_body
|
||||||
|
|
||||||
|
|
||||||
|
def read_mail_title() -> str:
|
||||||
|
"""メールタイトルを読み込む
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FileNotFoundException: ファイルが読み込めなかったエラー
|
||||||
|
Exception: 想定外のエラー
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: メールタイトル
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
config_bucket = ConfigBucket()
|
||||||
|
mail_title = config_bucket.notice_mail_title_template
|
||||||
|
except botocore.exceptions.ClientError as e:
|
||||||
|
if e.response[RESPONSE_ERROR][RESPONSE_ERROR_CODE] == RESPONSE_CODE_NO_SUCH_KEY:
|
||||||
|
raise FileNotFoundException('E-05-01', f'通知メール(タイトル)テンプレートファイルの読み込みに失敗しました エラー内容:{e}')
|
||||||
|
else:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
return mail_title
|
||||||
|
|
||||||
|
|
||||||
|
def read_mail_body_template() -> str:
|
||||||
|
"""メール本文を読み込む
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FileNotFoundException: ファイルが読み込めなかったエラー
|
||||||
|
Exception: 想定外のエラー
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: メール本文
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
config_bucket = ConfigBucket()
|
||||||
|
mail_body_template = config_bucket.notice_mail_body_template
|
||||||
|
except botocore.exceptions.ClientError as e:
|
||||||
|
if e.response[RESPONSE_ERROR][RESPONSE_ERROR_CODE] == RESPONSE_CODE_NO_SUCH_KEY:
|
||||||
|
raise FileNotFoundException('E-05-02', f'通知メール(本文)テンプレートファイルの読み込みに失敗しました エラー内容:{e}')
|
||||||
|
else:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
return mail_body_template
|
||||||
|
|
||||||
|
|
||||||
|
def notice_to_mbj(mail_title: str, mail_body: str) -> None:
|
||||||
|
"""MBJへ通知を行います
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mail_title (str): メールタイトル
|
||||||
|
mail_body (str): メール本文
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
SNSPublishException: SNSでの通知失敗した場合のエラー
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
notifier = SNSNotifier()
|
||||||
|
notifier.publish_to_mbj(mail_title, mail_body)
|
||||||
|
except Exception as e:
|
||||||
|
raise SNSPublishException('E-98', f'通知の送信指示に失敗しました エラー内容:{e}')
|
||||||
|
|
||||||
|
|
||||||
|
def notice_to_nds(error_id: str, error_message: str) -> None:
|
||||||
|
"""NDSに処理以上通知を行う
|
||||||
|
|
||||||
|
Args:
|
||||||
|
error_id (str): エラーID
|
||||||
|
error_message (str): エラーメッセージ
|
||||||
|
Raises:
|
||||||
|
SNSPublishException: SNSでの通知失敗した場合のエラー
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
notifier = SNSNotifier()
|
||||||
|
notifier.publish_to_nds(error_id, error_message)
|
||||||
|
except Exception as e:
|
||||||
|
raise SNSPublishException('E-98', f'通知の送信指示に失敗しました エラー内容:{e}')
|
||||||
|
|
||||||
|
|
||||||
|
# ローカル実行用
|
||||||
|
if __name__ == '__main__':
|
||||||
|
handler({}, {})
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
from constants import LAUNCH_ON_LOCAL, LOG_DATE_FORMAT, LOG_FORMAT
|
||||||
|
from environments import LOG_LEVEL, TZ
|
||||||
|
|
||||||
|
|
||||||
|
class SingletonLogger:
|
||||||
|
__logger: logging.Logger = None
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
# logger設定
|
||||||
|
logger = logging.getLogger()
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
LOG_FORMAT,
|
||||||
|
LOG_DATE_FORMAT
|
||||||
|
)
|
||||||
|
formatter.converter = lambda *arg: datetime.datetime.now(ZoneInfo(TZ)).timetuple()
|
||||||
|
# ローカル環境で動かす場合、標準出力ハンドラーを追加する
|
||||||
|
# AWS Lambda上では`LambdaLoggerHandler`がデフォルトでセットされている
|
||||||
|
if len(sys.argv) == 2 and sys.argv[1] == LAUNCH_ON_LOCAL:
|
||||||
|
localHandler = logging.StreamHandler()
|
||||||
|
logger.addHandler(localHandler)
|
||||||
|
for handler in logger.handlers:
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
level = logging.getLevelName(LOG_LEVEL)
|
||||||
|
logger.setLevel(level)
|
||||||
|
|
||||||
|
self.__logger = logger
|
||||||
|
|
||||||
|
def debug(self, log_id: str, msg: str):
|
||||||
|
self._log(logging.DEBUG, log_id, msg)
|
||||||
|
|
||||||
|
def info(self, log_id: str, msg: str):
|
||||||
|
self._log(logging.INFO, log_id, msg)
|
||||||
|
|
||||||
|
def warning(self, log_id: str, msg: str):
|
||||||
|
self._log(logging.WARNING, log_id, msg)
|
||||||
|
|
||||||
|
def error(self, log_id: str, msg: str):
|
||||||
|
self._log(logging.ERROR, log_id, msg)
|
||||||
|
|
||||||
|
def exception(self, log_id: str, msg: str):
|
||||||
|
self._log(logging.ERROR, log_id, msg, exc_info=True)
|
||||||
|
|
||||||
|
def _log(self, log_level: int, log_id: str, msg: str, exc_info=False):
|
||||||
|
self.__logger.log(log_level, f'{log_id} {msg}', exc_info=exc_info)
|
||||||
|
|
||||||
|
|
||||||
|
class MeDaCaLogger:
|
||||||
|
__unique_instance: logging.Logger = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_logger() -> SingletonLogger:
|
||||||
|
# インスタンス未生成の場合、唯一のインスタンスを生成する
|
||||||
|
if not MeDaCaLogger.__unique_instance:
|
||||||
|
MeDaCaLogger.__unique_instance = SingletonLogger()
|
||||||
|
return MeDaCaLogger.__unique_instance
|
||||||
3
s3/config/view_check/check_target_schemas.json
Normal file
3
s3/config/view_check/check_target_schemas.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"check_target_schemas": ["custom01", "custom02", "custom03"]
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
宛先各位
|
||||||
|
customスキーマの以下のviewに「SQL SECURITY INVOKER」オプションが指定されておりません。viewを再作成しオプションを指定してください。
|
||||||
|
{no_option_views}
|
||||||
|
|
||||||
|
尚、本メールはシステム自動送信ですので、返信できません。
|
||||||
|
本件に関する問い合わせは、IT部門ゴザリ様にお願いいたします。
|
||||||
@ -0,0 +1 @@
|
|||||||
|
【MeDaCaシステム通知】view参照制限オプション指定漏れを検出しました
|
||||||
Loading…
x
Reference in New Issue
Block a user