From 82918483a82ec4c59199e63eb9090825986afb99 Mon Sep 17 00:00:00 2001 From: Steve Mactaggart Date: Sun, 17 Apr 2022 12:09:14 +1000 Subject: [PATCH 1/3] Minor refactor to support alternate dimensions. Support name lookup for LINKED_ACCOUNT dimension. Support for varying the ROWS returned by env. Added support for posting to MS Teams. --- Pipfile.lock | 317 +++++++++++++++++++++++++++++----------------- README.md | 36 ++++++ handler.py | 111 ++++++++++++---- package-lock.json | 137 +++++++++++++++----- package.json | 2 +- serverless.yml | 13 +- 6 files changed, 432 insertions(+), 184 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index e2196c1..96dbef7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "5c8c419cd729bf70fedeac6b1787d5dea302df1663117be123375968adb1797d" + "sha256": "2aa0fb6a5a6da534cfb0818e1e18150bd568f8c371145e005562f330bc37b0c4" }, "pipfile-spec": 6, "requires": { - "python_version": "3.7" + "python_version": "3.9" }, "sources": [ { @@ -18,190 +18,277 @@ "default": { "boto3": { "hashes": [ - "sha256:10e8d9b18a8ae15677e850c7240140b9539635a03098f01dfdd75b2042d15862", - "sha256:aee742f2a2315244fb31a507f65d8809fcd0029508c0b12be8611ddd2075b666" + "sha256:895fb88c69be78f82cfee58a79c97a3ad8d4a2a1209041a411d7d6b9fc5393e4", + "sha256:bcb541175a7d190dd919a0af0e807ee6e9d26f135551e741b10d94343f2d7588" ], "index": "pypi", - "version": "==1.16.60" + "version": "==1.21.42" }, "botocore": { "hashes": [ - "sha256:ad4adfcc195b5401d84b0c65d3a89e507c1d54c201879c8761ff10ef5c361e21", - "sha256:d3694f6ef918def8082513e5ef309cd6cd83b612e9984e3a66e8adc98c650a92" + "sha256:14aee41c8bf59d2dd2d89e8751fa37d3c95dcb92707d1966aa02697e914c1417", + "sha256:a2baa9484bbaee96ef312c049b8e360badcab58329e487b57567644a571b5f4a" ], - "version": "==1.19.63" + "markers": "python_version >= '3.6'", + "version": "==1.24.42" }, "certifi": { "hashes": [ - "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", - "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" ], - "version": "==2021.5.30" + "version": "==2021.10.8" }, - "chardet": { + "charset-normalizer": { "hashes": [ - "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", + "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" ], - "version": "==4.0.0" + "markers": "python_version >= '3'", + "version": "==2.0.12" }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "version": "==2.10" + "markers": "python_version >= '3'", + "version": "==3.3" }, "jmespath": { "hashes": [ - "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9", - "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f" + "sha256:a490e280edd1f57d6de88636992d05b71e97d69a26a19f058ecf7d304474bf5e", + "sha256:e8dcd576ed616f14ec02eed0005c85973b5890083313860136657e24784e4c04" ], - "version": "==0.10.0" + "markers": "python_version >= '3.7'", + "version": "==1.0.0" }, "python-dateutil": { "hashes": [ - "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", - "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "version": "==2.8.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.2" }, "requests": { "hashes": [ - "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", - "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", + "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" ], "index": "pypi", - "version": "==2.25.1" + "version": "==2.27.1" }, "s3transfer": { "hashes": [ - "sha256:35627b86af8ff97e7ac27975fe0a98a312814b46c6333d8a6b889627bcd80994", - "sha256:efa5bd92a897b6a8d5c1383828dca3d52d0790e0756d49740563a3fb6ed03246" + "sha256:7a6f4c4d1fdb9a2b640244008e142cbc2cd3ae34b386584ef044dd0f27101971", + "sha256:95c58c194ce657a5f4fb0b9e60a84968c808888aed628cd98ab8771fe1db98ed" ], - "version": "==0.3.7" + "markers": "python_version >= '3.6'", + "version": "==0.5.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:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c", - "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098" + "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", + "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" ], - "index": "pypi", - "version": "==1.26.5" + "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": { "astroid": { "hashes": [ - "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc", - "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d" + "sha256:8d0a30fe6481ce919f56690076eafbb2fb649142a89dc874f1ec0e7a011492d0", + "sha256:cc8cc0d2d916c42d0a7c476c57550a4557a083081976bf42a73414322a6411d9" ], - "version": "==2.5" + "markers": "python_full_version >= '3.6.2'", + "version": "==2.11.2" + }, + "dill": { + "hashes": [ + "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f", + "sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675" + ], + "markers": "python_version >= '2.7' and python_version != '3.0'", + "version": "==0.3.4" }, "isort": { "hashes": [ - "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6", - "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d" + "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7", + "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951" ], - "version": "==5.8.0" + "markers": "python_version < '4.0' and python_full_version >= '3.6.1'", + "version": "==5.10.1" }, "lazy-object-proxy": { "hashes": [ - "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653", - "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61", - "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2", - "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837", - "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3", - "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43", - "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726", - "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3", - "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587", - "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8", - "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a", - "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd", - "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f", - "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad", - "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4", - "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b", - "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf", - "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981", - "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741", - "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e", - "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93", - "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b" - ], - "version": "==1.6.0" + "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7", + "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a", + "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c", + "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc", + "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f", + "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09", + "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442", + "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e", + "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029", + "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61", + "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb", + "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0", + "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35", + "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42", + "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1", + "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad", + "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443", + "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd", + "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9", + "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148", + "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38", + "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55", + "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36", + "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a", + "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b", + "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44", + "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6", + "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69", + "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4", + "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84", + "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de", + "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28", + "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c", + "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1", + "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8", + "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b", + "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb" + ], + "markers": "python_version >= '3.6'", + "version": "==1.7.1" }, "mccabe": { "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" ], - "version": "==0.6.1" + "markers": "python_version >= '3.6'", + "version": "==0.7.0" + }, + "platformdirs": { + "hashes": [ + "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d", + "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227" + ], + "markers": "python_version >= '3.7'", + "version": "==2.5.1" }, "pylint": { "hashes": [ - "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210", - "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f" + "sha256:c149694cfdeaee1aa2465e6eaab84c87a881a7d55e6e93e09466be7164764d1e", + "sha256:dab221658368c7a05242e673c275c488670144123f4bd262b2777249c1c0de9b" ], "index": "pypi", - "version": "==2.6.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "version": "==0.10.2" - }, - "typed-ast": { - "hashes": [ - "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace", - "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff", - "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266", - "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528", - "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6", - "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808", - "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4", - "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363", - "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341", - "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04", - "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41", - "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e", - "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3", - "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899", - "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805", - "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c", - "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c", - "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39", - "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a", - "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3", - "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7", - "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f", - "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075", - "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0", - "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40", - "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428", - "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927", - "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3", - "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f", - "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65" - ], - "markers": "implementation_name == 'cpython' and python_version < '3.8'", - "version": "==1.4.3" + "version": "==2.13.5" + }, + "setuptools": { + "hashes": [ + "sha256:26ead7d1f93efc0f8c804d9fafafbe4a44b179580a7105754b245155f9af05a8", + "sha256:47c7b0c0f8fc10eec4cf1e71c6fdadf8decaa74ffa087e68cd1c20db7ad6a592" + ], + "markers": "python_version >= '3.7'", + "version": "==62.1.0" + }, + "tomli": { + "hashes": [ + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + ], + "markers": "python_version < '3.11'", + "version": "==2.0.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42", + "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" + ], + "markers": "python_version < '3.10'", + "version": "==4.1.1" }, "wrapt": { "hashes": [ - "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" + "sha256:00108411e0f34c52ce16f81f1d308a571df7784932cc7491d1e94be2ee93374b", + "sha256:01f799def9b96a8ec1ef6b9c1bbaf2bbc859b87545efbecc4a78faea13d0e3a0", + "sha256:09d16ae7a13cff43660155383a2372b4aa09109c7127aa3f24c3cf99b891c330", + "sha256:14e7e2c5f5fca67e9a6d5f753d21f138398cad2b1159913ec9e9a67745f09ba3", + "sha256:167e4793dc987f77fd476862d32fa404d42b71f6a85d3b38cbce711dba5e6b68", + "sha256:1807054aa7b61ad8d8103b3b30c9764de2e9d0c0978e9d3fc337e4e74bf25faa", + "sha256:1f83e9c21cd5275991076b2ba1cd35418af3504667affb4745b48937e214bafe", + "sha256:21b1106bff6ece8cb203ef45b4f5778d7226c941c83aaaa1e1f0f4f32cc148cd", + "sha256:22626dca56fd7f55a0733e604f1027277eb0f4f3d95ff28f15d27ac25a45f71b", + "sha256:23f96134a3aa24cc50614920cc087e22f87439053d886e474638c68c8d15dc80", + "sha256:2498762814dd7dd2a1d0248eda2afbc3dd9c11537bc8200a4b21789b6df6cd38", + "sha256:28c659878f684365d53cf59dc9a1929ea2eecd7ac65da762be8b1ba193f7e84f", + "sha256:2eca15d6b947cfff51ed76b2d60fd172c6ecd418ddab1c5126032d27f74bc350", + "sha256:354d9fc6b1e44750e2a67b4b108841f5f5ea08853453ecbf44c81fdc2e0d50bd", + "sha256:36a76a7527df8583112b24adc01748cd51a2d14e905b337a6fefa8b96fc708fb", + "sha256:3a0a4ca02752ced5f37498827e49c414d694ad7cf451ee850e3ff160f2bee9d3", + "sha256:3a71dbd792cc7a3d772ef8cd08d3048593f13d6f40a11f3427c000cf0a5b36a0", + "sha256:3a88254881e8a8c4784ecc9cb2249ff757fd94b911d5df9a5984961b96113fff", + "sha256:47045ed35481e857918ae78b54891fac0c1d197f22c95778e66302668309336c", + "sha256:4775a574e9d84e0212f5b18886cace049a42e13e12009bb0491562a48bb2b758", + "sha256:493da1f8b1bb8a623c16552fb4a1e164c0200447eb83d3f68b44315ead3f9036", + "sha256:4b847029e2d5e11fd536c9ac3136ddc3f54bc9488a75ef7d040a3900406a91eb", + "sha256:59d7d92cee84a547d91267f0fea381c363121d70fe90b12cd88241bd9b0e1763", + "sha256:5a0898a640559dec00f3614ffb11d97a2666ee9a2a6bad1259c9facd01a1d4d9", + "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7", + "sha256:5b835b86bd5a1bdbe257d610eecab07bf685b1af2a7563093e0e69180c1d4af1", + "sha256:5f24ca7953f2643d59a9c87d6e272d8adddd4a53bb62b9208f36db408d7aafc7", + "sha256:61e1a064906ccba038aa3c4a5a82f6199749efbbb3cef0804ae5c37f550eded0", + "sha256:65bf3eb34721bf18b5a021a1ad7aa05947a1767d1aa272b725728014475ea7d5", + "sha256:6807bcee549a8cb2f38f73f469703a1d8d5d990815c3004f21ddb68a567385ce", + "sha256:68aeefac31c1f73949662ba8affaf9950b9938b712fb9d428fa2a07e40ee57f8", + "sha256:6915682f9a9bc4cf2908e83caf5895a685da1fbd20b6d485dafb8e218a338279", + "sha256:6d9810d4f697d58fd66039ab959e6d37e63ab377008ef1d63904df25956c7db0", + "sha256:729d5e96566f44fccac6c4447ec2332636b4fe273f03da128fff8d5559782b06", + "sha256:748df39ed634851350efa87690c2237a678ed794fe9ede3f0d79f071ee042561", + "sha256:763a73ab377390e2af26042f685a26787c402390f682443727b847e9496e4a2a", + "sha256:8323a43bd9c91f62bb7d4be74cc9ff10090e7ef820e27bfe8815c57e68261311", + "sha256:8529b07b49b2d89d6917cfa157d3ea1dfb4d319d51e23030664a827fe5fd2131", + "sha256:87fa943e8bbe40c8c1ba4086971a6fefbf75e9991217c55ed1bcb2f1985bd3d4", + "sha256:88236b90dda77f0394f878324cfbae05ae6fde8a84d548cfe73a75278d760291", + "sha256:891c353e95bb11abb548ca95c8b98050f3620a7378332eb90d6acdef35b401d4", + "sha256:89ba3d548ee1e6291a20f3c7380c92f71e358ce8b9e48161401e087e0bc740f8", + "sha256:8c6be72eac3c14baa473620e04f74186c5d8f45d80f8f2b4eda6e1d18af808e8", + "sha256:9a242871b3d8eecc56d350e5e03ea1854de47b17f040446da0e47dc3e0b9ad4d", + "sha256:9a3ff5fb015f6feb78340143584d9f8a0b91b6293d6b5cf4295b3e95d179b88c", + "sha256:9a5a544861b21e0e7575b6023adebe7a8c6321127bb1d238eb40d99803a0e8bd", + "sha256:9d57677238a0c5411c76097b8b93bdebb02eb845814c90f0b01727527a179e4d", + "sha256:9d8c68c4145041b4eeae96239802cfdfd9ef927754a5be3f50505f09f309d8c6", + "sha256:9d9fcd06c952efa4b6b95f3d788a819b7f33d11bea377be6b8980c95e7d10775", + "sha256:a0057b5435a65b933cbf5d859cd4956624df37b8bf0917c71756e4b3d9958b9e", + "sha256:a65bffd24409454b889af33b6c49d0d9bcd1a219b972fba975ac935f17bdf627", + "sha256:b0ed6ad6c9640671689c2dbe6244680fe8b897c08fd1fab2228429b66c518e5e", + "sha256:b21650fa6907e523869e0396c5bd591cc326e5c1dd594dcdccac089561cacfb8", + "sha256:b3f7e671fb19734c872566e57ce7fc235fa953d7c181bb4ef138e17d607dc8a1", + "sha256:b77159d9862374da213f741af0c361720200ab7ad21b9f12556e0eb95912cd48", + "sha256:bb36fbb48b22985d13a6b496ea5fb9bb2a076fea943831643836c9f6febbcfdc", + "sha256:d066ffc5ed0be00cd0352c95800a519cf9e4b5dd34a028d301bdc7177c72daf3", + "sha256:d332eecf307fca852d02b63f35a7872de32d5ba8b4ec32da82f45df986b39ff6", + "sha256:d808a5a5411982a09fef6b49aac62986274ab050e9d3e9817ad65b2791ed1425", + "sha256:d9bdfa74d369256e4218000a629978590fd7cb6cf6893251dad13d051090436d", + "sha256:db6a0ddc1282ceb9032e41853e659c9b638789be38e5b8ad7498caac00231c23", + "sha256:debaf04f813ada978d7d16c7dfa16f3c9c2ec9adf4656efdc4defdf841fc2f0c", + "sha256:f0408e2dbad9e82b4c960274214af533f856a199c9274bd4aff55d4634dedc33", + "sha256:f2f3bc7cd9c9fcd39143f11342eb5963317bd54ecc98e3650ca22704b69d9653" ], - "version": "==1.12.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.14.0" } } } diff --git a/README.md b/README.md index 11dc2c1..93eb3ee 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,42 @@ If you have AWS credits on your account and want to see them taken into account --param "credits_remaining=xxx.xx" ``` +## Support for other Dimensions + +If you have and AWS Organisation estaablished and would like to see a breakdown by account, you can override the default dimensions with parameters: + + ``` + serverless deploy \ + --param "slack_url=https://hooks.slack.com/services/xxx/yyy/zzzz" \ + --param "group=LINKED_ACCOUNT" \ + --param "group_length=15" + ``` + +Possible value for `group` are: + +* AZ +* INSTANCE_TYPE +* LINKED_ACCOUNT +* OPERATION +* PURCHASE_TYPE +* SERVICE +* USAGE_TYPE +* PLATFORM +* TENANCY +* RECORD_TYPE +* LEGAL_ENTITY_NAME +* INVOICING_ENTITY +* DEPLOYMENT_OPTION +* DATABASE_ENGINE +* CACHE_ENGINE +* INSTANCE_TYPE_FAMILY +* REGION, BILLING_ENTITY +* RESERVATION_ID +* SAVINGS_PLANS_TYPE +* SAVINGS_PLAN_ARN +* OPERATING_SYSTEM + + ## Other Useful CLI Arguments Related to your AWS account By default, `AWS_PROFILE` and `AWS_REGION` are defaulting to `default` and `us-east-1`. These value can be changed by modifying the environment. For aws account, sensible default is attempted to be retrieved. For example, boto3 is used to try and determine your AWS account alias if it exists, and if not your AWS account ID. diff --git a/handler.py b/handler.py index 79571c6..e003d17 100644 --- a/handler.py +++ b/handler.py @@ -9,7 +9,7 @@ yesterday = datetime.datetime.today() - datetime.timedelta(days=1) week_ago = yesterday - datetime.timedelta(days=n_days) -# It seems that the sparkline symbols don't line up (probalby based on font?) so put them last +# It seems that the sparkline symbols don't line up (probably based on font?) so put them last # Also, leaving out the full block because Slack doesn't like it: '█' sparks = ['▁', '▂', '▃', '▄', '▅', '▆', '▇'] @@ -27,6 +27,7 @@ def sparkline(datapoints): return line + def delta(costs): if (len(costs) > 1 and costs[-1] >= 1 and costs[-2] >= 1): # This only handles positive numbers @@ -35,7 +36,30 @@ def delta(costs): result = 0 return result -def report_cost(event, context, result: dict = None, yesterday: str = None, new_method=True): + +def find_by_key(values: list, key: str, value: str): + for item in values: + if item.get(key) == value: + return item + return None + + +def lambda_handler(event, context): + group_by = os.environ.get("GROUP_BY", "SERVICE") + length = int(os.environ.get("LENGTH", "5")) + + summary, buffer, data = report_cost(group_by=group_by, length=length) + + slack_hook_url = os.environ.get('SLACK_WEBHOOK_URL') + if slack_hook_url: + publish_slack(slack_hook_url, summary, buffer) + + teams_hook_url = os.environ.get('TEAMS_WEBHOOK_URL') + if teams_hook_url: + publish_teams(teams_hook_url, summary, buffer) + + +def report_cost(group_by: str = "SERVICE", length: int = 5, result: dict = None, yesterday: str = None, new_method=True): if yesterday is None: yesterday = datetime.datetime.today() - datetime.timedelta(days=1) @@ -91,7 +115,7 @@ def report_cost(event, context, result: dict = None, yesterday: str = None, new_ "GroupBy": [ { "Type": "DIMENSION", - "Key": "SERVICE", + "Key": group_by, }, ], } @@ -119,27 +143,31 @@ def report_cost(event, context, result: dict = None, yesterday: str = None, new_ start_date = day["TimePeriod"]["Start"] for group in day['Groups']: key = group['Keys'][0] + if group_by == "LINKED_ACCOUNT": + dimension = find_by_key(result["DimensionValueAttributes"], "Value", key) + if dimension: + key += " ("+dimension["Attributes"]["description"]+")" cost = float(group['Metrics']['UnblendedCost']['Amount']) cost_per_day_dict[key][start_date] = cost for key in cost_per_day_dict.keys(): for start_date in list_of_dates: - cost = cost_per_day_dict[key].get(start_date, 0.0) # fallback for sparse data + cost = cost_per_day_dict[key].get(start_date, 0.0) # fallback for sparse data cost_per_day_by_service[key].append(cost) # Sort the map by yesterday's cost most_expensive_yesterday = sorted(cost_per_day_by_service.items(), key=lambda i: i[1][-1], reverse=True) - service_names = [k for k,_ in most_expensive_yesterday[:5]] + service_names = [k for k,_ in most_expensive_yesterday[:length]] longest_name_len = len(max(service_names, key = len)) buffer = f"{'Service':{longest_name_len}} ${'Yday':8} {'∆%':>5} {'Last 7d':7}\n" - for service_name, costs in most_expensive_yesterday[:5]: + for service_name, costs in most_expensive_yesterday[:length]: buffer += f"{service_name:{longest_name_len}} ${costs[-1]:8,.2f} {delta(costs):4.0f}% {sparkline(costs):7}\n" other_costs = [0.0] * n_days - for service_name, costs in most_expensive_yesterday[5:]: + for service_name, costs in most_expensive_yesterday[length:]: for i, cost in enumerate(costs): other_costs[i] += cost @@ -185,23 +213,34 @@ def report_cost(event, context, result: dict = None, yesterday: str = None, new_ else: summary = f"Yesterday's cost for account {account_name} was ${total_costs[-1]:,.2f}" - hook_url = os.environ.get('SLACK_WEBHOOK_URL') - if hook_url: - resp = requests.post( - hook_url, - json={ - "text": summary + "\n\n```\n" + buffer + "\n```", - } - ) + return summary, buffer, cost_per_day_by_service + + +def publish_slack(hook_url, summary, buffer): + + resp = requests.post( + hook_url, + json={ + "text": summary + "\n\n```\n" + buffer + "\n```", + } + ) + + if resp.status_code != 200: + print("HTTP %s: %s" % (resp.status_code, resp.text)) - if resp.status_code != 200: - print("HTTP %s: %s" % (resp.status_code, resp.text)) - else: - print(summary) - print(buffer) - # for running locally to test output - return cost_per_day_by_service +def publish_teams(hook_url, summary, buffer): + + resp = requests.post( + hook_url, + json={ + "text": summary + "\n\n```\n" + buffer + "\n```", + } + ) + + if resp.status_code != 200: + print("HTTP %s: %s" % (resp.status_code, resp.text)) + if __name__ == "__main__": # for running locally to test @@ -211,14 +250,30 @@ def report_cost(event, context, result: dict = None, yesterday: str = None, new_ with open("example_boto3_result2.json", "r") as f: example_result2 = json.load(f) + # summary, buffer, data = report_cost(group_by="LINKED_ACCOUNT") + # print(summary) + # print(buffer) + # + # summary, buffer, data = report_cost(group_by="REGION") + # print(summary) + # print(buffer) + # + # summary, buffer, data = report_cost(group_by="USAGE_TYPE", length=20) + # print(summary) + # print(buffer) + # + # summary, buffer, data = report_cost(group_by="SERVICE", length=20) + # print(summary) + # print(buffer) + # New Method with 2 example jsons - cost_dict = report_cost(None, None, example_result, yesterday="2021-08-23", new_method=True) - assert "{0:.2f}".format(cost_dict.get("total", 0.0)) == "286.37", f'{cost_dict.get("total"):,.2f} != 286.37' - cost_dict = report_cost(None, None, example_result2, yesterday="2021-08-29", new_method=True) + summary, buffer, cost_dict = report_cost(None, None, example_result, yesterday="2021-08-23", new_method=True) + assert "{0:.2f}".format(cost_dict.get("total", 0.0)) == "286.37", f'{cost_dict.get("total"):,.2f} != 286.37' + summary, buffer, cost_dict = report_cost(None, None, example_result2, yesterday="2021-08-29", new_method=True) assert "{0:.2f}".format(cost_dict.get("total", 0.0)) == "21.45", f'{cost_dict.get("total"):,.2f} != 21.45' # Old Method with same jsons (will fail) - cost_dict = report_cost(None, None, example_result, yesterday="2021-08-23", new_method=False) - assert "{0:.2f}".format(cost_dict.get("total", 0.0)) == "286.37", f'{cost_dict.get("total"):,.2f} != 286.37' - cost_dict = report_cost(None, None, example_result2, yesterday="2021-08-29", new_method=False) + summary, buffer, cost_dict = report_cost(None, None, example_result, yesterday="2021-08-23", new_method=False) + assert "{0:.2f}".format(cost_dict.get("total", 0.0)) == "286.37", f'{cost_dict.get("total"):,.2f} != 286.37' + summary, buffer, cost_dict = report_cost(None, None, example_result2, yesterday="2021-08-29", new_method=False) assert "{0:.2f}".format(cost_dict.get("total", 0.0)) == "21.45", f'{cost_dict.get("total"):,.2f} != 21.45' diff --git a/package-lock.json b/package-lock.json index 14d1946..065ec84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "aws-billing-to-slack", "version": "0.1.0", "devDependencies": { - "serverless-python-requirements": "^5.3.1" + "serverless-python-requirements": "^5.4.0" } }, "node_modules/@iarna/toml": { @@ -2227,9 +2227,9 @@ } }, "node_modules/glob-all": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.2.1.tgz", - "integrity": "sha512-x877rVkzB3ipid577QOp+eQCR6M5ZyiwrtaYgrX/z3EThaSPFtLDwBXFHc3sH1cG0R0vFYI5SRYeWMMSEyXkUw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.3.0.tgz", + "integrity": "sha512-30gCh9beSb+YSAh0vsoIlBRm4bSlyMa+5nayax1EJhjwYrCohX0aDxcxvWVe3heOrJikbHgRs75Af6kPLcumew==", "dev": true, "dependencies": { "glob": "^7.1.2", @@ -2571,6 +2571,27 @@ "node": ">=0.10.0" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-primitive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", + "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -2624,6 +2645,15 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", @@ -2907,12 +2937,6 @@ "dev": true, "peer": true }, - "node_modules/lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", - "dev": true - }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -4120,9 +4144,9 @@ } }, "node_modules/serverless-python-requirements": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-5.3.1.tgz", - "integrity": "sha512-biow8JZtPNs8Sv4vydTBJlRxOsKrvuZugzTbLDYlviS1uBdGN60ShTKLIv8Oa4sedO7Rhb+THELIIewuLdJgfQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-5.4.0.tgz", + "integrity": "sha512-0ji96KayLG3G3vxtHS6GRcU2879tFPk6gAaRejRkPCf4RxmbebWjIbf56xljRi7DmBzhmxLJd93FVGPq9aundQ==", "dev": true, "dependencies": { "@iarna/toml": "^2.2.5", @@ -4130,14 +4154,14 @@ "bluebird": "^3.7.2", "child-process-ext": "^2.1.1", "fs-extra": "^9.1.0", - "glob-all": "^3.2.1", + "glob-all": "^3.3.0", "is-wsl": "^2.2.0", "jszip": "^3.7.1", "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", "lodash.uniqby": "^4.7.0", "lodash.values": "^4.3.0", "rimraf": "^3.0.2", + "set-value": "^4.1.0", "sha256-file": "1.0.0", "shell-quote": "^1.7.3" }, @@ -4163,6 +4187,24 @@ "node": ">=0.10.0" } }, + "node_modules/set-value": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", + "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/jonschlinkert", + "https://paypal.me/jonathanschlinkert", + "https://jonschlinkert.dev/sponsor" + ], + "dependencies": { + "is-plain-object": "^2.0.4", + "is-primitive": "^3.0.1" + }, + "engines": { + "node": ">=11.0" + } + }, "node_modules/sha256-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/sha256-file/-/sha256-file-1.0.0.tgz", @@ -4902,9 +4944,9 @@ } }, "node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "node_modules/yallist": { @@ -6822,9 +6864,9 @@ } }, "glob-all": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.2.1.tgz", - "integrity": "sha512-x877rVkzB3ipid577QOp+eQCR6M5ZyiwrtaYgrX/z3EThaSPFtLDwBXFHc3sH1cG0R0vFYI5SRYeWMMSEyXkUw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.3.0.tgz", + "integrity": "sha512-30gCh9beSb+YSAh0vsoIlBRm4bSlyMa+5nayax1EJhjwYrCohX0aDxcxvWVe3heOrJikbHgRs75Af6kPLcumew==", "dev": true, "requires": { "glob": "^7.1.2", @@ -7088,6 +7130,21 @@ "dev": true, "peer": true }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-primitive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", + "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", + "dev": true + }, "is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -7129,6 +7186,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", @@ -7390,12 +7453,6 @@ "dev": true, "peer": true }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", - "dev": true - }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -8285,9 +8342,9 @@ } }, "serverless-python-requirements": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-5.3.1.tgz", - "integrity": "sha512-biow8JZtPNs8Sv4vydTBJlRxOsKrvuZugzTbLDYlviS1uBdGN60ShTKLIv8Oa4sedO7Rhb+THELIIewuLdJgfQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-5.4.0.tgz", + "integrity": "sha512-0ji96KayLG3G3vxtHS6GRcU2879tFPk6gAaRejRkPCf4RxmbebWjIbf56xljRi7DmBzhmxLJd93FVGPq9aundQ==", "dev": true, "requires": { "@iarna/toml": "^2.2.5", @@ -8295,14 +8352,14 @@ "bluebird": "^3.7.2", "child-process-ext": "^2.1.1", "fs-extra": "^9.1.0", - "glob-all": "^3.2.1", + "glob-all": "^3.3.0", "is-wsl": "^2.2.0", "jszip": "^3.7.1", "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", "lodash.uniqby": "^4.7.0", "lodash.values": "^4.3.0", "rimraf": "^3.0.2", + "set-value": "^4.1.0", "sha256-file": "1.0.0", "shell-quote": "^1.7.3" } @@ -8319,6 +8376,16 @@ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, + "set-value": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", + "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "is-primitive": "^3.0.1" + } + }, "sha256-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/sha256-file/-/sha256-file-1.0.0.tgz", @@ -8920,9 +8987,9 @@ "peer": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yallist": { diff --git a/package.json b/package.json index 62ed281..f3e1711 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,6 @@ "description": "", "version": "0.1.0", "devDependencies": { - "serverless-python-requirements": "^5.3.1" + "serverless-python-requirements": "^5.4.0" } } diff --git a/serverless.yml b/serverless.yml index 3252ea7..700990b 100644 --- a/serverless.yml +++ b/serverless.yml @@ -5,7 +5,7 @@ plugins: provider: name: aws # Sane defaults, easy for multi-account/multi-region organizations - profile: ${param:aws_profile, env:AWS_PROFILE, 'default'} +# profile: ${param:aws_profile, env:AWS_PROFILE, 'default'} region: ${env:AWS_REGION, env:AWS_DEFAULT_REGION, 'us-east-1'} runtime: python3.9 @@ -24,9 +24,9 @@ provider: functions: report_cost: - handler: handler.report_cost + handler: handler.lambda_handler - description: Send account daily billing data to Slack channel + description: Send account daily billing data to Slack/Teams # Keep costs minimal memorySize: 128 @@ -37,8 +37,11 @@ functions: - schedule: cron(0 15 * * ? *) environment: - SLACK_WEBHOOK_URL: ${param:slack_url} + GROUP_BY: ${param:group, 'SERVICE'} + LENGTH: ${param:group_length, 10} + SLACK_WEBHOOK_URL: ${param:slack_url, ''} + TEAMS_WEBHOOK_URL: ${param:teams_url, ''} AWS_ACCOUNT_NAME: ${param:aws_account, ''} CREDITS_EXPIRE_DATE: ${param:credits_expire_date, ''} CREDITS_REMAINING_AS_OF: ${param:credits_remaining_date, ''} - CREDITS_REMAINING: ${param:credits_remaining, ''} + CREDITS_REMAINING: ${param:credits_remaining, ''} \ No newline at end of file From cad4c3a4dc0329bfb4ae940f0225e708fa84ba3d Mon Sep 17 00:00:00 2001 From: Steve Mactaggart Date: Sun, 17 Apr 2022 12:11:19 +1000 Subject: [PATCH 2/3] Reverted profile comment. --- serverless.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serverless.yml b/serverless.yml index 700990b..785465c 100644 --- a/serverless.yml +++ b/serverless.yml @@ -5,7 +5,7 @@ plugins: provider: name: aws # Sane defaults, easy for multi-account/multi-region organizations -# profile: ${param:aws_profile, env:AWS_PROFILE, 'default'} + profile: ${param:aws_profile, env:AWS_PROFILE, 'default'} region: ${env:AWS_REGION, env:AWS_DEFAULT_REGION, 'us-east-1'} runtime: python3.9 From c3152deaaaeb38e21c2f587991df7de58fb638b6 Mon Sep 17 00:00:00 2001 From: Ian Dees Date: Sat, 16 Apr 2022 21:25:37 -0500 Subject: [PATCH 3/3] Fixing typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93eb3ee..f0dc5b6 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ If you have AWS credits on your account and want to see them taken into account ## Support for other Dimensions -If you have and AWS Organisation estaablished and would like to see a breakdown by account, you can override the default dimensions with parameters: +If you have and AWS Organisation established and would like to see a breakdown by account, you can override the default dimensions with parameters: ``` serverless deploy \