14
Pipfile
14
Pipfile
@@ -1,35 +1,25 @@
|
||||
[[source]]
|
||||
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
|
||||
[packages]
|
||||
|
||||
click = "*"
|
||||
gevent = "*"
|
||||
requests = "*"
|
||||
stups-tokens = ">=1.1.19"
|
||||
redlock-py = "*"
|
||||
json-delta = ">=2.0"
|
||||
kubernetes = "==7.0.0a1"
|
||||
flask = "*"
|
||||
flask-oauthlib = "*"
|
||||
|
||||
pykube-ng = "*"
|
||||
flask-dance = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
"flake8" = "*"
|
||||
pytest = "*"
|
||||
pipenv = "*"
|
||||
|
||||
pytest-cov = "*"
|
||||
coveralls = "*"
|
||||
|
||||
[requires]
|
||||
|
||||
python_version = "3.7"
|
||||
|
||||
[pipenv]
|
||||
allow_prereleases = true
|
||||
|
||||
380
Pipfile.lock
generated
380
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "80d2840fc9f6231022f9be3d0c57bc3286ab0aa4c2b26195a3f7ddfbd44d955f"
|
||||
"sha256": "b08b64b6ea15f966d4c4cdb6f96e61a7b5239bdcc5ea27953c16bd76d9572d34"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -16,19 +16,12 @@
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
"sha256:0a258d82933a1dd18cb540aca4ac5d5690731e24d1239a08577b814998f49785",
|
||||
"sha256:4621965b0d9d4c82a79a29edbad19946f5e7702df4afae7d1ed2df951559a8cc"
|
||||
],
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
|
||||
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
|
||||
"sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5",
|
||||
"sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"
|
||||
],
|
||||
"version": "==2018.11.29"
|
||||
"version": "==2019.3.9"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
@@ -53,49 +46,42 @@
|
||||
"index": "pypi",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"flask-oauthlib": {
|
||||
"flask-dance": {
|
||||
"hashes": [
|
||||
"sha256:cbfe835902569909a19828582c3381148995ad677243016ccad9c951acf69406",
|
||||
"sha256:d3e8ea932df01177018c502e5a07eaeb5c27bcb5352b678f14e57f892272bb56"
|
||||
"sha256:3e91f3488761916caaa055df4f6190364cc83174a4ee8806c71589e998e99f84",
|
||||
"sha256:97d54904796ccec15f775c82d39290ec3983d3e32757ee39e256a98180162c0c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.9.5"
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"gevent": {
|
||||
"hashes": [
|
||||
"sha256:1f277c5cf060b30313c5f9b91588f4c645e11839e14a63c83fcf6f24b1bc9b95",
|
||||
"sha256:298a04a334fb5e3dcd6f89d063866a09155da56041bc94756da59db412cb45b1",
|
||||
"sha256:30e9b2878d5b57c68a40b3a08d496bcdaefc79893948989bb9b9fab087b3f3c0",
|
||||
"sha256:33533bc5c6522883e4437e901059fe5afa3ea74287eeea27a130494ff130e731",
|
||||
"sha256:3f06f4802824c577272960df003a304ce95b3e82eea01dad2637cc8609c80e2c",
|
||||
"sha256:419fd562e4b94b91b58cccb3bd3f17e1a11f6162fca6c591a7822bc8a68f023d",
|
||||
"sha256:4ea938f44b882e02cca9583069d38eb5f257cc15a03e918980c307e7739b1038",
|
||||
"sha256:51143a479965e3e634252a0f4a1ea07e5307cf8dc773ef6bf9dfe6741785fb4c",
|
||||
"sha256:5bf9bd1dd4951552d9207af3168f420575e3049016b9c10fe0c96760ce3555b7",
|
||||
"sha256:6004512833707a1877cc1a5aea90fd182f569e089bc9ab22a81d480dad018f1b",
|
||||
"sha256:640b3b52121ab519e0980cb38b572df0d2bc76941103a697e828c13d76ac8836",
|
||||
"sha256:6951655cc18b8371d823e81c700883debb0f633aae76f425dfeb240f76b95a67",
|
||||
"sha256:71eeb8d9146e8131b65c3364bb760b097c21b7b9fdbec91bf120685a510f997a",
|
||||
"sha256:7c899e5a6f94d6310352716740f05e41eb8c52d995f27fc01e90380913aa8f22",
|
||||
"sha256:8465f84ba31aaf52a080837e9c5ddd592ab0a21dfda3212239ce1e1796f4d503",
|
||||
"sha256:99de2e38dde8669dd30a8a1261bdb39caee6bd00a5f928d01dfdb85ab0502562",
|
||||
"sha256:9fa4284b44bc42bef6e437488d000ae37499ccee0d239013465638504c4565b7",
|
||||
"sha256:a1beea0443d3404c03e069d4c4d9fc13d8ec001771c77f9a23f01911a41f0e49",
|
||||
"sha256:a66a26b78d90d7c4e9bf9efb2b2bd0af49234604ac52eaca03ea79ac411e3f6d",
|
||||
"sha256:a94e197bd9667834f7bb6bd8dff1736fab68619d0f8cd78a9c1cebe3c4944677",
|
||||
"sha256:ac0331d3a3289a3d16627742be9c8969f293740a31efdedcd9087dadd6b2da57",
|
||||
"sha256:d26b57c50bf52fb38dadf3df5bbecd2236f49d7ac98f3cf32d6b8a2d25afc27f",
|
||||
"sha256:fd23b27387d76410eb6a01ea13efc7d8b4b95974ba212c336e8b1d6ab45a9578"
|
||||
"sha256:0774babec518a24d9a7231d4e689931f31b332c4517a771e532002614e270a64",
|
||||
"sha256:0e1e5b73a445fe82d40907322e1e0eec6a6745ca3cea19291c6f9f50117bb7ea",
|
||||
"sha256:0ff2b70e8e338cf13bedf146b8c29d475e2a544b5d1fe14045aee827c073842c",
|
||||
"sha256:107f4232db2172f7e8429ed7779c10f2ed16616d75ffbe77e0e0c3fcdeb51a51",
|
||||
"sha256:14b4d06d19d39a440e72253f77067d27209c67e7611e352f79fe69e0f618f76e",
|
||||
"sha256:1b7d3a285978b27b469c0ff5fb5a72bcd69f4306dbbf22d7997d83209a8ba917",
|
||||
"sha256:1eb7fa3b9bd9174dfe9c3b59b7a09b768ecd496debfc4976a9530a3e15c990d1",
|
||||
"sha256:2711e69788ddb34c059a30186e05c55a6b611cb9e34ac343e69cf3264d42fe1c",
|
||||
"sha256:28a0c5417b464562ab9842dd1fb0cc1524e60494641d973206ec24d6ec5f6909",
|
||||
"sha256:3249011d13d0c63bea72d91cec23a9cf18c25f91d1f115121e5c9113d753fa12",
|
||||
"sha256:44089ed06a962a3a70e96353c981d628b2d4a2f2a75ea5d90f916a62d22af2e8",
|
||||
"sha256:4bfa291e3c931ff3c99a349d8857605dca029de61d74c6bb82bd46373959c942",
|
||||
"sha256:50024a1ee2cf04645535c5ebaeaa0a60c5ef32e262da981f4be0546b26791950",
|
||||
"sha256:53b72385857e04e7faca13c613c07cab411480822ac658d97fd8a4ddbaf715c8",
|
||||
"sha256:74b7528f901f39c39cdbb50cdf08f1a2351725d9aebaef212a29abfbb06895ee",
|
||||
"sha256:7d0809e2991c9784eceeadef01c27ee6a33ca09ebba6154317a257353e3af922",
|
||||
"sha256:896b2b80931d6b13b5d9feba3d4eebc67d5e6ec54f0cf3339d08487d55d93b0e",
|
||||
"sha256:8d9ec51cc06580f8c21b41fd3f2b3465197ba5b23c00eb7d422b7ae0380510b0",
|
||||
"sha256:9f7a1e96fec45f70ad364e46de32ccacab4d80de238bd3c2edd036867ccd48ad",
|
||||
"sha256:ab4dc33ef0e26dc627559786a4fba0c2227f125db85d970abbf85b77506b3f51",
|
||||
"sha256:d1e6d1f156e999edab069d79d890859806b555ce4e4da5b6418616322f0a3df1",
|
||||
"sha256:d752bcf1b98174780e2317ada12013d612f05116456133a6acf3e17d43b71f05",
|
||||
"sha256:e5bcc4270671936349249d26140c267397b7b4b1381f5ec8b13c53c5b53ab6e1"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3.7"
|
||||
},
|
||||
"google-auth": {
|
||||
"hashes": [
|
||||
"sha256:494e747bdc2cdeb0fa6ef85118de2ea1a563f160294cce05048c6ff563fda1bb",
|
||||
"sha256:b08a27888e9d1c17a891b3688aacc9c6f2019d7f6c5a2e73588e6bb9a2c0fa98"
|
||||
],
|
||||
"version": "==1.6.1"
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"greenlet": {
|
||||
"hashes": [
|
||||
@@ -151,91 +137,83 @@
|
||||
"index": "pypi",
|
||||
"version": "==2.0"
|
||||
},
|
||||
"kubernetes": {
|
||||
"lazy": {
|
||||
"hashes": [
|
||||
"sha256:460a1f35042b7829243f533be46932c8f0b72717402b5b84b5292cc25229d708",
|
||||
"sha256:60128a9b752ad179b4fcbf06c6805640f4f25bdb738cd80214330cf5b2e53c73"
|
||||
"sha256:2c6d27a5ab130fb85435320651a47403adcb37ecbcc501b0c6606391f65f5b43",
|
||||
"sha256:9f293fd531546f3eda039da8f919b513b94f219e562764e3ceefc26fa503bf03"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==7.0.0a1"
|
||||
"version": "==1.4"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432",
|
||||
"sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b",
|
||||
"sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9",
|
||||
"sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af",
|
||||
"sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834",
|
||||
"sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd",
|
||||
"sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d",
|
||||
"sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7",
|
||||
"sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b",
|
||||
"sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3",
|
||||
"sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c",
|
||||
"sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2",
|
||||
"sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7",
|
||||
"sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36",
|
||||
"sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1",
|
||||
"sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e",
|
||||
"sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1",
|
||||
"sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c",
|
||||
"sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856",
|
||||
"sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550",
|
||||
"sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492",
|
||||
"sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672",
|
||||
"sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401",
|
||||
"sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6",
|
||||
"sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6",
|
||||
"sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c",
|
||||
"sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd",
|
||||
"sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162",
|
||||
"sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b"
|
||||
"sha256:0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298",
|
||||
"sha256:3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e"
|
||||
],
|
||||
"version": "==2.1.0"
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"pyasn1": {
|
||||
"pykube-ng": {
|
||||
"hashes": [
|
||||
"sha256:b9d3abc5031e61927c82d4d96c1cec1e55676c1a991623cfed28faea73cdd7ca",
|
||||
"sha256:f58f2a3d12fd754aa123e9fa74fb7345333000a035f3921dbdaa08597aa53137"
|
||||
"sha256:37ecabf54addf3842e1ff342ce7796487f078f7e82411ba3f653527a82de7a4b",
|
||||
"sha256:a602b5f607411accae7c099fdd69a41fe756037bde2659ab4bdc46012719790c"
|
||||
],
|
||||
"version": "==0.4.4"
|
||||
},
|
||||
"pyasn1-modules": {
|
||||
"hashes": [
|
||||
"sha256:a0cf3e1842e7c60fde97cb22d275eb6f9524f5c5250489e292529de841417547",
|
||||
"sha256:a38a8811ea784c0136abfdba73963876328f66172db21a05a82f9515909bfb4e"
|
||||
],
|
||||
"version": "==0.2.2"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:063df5763652e21de43de7d9e00ccf239f953a832941e37be541614732cdfc93",
|
||||
"sha256:88f9287c0174266bb0d8cedd395cfba9c58e87e5ad86b2ce58859bc11be3cf02"
|
||||
],
|
||||
"version": "==2.7.5"
|
||||
"index": "pypi",
|
||||
"version": "==0.20"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:254bf6fda2b7c651837acb2c718e213df29d531eebf00edb54743d10bcb694eb",
|
||||
"sha256:3108529b78577327d15eec243f0ff348a0640b0c3478d67ad7f5648f93bac3e2",
|
||||
"sha256:3c17fb92c8ba2f525e4b5f7941d850e7a48c3a59b32d331e2502a3cdc6648e76",
|
||||
"sha256:8d6d96001aa7f0a6a4a95e8143225b5d06e41b1131044913fecb8f85a125714b",
|
||||
"sha256:c8a88edd93ee29ede719080b2be6cb2333dfee1dccba213b422a9c8e97f2967b"
|
||||
"sha256:1adecc22f88d38052fb787d959f003811ca858b799590a5eaa70e63dca50308c",
|
||||
"sha256:436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95",
|
||||
"sha256:460a5a4248763f6f37ea225d19d5c205677d8d525f6a83357ca622ed541830c2",
|
||||
"sha256:5a22a9c84653debfbf198d02fe592c176ea548cccce47553f35f466e15cf2fd4",
|
||||
"sha256:7a5d3f26b89d688db27822343dfa25c599627bc92093e788956372285c6298ad",
|
||||
"sha256:9372b04a02080752d9e6f990179a4ab840227c6e2ce15b95e1278456664cf2ba",
|
||||
"sha256:a5dcbebee834eaddf3fa7366316b880ff4062e4bcc9787b78c7fbb4a26ff2dd1",
|
||||
"sha256:aee5bab92a176e7cd034e57f46e9df9a9862a71f8f37cad167c6fc74c65f5b4e",
|
||||
"sha256:c51f642898c0bacd335fc119da60baae0824f2cde95b0330b56c0553439f0673",
|
||||
"sha256:c68ea4d3ba1705da1e0d85da6684ac657912679a649e8868bd850d2c299cce13",
|
||||
"sha256:e23d0cc5299223dcc37885dae624f382297717e459ea24053709675a976a3e19"
|
||||
],
|
||||
"version": "==4.2b4"
|
||||
"version": "==5.1"
|
||||
},
|
||||
"redis": {
|
||||
"hashes": [
|
||||
"sha256:2100750629beff143b6a200a2ea8e719fcf26420adabb81402895e144c5083cf",
|
||||
"sha256:8e0bdd2de02e829b6225b25646f9fb9daffea99a252610d040409a6738541f0a"
|
||||
"sha256:6946b5dca72e86103edc8033019cc3814c031232d339d5f4533b02ea85685175",
|
||||
"sha256:8ca418d2ddca1b1a850afa1680a7d2fd1f3322739271de4b704e0d4668449273"
|
||||
],
|
||||
"version": "==3.0.1"
|
||||
"version": "==3.2.1"
|
||||
},
|
||||
"redlock-py": {
|
||||
"hashes": [
|
||||
@@ -254,17 +232,10 @@
|
||||
},
|
||||
"requests-oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:8886bfec5ad7afb391ed5443b1f697c6f4ae98d0e5620839d8b4499c032ada3f",
|
||||
"sha256:e21232e2465808c0e892e0e4dbb8c2faafec16ac6dc067dd546e9b466f3deac8"
|
||||
"sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57",
|
||||
"sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140"
|
||||
],
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"rsa": {
|
||||
"hashes": [
|
||||
"sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66",
|
||||
"sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487"
|
||||
],
|
||||
"version": "==4.0"
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
@@ -288,42 +259,41 @@
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
},
|
||||
"websocket-client": {
|
||||
"urlobject": {
|
||||
"hashes": [
|
||||
"sha256:8c8bf2d4f800c3ed952df206b18c28f7070d9e3dcbd6ca6291127574f57ee786",
|
||||
"sha256:e51562c91ddb8148e791f0155fdb01325d99bb52c4cdbb291aee7a3563fd0849"
|
||||
"sha256:47b2e20e6ab9c8366b2f4a3566b6ff4053025dad311c4bb71279bbcfa2430caa"
|
||||
],
|
||||
"version": "==0.54.0"
|
||||
"version": "==2.4.3"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
|
||||
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
|
||||
"sha256:96da23fa8ccecbc3ae832a83df5c722c11547d021637faacb0bec4dd2f4666c8",
|
||||
"sha256:ca5c2dcd367d6c0df87185b9082929d255358f5391923269335782b213d52655"
|
||||
],
|
||||
"version": "==0.14.1"
|
||||
"version": "==0.15.1"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"atomicwrites": {
|
||||
"hashes": [
|
||||
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
|
||||
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
|
||||
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
|
||||
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
|
||||
],
|
||||
"version": "==1.2.1"
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69",
|
||||
"sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"
|
||||
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
|
||||
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
|
||||
],
|
||||
"version": "==18.2.0"
|
||||
"version": "==19.1.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
|
||||
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
|
||||
"sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5",
|
||||
"sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"
|
||||
],
|
||||
"version": "==2018.11.29"
|
||||
"version": "==2019.3.9"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
@@ -334,45 +304,47 @@
|
||||
},
|
||||
"coverage": {
|
||||
"hashes": [
|
||||
"sha256:029c69deaeeeae1b15bc6c59f0ffa28aa8473721c614a23f2c2976dec245cd12",
|
||||
"sha256:02abbbebc6e9d5abe13cd28b5e963dedb6ffb51c146c916d17b18f141acd9947",
|
||||
"sha256:1bbfe5b82a3921d285e999c6d256c1e16b31c554c29da62d326f86c173d30337",
|
||||
"sha256:210c02f923df33a8d0e461c86fdcbbb17228ff4f6d92609fc06370a98d283c2d",
|
||||
"sha256:2d0807ba935f540d20b49d5bf1c0237b90ce81e133402feda906e540003f2f7a",
|
||||
"sha256:35d7a013874a7c927ce997350d314144ffc5465faf787bb4e46e6c4f381ef562",
|
||||
"sha256:3636f9d0dcb01aed4180ef2e57a4e34bb4cac3ecd203c2a23db8526d86ab2fb4",
|
||||
"sha256:42f4be770af2455a75e4640f033a82c62f3fb0d7a074123266e143269d7010ef",
|
||||
"sha256:48440b25ba6cda72d4c638f3a9efa827b5b87b489c96ab5f4ff597d976413156",
|
||||
"sha256:4dac8dfd1acf6a3ac657475dfdc66c621f291b1b7422a939cc33c13ac5356473",
|
||||
"sha256:4e8474771c69c2991d5eab65764289a7dd450bbea050bc0ebb42b678d8222b42",
|
||||
"sha256:551f10ddfeff56a1325e5a34eff304c5892aa981fd810babb98bfee77ee2fb17",
|
||||
"sha256:5b104982f1809c1577912519eb249f17d9d7e66304ad026666cb60a5ef73309c",
|
||||
"sha256:5c62aef73dfc87bfcca32cee149a1a7a602bc74bac72223236b0023543511c88",
|
||||
"sha256:633151f8d1ad9467b9f7e90854a7f46ed8f2919e8bc7d98d737833e8938fc081",
|
||||
"sha256:772207b9e2d5bf3f9d283b88915723e4e92d9a62c83f44ec92b9bd0cd685541b",
|
||||
"sha256:7d5e02f647cd727afc2659ec14d4d1cc0508c47e6cfb07aea33d7aa9ca94d288",
|
||||
"sha256:a9798a4111abb0f94584000ba2a2c74841f2cfe5f9254709756367aabbae0541",
|
||||
"sha256:b38ea741ab9e35bfa7015c93c93bbd6a1623428f97a67083fc8ebd366238b91f",
|
||||
"sha256:b6a5478c904236543c0347db8a05fac6fc0bd574c870e7970faa88e1d9890044",
|
||||
"sha256:c6248bfc1de36a3844685a2e10ba17c18119ba6252547f921062a323fb31bff1",
|
||||
"sha256:c705ab445936457359b1424ef25ccc0098b0491b26064677c39f1d14a539f056",
|
||||
"sha256:d95a363d663ceee647291131dbd213af258df24f41350246842481ec3709bd33",
|
||||
"sha256:e27265eb80cdc5dab55a40ef6f890e04ecc618649ad3da5265f128b141f93f78",
|
||||
"sha256:ebc276c9cb5d917bd2ae959f84ffc279acafa9c9b50b0fa436ebb70bbe2166ea",
|
||||
"sha256:f4d229866d030863d0fe3bf297d6d11e6133ca15bbb41ed2534a8b9a3d6bd061",
|
||||
"sha256:f95675bd88b51474d4fe5165f3266f419ce754ffadfb97f10323931fa9ac95e5",
|
||||
"sha256:f95bc54fb6d61b9f9ff09c4ae8ff6a3f5edc937cda3ca36fc937302a7c152bf1",
|
||||
"sha256:fd0f6be53de40683584e5331c341e65a679dbe5ec489a0697cec7c2ef1a48cda"
|
||||
"sha256:3684fabf6b87a369017756b551cef29e505cb155ddb892a7a29277b978da88b9",
|
||||
"sha256:39e088da9b284f1bd17c750ac672103779f7954ce6125fd4382134ac8d152d74",
|
||||
"sha256:3c205bc11cc4fcc57b761c2da73b9b72a59f8d5ca89979afb0c1c6f9e53c7390",
|
||||
"sha256:465ce53a8c0f3a7950dfb836438442f833cf6663d407f37d8c52fe7b6e56d7e8",
|
||||
"sha256:48020e343fc40f72a442c8a1334284620f81295256a6b6ca6d8aa1350c763bbe",
|
||||
"sha256:5296fc86ab612ec12394565c500b412a43b328b3907c0d14358950d06fd83baf",
|
||||
"sha256:5f61bed2f7d9b6a9ab935150a6b23d7f84b8055524e7be7715b6513f3328138e",
|
||||
"sha256:68a43a9f9f83693ce0414d17e019daee7ab3f7113a70c79a3dd4c2f704e4d741",
|
||||
"sha256:6b8033d47fe22506856fe450470ccb1d8ba1ffb8463494a15cfc96392a288c09",
|
||||
"sha256:7ad7536066b28863e5835e8cfeaa794b7fe352d99a8cded9f43d1161be8e9fbd",
|
||||
"sha256:7bacb89ccf4bedb30b277e96e4cc68cd1369ca6841bde7b005191b54d3dd1034",
|
||||
"sha256:839dc7c36501254e14331bcb98b27002aa415e4af7ea039d9009409b9d2d5420",
|
||||
"sha256:8f9a95b66969cdea53ec992ecea5406c5bd99c9221f539bca1e8406b200ae98c",
|
||||
"sha256:932c03d2d565f75961ba1d3cec41ddde00e162c5b46d03f7423edcb807734eab",
|
||||
"sha256:988529edadc49039d205e0aa6ce049c5ccda4acb2d6c3c5c550c17e8c02c05ba",
|
||||
"sha256:998d7e73548fe395eeb294495a04d38942edb66d1fa61eb70418871bc621227e",
|
||||
"sha256:9de60893fb447d1e797f6bf08fdf0dbcda0c1e34c1b06c92bd3a363c0ea8c609",
|
||||
"sha256:9e80d45d0c7fcee54e22771db7f1b0b126fb4a6c0a2e5afa72f66827207ff2f2",
|
||||
"sha256:a545a3dfe5082dc8e8c3eb7f8a2cf4f2870902ff1860bd99b6198cfd1f9d1f49",
|
||||
"sha256:a5d8f29e5ec661143621a8f4de51adfb300d7a476224156a39a392254f70687b",
|
||||
"sha256:aca06bfba4759bbdb09bf52ebb15ae20268ee1f6747417837926fae990ebc41d",
|
||||
"sha256:bb23b7a6fd666e551a3094ab896a57809e010059540ad20acbeec03a154224ce",
|
||||
"sha256:bfd1d0ae7e292105f29d7deaa9d8f2916ed8553ab9d5f39ec65bcf5deadff3f9",
|
||||
"sha256:c62ca0a38958f541a73cf86acdab020c2091631c137bd359c4f5bddde7b75fd4",
|
||||
"sha256:c709d8bda72cf4cd348ccec2a4881f2c5848fd72903c185f363d361b2737f773",
|
||||
"sha256:c968a6aa7e0b56ecbd28531ddf439c2ec103610d3e2bf3b75b813304f8cb7723",
|
||||
"sha256:df785d8cb80539d0b55fd47183264b7002077859028dfe3070cf6359bf8b2d9c",
|
||||
"sha256:f406628ca51e0ae90ae76ea8398677a921b36f0bd71aab2099dfed08abd0322f",
|
||||
"sha256:f46087bbd95ebae244a0eda01a618aff11ec7a069b15a3ef8f6b520db523dcf1",
|
||||
"sha256:f8019c5279eb32360ca03e9fac40a12667715546eed5c5eb59eb381f2f501260",
|
||||
"sha256:fc5f4d209733750afd2714e9109816a29500718b32dd9a5db01c0cb3a019b96a"
|
||||
],
|
||||
"version": "==5.0a4"
|
||||
"version": "==4.5.3"
|
||||
},
|
||||
"coveralls": {
|
||||
"hashes": [
|
||||
"sha256:ab638e88d38916a6cedbf80a9cd8992d5fa55c77ab755e262e00b36792b7cd6d",
|
||||
"sha256:b2388747e2529fa4c669fb1e3e2756e4e07b6ee56c7d9fce05f35ccccc913aa0"
|
||||
"sha256:baa26648430d5c2225ab12d7e2067f75597a4b967034bba7e3d5ab7501d207a1",
|
||||
"sha256:ff9b7823b15070f26f654837bb02a201d006baaf2083e0514ffd3b34a3ffed81"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.5.1"
|
||||
"version": "==1.7.0"
|
||||
},
|
||||
"docopt": {
|
||||
"hashes": [
|
||||
@@ -380,13 +352,20 @@
|
||||
],
|
||||
"version": "==0.6.2"
|
||||
},
|
||||
"entrypoints": {
|
||||
"hashes": [
|
||||
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
|
||||
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
|
||||
],
|
||||
"version": "==0.3"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670",
|
||||
"sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2"
|
||||
"sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661",
|
||||
"sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.6.0"
|
||||
"version": "==3.7.7"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
@@ -404,11 +383,11 @@
|
||||
},
|
||||
"more-itertools": {
|
||||
"hashes": [
|
||||
"sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092",
|
||||
"sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e",
|
||||
"sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"
|
||||
"sha256:0125e8f60e9e031347105eb1682cef932f5e97d7b9a1a28d9bf00c22a5daef40",
|
||||
"sha256:590044e3942351a1bdb1de960b739ff4ce277960f2425ad4509446dbace8d9d1"
|
||||
],
|
||||
"version": "==4.3.0"
|
||||
"markers": "python_version > '2.7'",
|
||||
"version": "==6.0.0"
|
||||
},
|
||||
"pipenv": {
|
||||
"hashes": [
|
||||
@@ -421,47 +400,47 @@
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095",
|
||||
"sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"
|
||||
"sha256:19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f",
|
||||
"sha256:84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"
|
||||
],
|
||||
"version": "==0.8.0"
|
||||
"version": "==0.9.0"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694",
|
||||
"sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"
|
||||
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
|
||||
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
|
||||
],
|
||||
"version": "==1.7.0"
|
||||
"version": "==1.8.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83",
|
||||
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a"
|
||||
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||
],
|
||||
"version": "==2.4.0"
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49",
|
||||
"sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae"
|
||||
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
|
||||
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
|
||||
],
|
||||
"version": "==2.0.0"
|
||||
"version": "==2.1.1"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:1d131cc532be0023ef8ae265e2a779938d0619bb6c2510f52987ffcba7fa1ee4",
|
||||
"sha256:ca4761407f1acc85ffd1609f464ca20bb71a767803505bd4127d0e45c5a50e23"
|
||||
"sha256:592eaa2c33fae68c7d75aacf042efc9f77b27c08a6224a4f59beab8d9a420523",
|
||||
"sha256:ad3ad5c450284819ecde191a654c09b0ec72257a2c711b9633d677c71c9850c4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.1"
|
||||
"version": "==4.3.1"
|
||||
},
|
||||
"pytest-cov": {
|
||||
"hashes": [
|
||||
"sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7",
|
||||
"sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762"
|
||||
"sha256:0ab664b25c6aa9716cbf203b17ddb301932383046082c081b9848a0edf5add33",
|
||||
"sha256:230ef817450ab0699c6cc3c9c8f7a829c34674456f2ed8df1fe1d39780f7c87f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.6.0"
|
||||
"version": "==2.6.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
@@ -487,17 +466,18 @@
|
||||
},
|
||||
"virtualenv": {
|
||||
"hashes": [
|
||||
"sha256:686176c23a538ecc56d27ed9d5217abd34644823d6391cbeb232f42bf722baad",
|
||||
"sha256:f899fafcd92e1150f40c8215328be38ff24b519cd95357fa6e78e006c7638208"
|
||||
"sha256:6aebaf4dd2568a0094225ebbca987859e369e3e5c22dc7d52e5406d504890417",
|
||||
"sha256:984d7e607b0a5d1329425dd8845bd971b957424b5ba664729fab51ab8c11bc39"
|
||||
],
|
||||
"version": "==16.1.0"
|
||||
"version": "==16.4.3"
|
||||
},
|
||||
"virtualenv-clone": {
|
||||
"hashes": [
|
||||
"sha256:06c5a8bc77f3ed0ad130a690e623e27e07b6599dbdbf83e089cc3a2c6b191da0",
|
||||
"sha256:afce268508aa5596c90dda234abe345deebc401a57d287bcbd76baa140a1aa58"
|
||||
"sha256:217bd3f0880c9f85672c0bcc9ad9e0354ab7dfa89c2f117e63aa878b4279f5bf",
|
||||
"sha256:316c8a05432a7adb5e461709759aca18c51433ffc2c33e2e80c9e51c452d339f",
|
||||
"sha256:f2a07ed255f3abaceef8c8442512d8cdb2ba9f867e212d8a51680c7790a85033"
|
||||
],
|
||||
"version": "==0.4.0"
|
||||
"version": "==0.5.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,16 @@ Relevant configuration settings (environment variables) for OAuth are:
|
||||
``CREDENTIALS_DIR``
|
||||
Folder path to load client credentials from. The folder needs to contain two files: ``authcode-client-id`` and ``authcode-client-secret``.
|
||||
|
||||
GitHub OAuth Example
|
||||
====================
|
||||
|
||||
TODO: how to configure
|
||||
How to configure Kubernetes Operational View to use GitHub OAuth for access control (example with localhost):
|
||||
|
||||
* create a new GitHub OAuth application and configure ``http://localhost:8080/login/oauth/authorized`` as "Authorization Callback URL".
|
||||
* create a file ``authcode-client-id`` with the contents of the generated GitHub "Client ID"
|
||||
* create a file ``authcode-client-secret`` with the contents of the generated GitHub "Client Secret"
|
||||
* point the ``CREDENTIALS_DIR`` environment variable to a folder with these two files
|
||||
* start Kubernetes Operational View with ``OAUTHLIB_INSECURE_TRANSPORT=true`` (needed as localhost is not running with SSL/TLS), ``AUTHORIZE_URL=https://github.com/login/oauth/authorize``, and ``ACCESS_TOKEN_URL=https://github.com/login/oauth/access_token``
|
||||
|
||||
Screen Tokens
|
||||
=============
|
||||
|
||||
@@ -4,12 +4,11 @@ import time
|
||||
from pathlib import Path
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import kubernetes.client
|
||||
import kubernetes.config
|
||||
import requests
|
||||
import tokens
|
||||
from requests.auth import AuthBase
|
||||
|
||||
from pykube import HTTPClient, KubeConfig
|
||||
# default URL points to kubectl proxy
|
||||
DEFAULT_CLUSTERS = 'http://localhost:8001/'
|
||||
CLUSTER_ID_INVALID_CHARS = re.compile('[^a-z0-9:-]')
|
||||
@@ -48,18 +47,22 @@ class OAuthTokenAuth(AuthBase):
|
||||
|
||||
def __call__(self, request):
|
||||
token = tokens.get(self.token_name)
|
||||
request.headers['Authorization'] = 'Bearer {}'.format(token)
|
||||
request.headers['Authorization'] = f'Bearer {token}'
|
||||
return request
|
||||
|
||||
|
||||
class Cluster:
|
||||
def __init__(self, id, api_server_url, ssl_ca_cert=None, auth=None, cert_file=None, key_file=None):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
name: str,
|
||||
api_server_url: str,
|
||||
client: HTTPClient
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.api_server_url = api_server_url
|
||||
self.ssl_ca_cert = ssl_ca_cert
|
||||
self.auth = auth
|
||||
self.cert_file = cert_file
|
||||
self.key_file = key_file
|
||||
self.client = client
|
||||
|
||||
|
||||
class StaticClusterDiscoverer:
|
||||
@@ -69,29 +72,30 @@ class StaticClusterDiscoverer:
|
||||
|
||||
if not api_server_urls:
|
||||
try:
|
||||
kubernetes.config.load_incluster_config()
|
||||
except kubernetes.config.ConfigException:
|
||||
config = KubeConfig.from_service_account()
|
||||
except FileNotFoundError:
|
||||
# we are not running inside a cluster
|
||||
# => assume default kubectl proxy URL
|
||||
cluster = Cluster(generate_cluster_id(DEFAULT_CLUSTERS), DEFAULT_CLUSTERS)
|
||||
else:
|
||||
# "load_incluster_config" set defaults in the config class
|
||||
config = kubernetes.client.configuration.Configuration()
|
||||
config = KubeConfig.from_url(DEFAULT_CLUSTERS)
|
||||
client = HTTPClient(config)
|
||||
cluster = Cluster(
|
||||
generate_cluster_id(config.host),
|
||||
config.host,
|
||||
ssl_ca_cert=config.ssl_ca_cert,
|
||||
auth=StaticAuthorizationHeaderAuth(config.api_key['authorization']))
|
||||
generate_cluster_id(DEFAULT_CLUSTERS), "cluster", DEFAULT_CLUSTERS, client
|
||||
)
|
||||
else:
|
||||
client = HTTPClient(config)
|
||||
cluster = Cluster(
|
||||
generate_cluster_id(config.cluster['server']),
|
||||
"cluster",
|
||||
config.cluster['server'],
|
||||
client
|
||||
)
|
||||
self._clusters.append(cluster)
|
||||
else:
|
||||
for api_server_url in api_server_urls:
|
||||
|
||||
if 'localhost' not in api_server_url:
|
||||
# TODO: hacky way of detecting whether we need a token or not
|
||||
auth = OAuthTokenAuth('read-only')
|
||||
else:
|
||||
auth = None
|
||||
self._clusters.append(Cluster(generate_cluster_id(api_server_url), api_server_url, auth=auth))
|
||||
config = KubeConfig.from_url(api_server_url)
|
||||
client = HTTPClient(config)
|
||||
generated_id = generate_cluster_id(api_server_url)
|
||||
self._clusters.append(Cluster(generated_id, generated_id, api_server_url, client))
|
||||
|
||||
def get_clusters(self):
|
||||
return self._clusters
|
||||
@@ -114,12 +118,24 @@ class ClusterRegistryDiscoverer:
|
||||
clusters = []
|
||||
for row in response.json()['items']:
|
||||
# only consider "ready" clusters
|
||||
if row.get('lifecycle_status', 'ready') == 'ready':
|
||||
clusters.append(Cluster(row['id'], row['api_server_url'], auth=OAuthTokenAuth('read-only')))
|
||||
if row.get("lifecycle_status", "ready") == "ready":
|
||||
config = KubeConfig.from_url(row['api_server_url'])
|
||||
client = HTTPClient(config)
|
||||
client.session.auth = OAuthTokenAuth("read-only")
|
||||
clusters.append(
|
||||
Cluster(
|
||||
row["id"],
|
||||
row["alias"],
|
||||
row["api_server_url"],
|
||||
client
|
||||
)
|
||||
)
|
||||
self._clusters = clusters
|
||||
self._last_cache_refresh = time.time()
|
||||
except:
|
||||
logger.exception('Failed to refresh from cluster registry {}'.format(self._url))
|
||||
logger.exception(
|
||||
f"Failed to refresh from cluster registry {self._url}"
|
||||
)
|
||||
|
||||
def get_clusters(self):
|
||||
now = time.time()
|
||||
@@ -137,25 +153,20 @@ class KubeconfigDiscoverer:
|
||||
def get_clusters(self):
|
||||
# Kubernetes Python client expects "vintage" string path
|
||||
config_file = str(self._path)
|
||||
contexts, current_context = kubernetes.config.list_kube_config_contexts(config_file)
|
||||
for context in contexts:
|
||||
if self._contexts and context['name'] not in self._contexts:
|
||||
config = KubeConfig.from_file(config_file)
|
||||
for context in config.contexts:
|
||||
if self._contexts and context not in self._contexts:
|
||||
# filter out
|
||||
continue
|
||||
config = kubernetes.client.configuration.Configuration()
|
||||
kubernetes.config.load_kube_config(config_file, context=context['name'], client_configuration=config)
|
||||
authorization = config.api_key.get('authorization')
|
||||
if authorization:
|
||||
auth = StaticAuthorizationHeaderAuth(authorization)
|
||||
else:
|
||||
auth = None
|
||||
# create a new KubeConfig with new "current context"
|
||||
context_config = KubeConfig(config.doc, context)
|
||||
client = HTTPClient(context_config)
|
||||
cluster = Cluster(
|
||||
context['name'],
|
||||
config.host,
|
||||
ssl_ca_cert=config.ssl_ca_cert,
|
||||
cert_file=config.cert_file,
|
||||
key_file=config.key_file,
|
||||
auth=auth)
|
||||
context,
|
||||
context,
|
||||
context_config.cluster['server'],
|
||||
client
|
||||
)
|
||||
yield cluster
|
||||
|
||||
|
||||
@@ -163,4 +174,9 @@ class MockDiscoverer:
|
||||
|
||||
def get_clusters(self):
|
||||
for i in range(3):
|
||||
yield Cluster('mock-cluster-{}'.format(i), api_server_url='https://kube-{}.example.org'.format(i))
|
||||
yield Cluster(
|
||||
f"mock-cluster-{i}",
|
||||
f"mock-cluster-{i}",
|
||||
api_server_url=f"https://kube-{i}.example.org",
|
||||
client=None
|
||||
)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import datetime
|
||||
import logging
|
||||
import time
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
|
||||
import pykube
|
||||
|
||||
from pykube import Pod, Node
|
||||
from pykube.objects import APIObject, NamespacedAPIObject
|
||||
|
||||
from .utils import get_short_error_message
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -12,6 +16,22 @@ logger = logging.getLogger(__name__)
|
||||
session = requests.Session()
|
||||
|
||||
|
||||
# https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md
|
||||
class NodeMetrics(APIObject):
|
||||
|
||||
version = 'metrics.k8s.io/v1beta1'
|
||||
endpoint = 'nodes'
|
||||
kind = 'NodeMetrics'
|
||||
|
||||
|
||||
# https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md
|
||||
class PodMetrics(NamespacedAPIObject):
|
||||
|
||||
version = 'metrics.k8s.io/v1beta1'
|
||||
endpoint = 'pods'
|
||||
kind = 'PodMetrics'
|
||||
|
||||
|
||||
def map_node_status(status: dict):
|
||||
return {
|
||||
'addresses': status.get('addresses'),
|
||||
@@ -48,15 +68,6 @@ def map_container(cont: dict, pod: dict):
|
||||
return obj
|
||||
|
||||
|
||||
def request(cluster, path, **kwargs):
|
||||
if 'timeout' not in kwargs:
|
||||
# sane default timeout
|
||||
kwargs['timeout'] = (5, 15)
|
||||
if cluster.cert_file and cluster.key_file:
|
||||
kwargs['cert'] = (cluster.cert_file, cluster.key_file)
|
||||
return session.get(urljoin(cluster.api_server_url, path), auth=cluster.auth, verify=cluster.ssl_ca_cert, **kwargs)
|
||||
|
||||
|
||||
def parse_time(s: str):
|
||||
return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=datetime.timezone.utc).timestamp()
|
||||
|
||||
@@ -64,23 +75,19 @@ def parse_time(s: str):
|
||||
def query_kubernetes_cluster(cluster):
|
||||
cluster_id = cluster.id
|
||||
api_server_url = cluster.api_server_url
|
||||
response = request(cluster, '/api/v1/nodes')
|
||||
response.raise_for_status()
|
||||
nodes = {}
|
||||
pods_by_namespace_name = {}
|
||||
unassigned_pods = {}
|
||||
for node in response.json()['items']:
|
||||
obj = map_node(node)
|
||||
for node in Node.objects(cluster.client):
|
||||
obj = map_node(node.obj)
|
||||
nodes[obj['name']] = obj
|
||||
response = request(cluster, '/api/v1/pods')
|
||||
response.raise_for_status()
|
||||
now = time.time()
|
||||
for pod in response.json()['items']:
|
||||
obj = map_pod(pod)
|
||||
if 'deletionTimestamp' in pod['metadata']:
|
||||
obj['deleted'] = parse_time(pod['metadata']['deletionTimestamp'])
|
||||
for cont in pod['spec']['containers']:
|
||||
obj['containers'].append(map_container(cont, pod))
|
||||
for pod in Pod.objects(cluster.client, namespace=pykube.all):
|
||||
obj = map_pod(pod.obj)
|
||||
if 'deletionTimestamp' in pod.metadata:
|
||||
obj['deleted'] = parse_time(pod.metadata['deletionTimestamp'])
|
||||
for cont in pod.obj['spec']['containers']:
|
||||
obj['containers'].append(map_container(cont, pod.obj))
|
||||
if obj['phase'] in ('Succeeded', 'Failed'):
|
||||
last_termination_time = 0
|
||||
for container in obj['containers']:
|
||||
@@ -93,38 +100,29 @@ def query_kubernetes_cluster(cluster):
|
||||
# the job/pod finished more than an hour ago or if it is evicted by cgroup limits
|
||||
# => filter out
|
||||
continue
|
||||
pods_by_namespace_name[(obj['namespace'], obj['name'])] = obj
|
||||
pod_key = '{}/{}'.format(obj['namespace'], obj['name'])
|
||||
if 'nodeName' in pod['spec'] and pod['spec']['nodeName'] in nodes:
|
||||
nodes[pod['spec']['nodeName']]['pods'][pod_key] = obj
|
||||
pods_by_namespace_name[(pod.namespace, pod.name)] = obj
|
||||
pod_key = f'{pod.namespace}/{pod.name}'
|
||||
node_name = pod.obj['spec'].get('nodeName')
|
||||
if node_name in nodes:
|
||||
nodes[node_name]['pods'][pod_key] = obj
|
||||
else:
|
||||
unassigned_pods[pod_key] = obj
|
||||
|
||||
try:
|
||||
response = request(cluster, '/apis/metrics.k8s.io/v1beta1/nodes')
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if not data.get('items'):
|
||||
logger.info('Heapster node metrics not available (yet)')
|
||||
else:
|
||||
for metrics in data['items']:
|
||||
nodes[metrics['metadata']['name']]['usage'] = metrics['usage']
|
||||
for node_metrics in NodeMetrics.objects(cluster.client):
|
||||
key = node_metrics.name
|
||||
nodes[key]['usage'] = node_metrics.obj.get('usage', {})
|
||||
except Exception as e:
|
||||
logger.warning('Failed to query node metrics {}: {}'.format(cluster.id, get_short_error_message(e)))
|
||||
try:
|
||||
response = request(cluster, '/apis/metrics.k8s.io/v1beta1/pods')
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if not data.get('items'):
|
||||
logger.info('Heapster pod metrics not available (yet)')
|
||||
else:
|
||||
for metrics in data['items']:
|
||||
pod = pods_by_namespace_name.get((metrics['metadata']['namespace'], metrics['metadata']['name']))
|
||||
if pod:
|
||||
for container in pod['containers']:
|
||||
for container_metrics in metrics['containers']:
|
||||
if container['name'] == container_metrics['name']:
|
||||
container['resources']['usage'] = container_metrics['usage']
|
||||
for pod_metrics in PodMetrics.objects(cluster.client, namespace=pykube.all):
|
||||
key = (pod_metrics.namespace, pod_metrics.name)
|
||||
pod = pods_by_namespace_name.get(key)
|
||||
if pod:
|
||||
for container in pod['containers']:
|
||||
for container_metrics in pod_metrics.obj.get('containers', []):
|
||||
if container['name'] == container_metrics['name']:
|
||||
container['resources']['usage'] = container_metrics['usage']
|
||||
except Exception as e:
|
||||
logger.warning('Failed to query pod metrics for cluster {}: {}'.format(cluster.id, get_short_error_message(e)))
|
||||
return {
|
||||
|
||||
@@ -17,9 +17,8 @@ import time
|
||||
import kube_ops_view
|
||||
from pathlib import Path
|
||||
|
||||
from flask import Flask, redirect
|
||||
from flask_oauthlib.client import OAuth
|
||||
from .oauth import OAuthRemoteAppWithRefresh
|
||||
from flask import Flask, redirect, url_for
|
||||
from .oauth import OAuth2ConsumerBlueprintWithClientRefresh
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from .mock import query_mock_cluster
|
||||
@@ -33,30 +32,26 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
SERVER_STATUS = {'shutdown': False}
|
||||
AUTHORIZE_URL = os.getenv('AUTHORIZE_URL')
|
||||
ACCESS_TOKEN_URL = os.getenv('ACCESS_TOKEN_URL')
|
||||
APP_URL = os.getenv('APP_URL')
|
||||
SCOPE = os.getenv('SCOPE')
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
oauth = OAuth(app)
|
||||
|
||||
auth = OAuthRemoteAppWithRefresh(
|
||||
oauth,
|
||||
'auth',
|
||||
request_token_url=None,
|
||||
access_token_method='POST',
|
||||
access_token_url=os.getenv('ACCESS_TOKEN_URL'),
|
||||
authorize_url=AUTHORIZE_URL,
|
||||
request_token_params={'scope': SCOPE} if SCOPE else None
|
||||
oauth_blueprint = OAuth2ConsumerBlueprintWithClientRefresh(
|
||||
"oauth", __name__,
|
||||
authorization_url=AUTHORIZE_URL,
|
||||
token_url=ACCESS_TOKEN_URL,
|
||||
token_url_params={'scope': SCOPE} if SCOPE else None,
|
||||
)
|
||||
oauth.remote_apps['auth'] = auth
|
||||
app.register_blueprint(oauth_blueprint, url_prefix="/login")
|
||||
|
||||
|
||||
def authorize(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
if AUTHORIZE_URL and 'auth_token' not in flask.session:
|
||||
return redirect(urljoin(APP_URL, '/login'))
|
||||
if AUTHORIZE_URL and 'auth_token' not in flask.session and not oauth_blueprint.session.authorized:
|
||||
return redirect(url_for('oauth.login'))
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
@@ -139,32 +134,12 @@ def redeem_screen_token(token: str):
|
||||
return redirect(urljoin(APP_URL, '/'))
|
||||
|
||||
|
||||
@app.route('/login')
|
||||
def login():
|
||||
redirect_uri = urljoin(APP_URL, '/login/authorized')
|
||||
return auth.authorize(callback=redirect_uri)
|
||||
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
flask.session.pop('auth_token', None)
|
||||
return redirect(urljoin(APP_URL, '/'))
|
||||
|
||||
|
||||
@app.route('/login/authorized')
|
||||
def authorized():
|
||||
resp = auth.authorized_response()
|
||||
if resp is None:
|
||||
return 'Access denied: reason=%s error=%s' % (
|
||||
flask.request.args['error'],
|
||||
flask.request.args['error_description']
|
||||
)
|
||||
if not isinstance(resp, dict):
|
||||
return 'Invalid auth response'
|
||||
flask.session['auth_token'] = (resp['access_token'], '')
|
||||
return redirect(urljoin(APP_URL, '/'))
|
||||
|
||||
|
||||
def shutdown():
|
||||
# just wait some time to give Kubernetes time to update endpoints
|
||||
# this requires changing the readinessProbe's
|
||||
|
||||
@@ -1,32 +1,21 @@
|
||||
import os
|
||||
|
||||
from flask_oauthlib.client import OAuthRemoteApp
|
||||
from flask_dance.consumer import OAuth2ConsumerBlueprint
|
||||
|
||||
|
||||
CREDENTIALS_DIR = os.getenv('CREDENTIALS_DIR', '')
|
||||
|
||||
|
||||
class OAuthRemoteAppWithRefresh(OAuthRemoteApp):
|
||||
'''Same as flask_oauthlib.client.OAuthRemoteApp, but always loads client credentials from file.'''
|
||||
|
||||
def __init__(self, oauth, name, **kwargs):
|
||||
# constructor expects some values, so make it happy..
|
||||
kwargs['consumer_key'] = 'not-needed-here'
|
||||
kwargs['consumer_secret'] = 'not-needed-here'
|
||||
OAuthRemoteApp.__init__(self, oauth, name, **kwargs)
|
||||
class OAuth2ConsumerBlueprintWithClientRefresh(OAuth2ConsumerBlueprint):
|
||||
'''Same as flask_dance.consumer.OAuth2ConsumerBlueprint, but loads client credentials from file'''
|
||||
|
||||
def refresh_credentials(self):
|
||||
with open(os.path.join(CREDENTIALS_DIR, 'authcode-client-id')) as fd:
|
||||
self._consumer_key = fd.read().strip()
|
||||
# note that we need to set two attributes because of how OAuth2ConsumerBlueprint works :-/
|
||||
self._client_id = self.client_id = fd.read().strip()
|
||||
with open(os.path.join(CREDENTIALS_DIR, 'authcode-client-secret')) as fd:
|
||||
self._consumer_secret = fd.read().strip()
|
||||
self.client_secret = fd.read().strip()
|
||||
|
||||
@property
|
||||
def consumer_key(self):
|
||||
def login(self):
|
||||
self.refresh_credentials()
|
||||
return self._consumer_key
|
||||
|
||||
@property
|
||||
def consumer_secrect(self):
|
||||
self.refresh_credentials()
|
||||
return self._consumer_secret
|
||||
return super().login()
|
||||
|
||||
Reference in New Issue
Block a user