first commit from local project
commit
0b2549d520
@ -0,0 +1,9 @@
|
|||||||
|
.venv
|
||||||
|
venv
|
||||||
|
.env
|
||||||
|
.idea
|
||||||
|
*.zip
|
||||||
|
*.tar
|
||||||
|
*.tar.gz
|
||||||
|
config.py
|
||||||
|
zappa_settings.json
|
@ -0,0 +1,14 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
pyramid = "*"
|
||||||
|
zappa = "*"
|
||||||
|
boto3 = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.6"
|
@ -0,0 +1,344 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "55e0fb489f47c86e4c53aaf61bbbb75bb2628725636eb1c7ca4dbbc4a09145e6"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.6"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"argcomplete": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c079ceb0b72d4d4e03531ed77e6071babb9d42c3f790d7def2c41295b4990b44",
|
||||||
|
"sha256:d97b7f3cfaa4e494ad59ed6d04c938fc5ed69b590bd8f53274e258fb1119bd1b"
|
||||||
|
],
|
||||||
|
"version": "==1.9.3"
|
||||||
|
},
|
||||||
|
"base58": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:93fa54b615a7c406701a56e3d11c3a5defdbcd371f36c0452f1ac77623e42d16",
|
||||||
|
"sha256:c5fe8b00fab798b4a3393da6235bdecb143db505833e3f979890f7c6fc99f651"
|
||||||
|
],
|
||||||
|
"version": "==1.0.0"
|
||||||
|
},
|
||||||
|
"boto3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:08f268d6eb3347061384e144121dcca1e454a7a8b6c8424a23d3a312cdebab68",
|
||||||
|
"sha256:ce462e7505c03c3e6708ce6f264ac43d478886082af703ff69c502592df5d4f3"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.7.58"
|
||||||
|
},
|
||||||
|
"botocore": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:17a88a578161dc12ecf14950afa93a354cf009380977921f7f52891acc5e751a",
|
||||||
|
"sha256:e0e6b6d1fdbce81c28151136ee919d2cdeee13041559710cd5c93d7e4035a455"
|
||||||
|
],
|
||||||
|
"version": "==1.10.58"
|
||||||
|
},
|
||||||
|
"certifi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
|
||||||
|
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
|
||||||
|
],
|
||||||
|
"version": "==2018.4.16"
|
||||||
|
},
|
||||||
|
"cfn-flip": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:9c61039c71995ab204c005ec46d47d0f7a109e9f1b6d63569397f8bc648a8151"
|
||||||
|
],
|
||||||
|
"version": "==1.0.3"
|
||||||
|
},
|
||||||
|
"chardet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||||
|
],
|
||||||
|
"version": "==3.0.4"
|
||||||
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
|
||||||
|
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
|
||||||
|
],
|
||||||
|
"version": "==6.7"
|
||||||
|
},
|
||||||
|
"docutils": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
||||||
|
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
|
||||||
|
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
|
||||||
|
],
|
||||||
|
"version": "==0.14"
|
||||||
|
},
|
||||||
|
"durationpy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5ef9416b527b50d722f34655becfb75e49228eb82f87b855ed1911b3314b5408"
|
||||||
|
],
|
||||||
|
"version": "==0.5"
|
||||||
|
},
|
||||||
|
"future": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
|
||||||
|
],
|
||||||
|
"version": "==0.16.0"
|
||||||
|
},
|
||||||
|
"futures": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265",
|
||||||
|
"sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1"
|
||||||
|
],
|
||||||
|
"version": "==3.2.0"
|
||||||
|
},
|
||||||
|
"hjson": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1d1727faa6aaef2973921877125a3ab7c5f6d34b93233179d01770f41fab51f9"
|
||||||
|
],
|
||||||
|
"version": "==3.0.1"
|
||||||
|
},
|
||||||
|
"hupper": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:20387760e4d32bd4813c2cabc8e51d92b2c22c546102a0af182c33c152cd7ede",
|
||||||
|
"sha256:6b8133e9c5cc0a8ec422a29ef3b38aea2c49a809a0af73f419a78a7015b32615"
|
||||||
|
],
|
||||||
|
"version": "==1.3"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
|
||||||
|
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
|
||||||
|
],
|
||||||
|
"version": "==2.7"
|
||||||
|
},
|
||||||
|
"jmespath": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64",
|
||||||
|
"sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63"
|
||||||
|
],
|
||||||
|
"version": "==0.9.3"
|
||||||
|
},
|
||||||
|
"kappa": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4b5b372872f25d619e427e04282551048dc975a107385b076b3ffc6406a15833",
|
||||||
|
"sha256:4d6b7b3accce4a0aaaac92b36237a6304f0f2fffbbe3caea3f7c9f52d12c9989"
|
||||||
|
],
|
||||||
|
"version": "==0.6.0"
|
||||||
|
},
|
||||||
|
"lambda-packages": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:b5e3b81ecef5f7c1b0903b5c40813536ba2343a33868a567e4e4ff1e26243406"
|
||||||
|
],
|
||||||
|
"version": "==0.20.0"
|
||||||
|
},
|
||||||
|
"pastedeploy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:39973e73f391335fac8bc8a8a95f7d34a9f42e2775600ce2dc518d93b37ef943",
|
||||||
|
"sha256:d5858f89a255e6294e63ed46b73613c56e3b9a2d82a42f1df4d06c8421a9e3cb"
|
||||||
|
],
|
||||||
|
"version": "==1.5.2"
|
||||||
|
},
|
||||||
|
"placebo": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8aa848b892924786fa5e37e75524e8ec039b7d54860d35c51ffb4ed3e30590c5"
|
||||||
|
],
|
||||||
|
"version": "==0.8.1"
|
||||||
|
},
|
||||||
|
"plaster": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:215c921a438b5349931fd7df9a5a11a3572947f20f4bc6dd622ac08f1c3ba249",
|
||||||
|
"sha256:8351c7c7efdf33084c1de88dd0f422cbe7342534537b553c49b857b12d98c8c3"
|
||||||
|
],
|
||||||
|
"version": "==1.0"
|
||||||
|
},
|
||||||
|
"plaster-pastedeploy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:71e29b0ab90df8343bca5f0debe4706f0f8147308a78922c8c26e8252809bce4",
|
||||||
|
"sha256:c231130cb86ae414084008fe1d1797db7e61dc5eaafb5e755de21387c27c6fae"
|
||||||
|
],
|
||||||
|
"version": "==0.6"
|
||||||
|
},
|
||||||
|
"pyramid": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:600f12e0d11211a55c2da970120af33214f77607ed45caba6af6c891afeaa771",
|
||||||
|
"sha256:cf89a48cb899291639686bf3d4a883b39e496151fa4871fb83cc1a3200d5b925"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.9.2"
|
||||||
|
},
|
||||||
|
"python-dateutil": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca",
|
||||||
|
"sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7'",
|
||||||
|
"version": "==2.6.1"
|
||||||
|
},
|
||||||
|
"python-slugify": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:57a385df7a1c6dbd15f7666eaff0ff29d3f60363b228b1197c5308ed3ba5f824",
|
||||||
|
"sha256:c3733135d3b184196fdb8844f6a74bbfb9cf6720d1dcce3254bdc434353f938f"
|
||||||
|
],
|
||||||
|
"version": "==1.2.4"
|
||||||
|
},
|
||||||
|
"pyyaml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8",
|
||||||
|
"sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736",
|
||||||
|
"sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f",
|
||||||
|
"sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608",
|
||||||
|
"sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8",
|
||||||
|
"sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab",
|
||||||
|
"sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7",
|
||||||
|
"sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3",
|
||||||
|
"sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1",
|
||||||
|
"sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6",
|
||||||
|
"sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8",
|
||||||
|
"sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4",
|
||||||
|
"sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca",
|
||||||
|
"sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269"
|
||||||
|
],
|
||||||
|
"version": "==3.12"
|
||||||
|
},
|
||||||
|
"repoze.lru": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0429a75e19380e4ed50c0694e26ac8819b4ea7851ee1fc7583c8572db80aff77",
|
||||||
|
"sha256:f77bf0e1096ea445beadd35f3479c5cff2aa1efe604a133e67150bc8630a62ea"
|
||||||
|
],
|
||||||
|
"version": "==0.7"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
|
||||||
|
"sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
|
||||||
|
],
|
||||||
|
"version": "==2.19.1"
|
||||||
|
},
|
||||||
|
"s3transfer": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:90dc18e028989c609146e241ea153250be451e05ecc0c2832565231dacdf59c1",
|
||||||
|
"sha256:c7a9ec356982d5e9ab2d4b46391a7d6a950e2b04c472419f5fdec70cc0ada72f"
|
||||||
|
],
|
||||||
|
"version": "==0.1.13"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
|
||||||
|
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
|
||||||
|
],
|
||||||
|
"version": "==1.11.0"
|
||||||
|
},
|
||||||
|
"toml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f73e3baab2d"
|
||||||
|
],
|
||||||
|
"version": "==0.9.4"
|
||||||
|
},
|
||||||
|
"tqdm": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ba650e08b8b102923a05896bf9d7e1c9cdc20b484156df0511a4bbf1f6b6f89b",
|
||||||
|
"sha256:fa6d2ea6285f56e75d7efe9259805deadc450f16066a1f82ad0629ea9be2cd0f"
|
||||||
|
],
|
||||||
|
"version": "==4.19.1"
|
||||||
|
},
|
||||||
|
"translationstring": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4ee44cfa58c52ade8910ea0ebc3d2d84bdcad9fa0422405b1801ec9b9a65b72d",
|
||||||
|
"sha256:e26c7bf383413234ed442e0980a2ebe192b95e3745288a8fd2805156d27515b4"
|
||||||
|
],
|
||||||
|
"version": "==1.3"
|
||||||
|
},
|
||||||
|
"troposphere": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:aecc32359326634c9911ae4bea05d308822b827787926dcc038c153410ce380b"
|
||||||
|
],
|
||||||
|
"version": "==2.3.1"
|
||||||
|
},
|
||||||
|
"unidecode": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:72f49d3729f3d8f5799f710b97c1451c5163102e76d64d20e170aedbbd923582",
|
||||||
|
"sha256:8c33dd588e0c9bc22a76eaa0c715a5434851f726131bd44a6c26471746efabf5"
|
||||||
|
],
|
||||||
|
"version": "==1.0.22"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
|
||||||
|
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
|
||||||
|
],
|
||||||
|
"version": "==1.23"
|
||||||
|
},
|
||||||
|
"venusian": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:757162c5f907e18571b6ab41b7673e5bf18cc8715abf8164292eaef4f1610668",
|
||||||
|
"sha256:9902e492c71a89a241a18b2f9950bea7e41d025cc8f3af1ea8d8201346f8577d"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"webob": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1fe722f2ab857685fc96edec567dc40b1875b21219b3b348e58cd8c4d5ea7df3",
|
||||||
|
"sha256:263690003a3e092ca1ec4df787f93feb0004e39d7bac9cba2c19a552c765894b"
|
||||||
|
],
|
||||||
|
"version": "==1.8.2"
|
||||||
|
},
|
||||||
|
"werkzeug": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
|
||||||
|
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
|
||||||
|
],
|
||||||
|
"version": "==0.14.1"
|
||||||
|
},
|
||||||
|
"wheel": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0a2e54558a0628f2145d2fc822137e322412115173e8a2ddbe1c9024338ae83c",
|
||||||
|
"sha256:80044e51ec5bbf6c894ba0bc48d26a8c20a9ba629f4ca19ea26ecfcf87685f5f"
|
||||||
|
],
|
||||||
|
"version": "==0.31.1"
|
||||||
|
},
|
||||||
|
"wsgi-request-logger": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:445d7ec52799562f812006394d0b4a7064b37084c6ea6bd74ea7a2136c97ed83"
|
||||||
|
],
|
||||||
|
"version": "==0.4.6"
|
||||||
|
},
|
||||||
|
"zappa": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:cb70195801efb8ae50c78d5180640afe1bcb9317d3c11da97b6d3588b90aea89",
|
||||||
|
"sha256:d841b2ca57c80c2fe5cd9098763ab26f59580658838eb77fcdefeed894543d45"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.46.1"
|
||||||
|
},
|
||||||
|
"zope.deprecation": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7d52e134bbaaa0d72e1e2bc90f0587f1adc116c4bdf15912afaf2f1e8856b224",
|
||||||
|
"sha256:c83cfef3085d10dcb07de5a59a2d95713865befa46e0e88784c5648610fba789"
|
||||||
|
],
|
||||||
|
"version": "==4.3.0"
|
||||||
|
},
|
||||||
|
"zope.interface": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:21506674d30c009271fe68a242d330c83b1b9d76d62d03d87e1e9528c61beea6",
|
||||||
|
"sha256:3d184aff0756c44fff7de69eb4cd5b5311b6f452d4de28cb08343b3f21993763",
|
||||||
|
"sha256:467d364b24cb398f76ad5e90398d71b9325eb4232be9e8a50d6a3b3c7a1c8789",
|
||||||
|
"sha256:57c38470d9f57e37afb460c399eb254e7193ac7fb8042bd09bdc001981a9c74c",
|
||||||
|
"sha256:9ada83f4384bbb12dedc152bcdd46a3ac9f5f7720d43ac3ce3e8e8b91d733c10",
|
||||||
|
"sha256:a1daf9c5120f3cc6f2b5fef8e1d2a3fb7bbbb20ed4bfdc25bc8364bc62dcf54b",
|
||||||
|
"sha256:e6b77ae84f2b8502d99a7855fa33334a1eb6159de45626905cb3e454c023f339",
|
||||||
|
"sha256:e881ef610ff48aece2f4ee2af03d2db1a146dc7c705561bd6089b2356f61641f",
|
||||||
|
"sha256:f41037260deaacb875db250021fe883bf536bf6414a4fd25b25059b02e31b120"
|
||||||
|
],
|
||||||
|
"version": "==4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
# owntracks-aws-slt
|
||||||
|
|
||||||
|
Serverless location tracking HTTP endpoints for use with [Owntracks](https://owntracks.org). Uses several [AWS](https://aws.amazon.com) services:
|
||||||
|
|
||||||
|
* **API Gateway** - Provides HTTP endpoints to point Owntracks client at
|
||||||
|
* **Lambda** - Processes incoming data streams and performs queries, cleanups, notifications, etc
|
||||||
|
* **S3** - Stores incoming messages
|
||||||
|
|
||||||
|
The backend code is written in Python 3.6 and makes use of the [Pyramid](https://pylonsproject.org) web framework.
|
||||||
|
|
||||||
|
Everything is deployed and managed using the [Zappa](https://github.com/Miserlou/Zappa) serverless management framework.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Before you can use this tool, you must have these prerequisites:
|
||||||
|
|
||||||
|
* Amazon Web Services account
|
||||||
|
* Administrative IAM API key pair configured on your computer
|
||||||
|
* Pipenv installed on your computer
|
||||||
|
* Python 3.6 installed on your computer
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Assuming you have all the requirements met, the following steps will create everything needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ git clone https://github.com/lalanza808/owntracks-aws-slt.git
|
||||||
|
$ cd owntracks-aws-slt
|
||||||
|
$ pipenv install --python 3.6
|
||||||
|
$ zappa init
|
||||||
|
$ zappa deploy live
|
||||||
|
```
|
||||||
|
|
||||||
|
The Zappa output should provide you with an endpoint for API Gateway - the HTTP endpoints with Python Lambda scripts being triggered behind them.
|
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import functions as lambda_functions
|
||||||
|
import config as app_config
|
||||||
|
|
||||||
|
from wsgiref.simple_server import make_server
|
||||||
|
from pyramid.view import view_config, view_defaults
|
||||||
|
from pyramid.config import Configurator
|
||||||
|
from configparser import ConfigParser
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
# Generate routes and views for each device and build the app
|
||||||
|
def configure_app():
|
||||||
|
with Configurator() as config:
|
||||||
|
for device_name in app_config.devices:
|
||||||
|
device_key = app_config.devices[device_name]
|
||||||
|
config.add_route(
|
||||||
|
device_name,
|
||||||
|
'/device/{}'.format(device_key)
|
||||||
|
)
|
||||||
|
config.add_view(
|
||||||
|
lambda_functions.ingest,
|
||||||
|
route_name=device_name,
|
||||||
|
renderer='json'
|
||||||
|
)
|
||||||
|
app = config.make_wsgi_app()
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
# API Gateway/Zappa function handler
|
||||||
|
def generate_wsgi_app(app, environ):
|
||||||
|
wsgi_app = configure_app()
|
||||||
|
return wsgi_app(app, environ)
|
||||||
|
|
||||||
|
|
||||||
|
# Local web server for development
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("[+] Starting local web server on port 8080...")
|
||||||
|
server = make_server('0.0.0.0', 8080, configure_app())
|
||||||
|
server.serve_forever()
|
@ -0,0 +1,11 @@
|
|||||||
|
devices = {
|
||||||
|
'my_device': 'device_secret_string'
|
||||||
|
}
|
||||||
|
|
||||||
|
backend = {
|
||||||
|
's3': {
|
||||||
|
'name': 'MYLOGBUCKETNAME',
|
||||||
|
'region': 'us-west-2',
|
||||||
|
'retention': 365
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from json import dumps
|
||||||
|
import config as app_config
|
||||||
|
import boto3
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
bucket_name = app_config.backend['s3']['name']
|
||||||
|
bucket_region = app_config.backend['s3']['region']
|
||||||
|
|
||||||
|
athena = boto3.client('athena')
|
||||||
|
|
||||||
|
query_tmpl = '''
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
history
|
||||||
|
WHERE
|
||||||
|
token = '%(token)s'
|
||||||
|
AND
|
||||||
|
year = %(year)d
|
||||||
|
AND
|
||||||
|
month = %(month)d
|
||||||
|
AND
|
||||||
|
day = %(day)d
|
||||||
|
ORDER BY
|
||||||
|
timestamp asc
|
||||||
|
'''
|
||||||
|
|
||||||
|
response = athena.start_query_execution(
|
||||||
|
QueryString=query,
|
||||||
|
QueryExecutionContext={
|
||||||
|
'Database': 'locations'
|
||||||
|
},
|
||||||
|
ResultConfiguration={
|
||||||
|
'OutputLocation': output_location
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
print('Execution scheduled with ID -> ', response['QueryExecutionId'])
|
||||||
|
|
||||||
|
def ingest(request):
|
||||||
|
"""Ingest incoming JSON data from Owntracks devices into S3"""
|
||||||
|
now = datetime.now()
|
||||||
|
device_name = request.matched_route.name
|
||||||
|
|
||||||
|
# https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1
|
||||||
|
if request.method == "POST":
|
||||||
|
s3 = boto3.client("s3")
|
||||||
|
json_data = request.json_body
|
||||||
|
json_data["device_name"] = device_name
|
||||||
|
s3.put_object(
|
||||||
|
ACL="private",
|
||||||
|
Body=dumps(json_data),
|
||||||
|
Bucket=bucket_name,
|
||||||
|
Key="year={}/month={}/day={}/{}.json".format(
|
||||||
|
now.year, now.month, now.day, json_data["tst"]
|
||||||
|
),
|
||||||
|
ServerSideEncryption='AES256'
|
||||||
|
)
|
||||||
|
response_code = 202
|
||||||
|
else:
|
||||||
|
response_code = 204
|
||||||
|
|
||||||
|
return {
|
||||||
|
"response": response_code,
|
||||||
|
"method": request.method,
|
||||||
|
"device": device_name
|
||||||
|
}
|
@ -0,0 +1,175 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from botocore.client import ClientError
|
||||||
|
from datetime import datetime
|
||||||
|
from json import dumps
|
||||||
|
import config as app_config
|
||||||
|
import boto3
|
||||||
|
|
||||||
|
|
||||||
|
bucket_name = app_config.backend["s3"]["name"]
|
||||||
|
bucket_region = app_config.backend["s3"]["region"]
|
||||||
|
bucket_retention = app_config.backend["s3"]["retention"]
|
||||||
|
account_id = boto3.client("sts").get_caller_identity().get("Account")
|
||||||
|
glue_role_name = "AWSGlue-{}".format(bucket_name)
|
||||||
|
glue_policy_name = "AWSGlue-{}-ReadOnly".format(bucket_name)
|
||||||
|
glue_policy_arn = "arn:aws:iam::{account_id}:policy/{policy_name}".format(account_id=account_id, policy_name=glue_policy_name)
|
||||||
|
glue_managed_policy = "arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole"
|
||||||
|
glue_assume_policy = {
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {
|
||||||
|
"Service": "glue.amazonaws.com"
|
||||||
|
},
|
||||||
|
"Action": "sts:AssumeRole"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
glue_custom_policy = {
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": "s3:Get*",
|
||||||
|
"Resource": "arn:aws:s3:::{}/*".format(bucket_name)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_bucket():
|
||||||
|
"""Create the s3 bucket used for capturing log data if it doesn"t exist already"""
|
||||||
|
s3 = boto3.resource("s3")
|
||||||
|
# s3c = boto3.client("s3")
|
||||||
|
# s3c.put_bucket_lifecycle_configuration(
|
||||||
|
# Bucket=bucket_name,
|
||||||
|
# LifecycleConfiguration={
|
||||||
|
# "Rules": [
|
||||||
|
# {
|
||||||
|
# "Expiration": {
|
||||||
|
# "Days": bucket_retention,
|
||||||
|
# "ExpiredObjectDeleteMarker": True
|
||||||
|
# },
|
||||||
|
# "Status": "Enabled"
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
|
||||||
|
try:
|
||||||
|
s3.meta.client.head_bucket(Bucket=bucket_name)
|
||||||
|
|
||||||
|
except ClientError:
|
||||||
|
s3.create_bucket(
|
||||||
|
ACL="private",
|
||||||
|
Bucket=bucket_name,
|
||||||
|
CreateBucketConfiguration={
|
||||||
|
"LocationConstraint": bucket_region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def create_glue_iam():
|
||||||
|
"""Create the required IAM roles for AWS Glue to assume"""
|
||||||
|
iam = boto3.client("iam")
|
||||||
|
res = boto3.resource("iam")
|
||||||
|
|
||||||
|
# Ensure IAM role exists
|
||||||
|
try:
|
||||||
|
res.meta.client.get_role(RoleName=glue_role_name)
|
||||||
|
pass
|
||||||
|
except ClientError:
|
||||||
|
iam.create_role(
|
||||||
|
RoleName=glue_role_name,
|
||||||
|
AssumeRolePolicyDocument=dumps(glue_assume_policy)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure custom IAM policy exists
|
||||||
|
try:
|
||||||
|
res.meta.client.get_policy(PolicyArn=glue_policy_arn)
|
||||||
|
pass
|
||||||
|
except ClientError:
|
||||||
|
iam.create_policy(
|
||||||
|
PolicyName=glue_policy_name,
|
||||||
|
PolicyDocument=dumps(glue_custom_policy)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure custom Glue policy is attached to role
|
||||||
|
try:
|
||||||
|
res.meta.client.attach_role_policy(
|
||||||
|
RoleName=glue_role_name,
|
||||||
|
PolicyArn=glue_policy_arn
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
except ClientError:
|
||||||
|
iam.attach_role_policy(
|
||||||
|
RoleName=glue_role_name,
|
||||||
|
PolicyArn=glue_policy_arn
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure managed Glue policy is attached to role
|
||||||
|
try:
|
||||||
|
res.meta.client.attach_role_policy(
|
||||||
|
RoleName=glue_role_name,
|
||||||
|
PolicyArn=glue_managed_policy
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
except ClientError:
|
||||||
|
iam.attach_role_policy(
|
||||||
|
RoleName=glue_role_name,
|
||||||
|
PolicyArn=glue_managed_policy
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def create_glue():
|
||||||
|
"""Sets up the Glue database and crawler"""
|
||||||
|
glue = boto3.client("glue")
|
||||||
|
|
||||||
|
# Ensure Glue database exists
|
||||||
|
try:
|
||||||
|
glue.get_database(Name=bucket_name)
|
||||||
|
pass
|
||||||
|
except ClientError:
|
||||||
|
glue.create_database(
|
||||||
|
DatabaseInput={
|
||||||
|
"Name": bucket_name,
|
||||||
|
"Description": "Owntracks SLT database"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure Glue crawler exists and run it if you create it
|
||||||
|
try:
|
||||||
|
glue.get_crawler(Name=bucket_name)
|
||||||
|
pass
|
||||||
|
except ClientError:
|
||||||
|
glue.create_crawler(
|
||||||
|
Name=bucket_name,
|
||||||
|
Description="Owntracks SLT data crawler",
|
||||||
|
Role=glue_role_name,
|
||||||
|
DatabaseName=bucket_name,
|
||||||
|
Targets={
|
||||||
|
"S3Targets": [{
|
||||||
|
"Path": "s3://{}/".format(bucket_name)
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
glue.start_crawler(
|
||||||
|
Name=bucket_name
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
print("[+] Setting up S3 bucket resources")
|
||||||
|
create_bucket()
|
||||||
|
print("[+] Setting up Glue IAM resources")
|
||||||
|
create_glue_iam()
|
||||||
|
print("[+] Setting up Glue resources")
|
||||||
|
create_glue()
|
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"live": {
|
||||||
|
"app_function": "app.generate_wsgi_app",
|
||||||
|
"aws_region": "us-west-2",
|
||||||
|
"profile_name": "default",
|
||||||
|
"project_name": "MYPROJECTNAME",
|
||||||
|
"prebuild_script": "prebuild.setup",
|
||||||
|
"runtime": "python3.6",
|
||||||
|
"s3_bucket": "MYZAPPABUCKETNAME",
|
||||||
|
"keep_warm": false,
|
||||||
|
"extra_permissions": [{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:Get*",
|
||||||
|
"s3:Put*"
|
||||||
|
],
|
||||||
|
"Resource": ["arn:aws:s3:::MYLOGBUCKETNAME"]
|
||||||
|
}],
|
||||||
|
"tags": {
|
||||||
|
"Project": "lzahq-ha"
|
||||||
|
},
|
||||||
|
"timeout_seconds": 10
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue