You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.2 KiB
93 lines
3.2 KiB
#!/usr/bin/env python3
|
|
import asyncio
|
|
import os
|
|
import prometheus_async
|
|
import random
|
|
import string
|
|
from passlib.context import CryptContext
|
|
from prometheus_client import Counter, Gauge
|
|
from kubernetes_asyncio.client.api_client import ApiClient
|
|
from kubernetes_asyncio.client.exceptions import ApiException
|
|
from kubernetes_asyncio import client, config, watch
|
|
from time import time
|
|
|
|
counter_opened_watch_streams = Counter(
|
|
"meta_operator_opened_watch_streams",
|
|
"Count of watch streams opened")
|
|
gauge_watch_stream_begin_timestamp = Gauge(
|
|
"meta_operator_watch_stream_begin_timestamp",
|
|
"Timestamp of last watch stream open")
|
|
|
|
|
|
bcrypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
|
|
|
|
async def apply_changes(item, v1, apps_api, api_instance):
|
|
namespace = item["metadata"]["namespace"]
|
|
name = item["metadata"]["name"]
|
|
password = "".join([random.choice(string.ascii_letters + string.digits) for j in range(item["spec"]["size"])])
|
|
data = {}
|
|
for o in item["spec"]["mapping"]:
|
|
data[o["key"]] = o["value"] % {
|
|
"name": name,
|
|
"namespace": namespace,
|
|
"password": password,
|
|
"bcrypt": bcrypt_context.hash(password),
|
|
}
|
|
try:
|
|
await v1.create_namespaced_secret(namespace, body={
|
|
"metadata": {
|
|
"name": name,
|
|
"annotations": {},
|
|
"ownerReferences": [{
|
|
"apiVersion": "codemowers.io/v1alpha1",
|
|
"kind": "GeneratedSecret",
|
|
"uid": item["metadata"]["uid"],
|
|
"name": name
|
|
}]
|
|
},
|
|
"stringData": data
|
|
})
|
|
print("Generated secret %s/%s" % (namespace, name))
|
|
except ApiException as e:
|
|
if e.status == 409:
|
|
print("Secret %s/%s already generated" % (namespace, name))
|
|
else:
|
|
raise
|
|
|
|
|
|
async def main():
|
|
if os.getenv("KUBECONFIG"):
|
|
await config.load_kube_config()
|
|
else:
|
|
config.load_incluster_config()
|
|
async with ApiClient() as api:
|
|
v1 = client.CoreV1Api(api)
|
|
apps_api = client.AppsV1Api()
|
|
api_instance = client.CustomObjectsApi(api)
|
|
while True:
|
|
try:
|
|
gauge_watch_stream_begin_timestamp.set(time())
|
|
print("Subscribing to updates in every namespace")
|
|
w = watch.Watch()
|
|
counter_opened_watch_streams.inc()
|
|
flt = "codemowers.io", "v1alpha1", "", "generatedsecrets"
|
|
method = api_instance.list_namespaced_custom_object
|
|
async for event in w.stream(method, *flt):
|
|
if event["type"] == "ADDED":
|
|
await apply_changes(event["object"], v1, apps_api, api_instance)
|
|
except ApiException as e:
|
|
print("Caught exception: %s" % e)
|
|
if e.status == 410:
|
|
pass
|
|
else:
|
|
raise
|
|
except asyncio.exceptions.TimeoutError:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
loop = asyncio.new_event_loop()
|
|
loop.create_task(prometheus_async.aio.web.start_http_server(port=5000))
|
|
loop.run_until_complete(main())
|
|
loop.close()
|
|
|