Skip to content

Commit

Permalink
Finishing
Browse files Browse the repository at this point in the history
  • Loading branch information
jkroepke committed Apr 8, 2020
1 parent effb8f6 commit b986c95
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 44 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.iml
helm
venv
contrib
34 changes: 20 additions & 14 deletions handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ async def startup(**_):


@kopf.on.create('postgres.database.k8s.jkroepke.de', 'v1alpha1', 'postgresdatabases')
def create(spec: dict, meta: dict, **_):
def create(body: dict, spec: dict, meta: dict, **_):
db_name = lib.generate_db_name(meta.get('namespace'), meta.get('name'))
db_username = lib.generate_db_username(meta.get('namespace'), meta.get('name'))

kopf.info(body, reason='Scheduled', message='Start creating database: {}'.format(db_name))

operator_db_username = os.getenv('POSTGRES_USER')

try:
Expand All @@ -24,14 +26,14 @@ def create(spec: dict, meta: dict, **_):
message = "Can't connect to database: " + str(e)
raise kopf.TemporaryError(message)

db_password = lib.generate_password(32)
db_password = lib.generate_password(40)

try:
lib.create_db_username(con, db_username, db_password)
lib.grant_role_to_current_user(con, db_username, operator_db_username)

message = "Created user {0}.".format(db_username)
kopf.info(spec, reason="Create user", message=message)
kopf.info(body, reason="Create user", message=message)
except Exception as e:
con.close()

Expand All @@ -51,7 +53,7 @@ def create(spec: dict, meta: dict, **_):
lib.grant_connect_on_db(con, db_name, operator_db_username)

message = "Created database {}.".format(db_name)
kopf.info(spec, reason="Create database", message=message)
kopf.info(body, reason="Create database", message=message)
except Exception as e:
lib.delete_db(con, db_name, db_username)
lib.delete_db_username(con, db_username)
Expand All @@ -62,18 +64,18 @@ def create(spec: dict, meta: dict, **_):

secret_name = spec.get('secretName')

secret = lib.generate_kubernetes_secret(
secret_doc = lib.generate_kubernetes_secret(
secret_name,
os.getenv('POSTGRES_HOST'), os.getenv('POSTGRES_POST', '5432'),
db_name, db_username, db_password
)

# Make it our child: assign the namespace, name, labels, owner references, etc.
kopf.adopt(secret)
kopf.adopt(secret_doc)

try:
response = lib.create_kubernetes_secret(meta.get('namespace'), secret)
kopf.info(response.to_dict(), reason='Secret created', message='Secret {} created'.format(secret_name))
secret = lib.create_kubernetes_secret(secret_doc)
kopf.info(secret_doc, reason='Successful Create', message='Secret created: {}'.format(secret_name))
except Exception as e:
lib.delete_db(con, db_name, db_username)
lib.delete_db_username(con, db_username)
Expand All @@ -84,7 +86,8 @@ def create(spec: dict, meta: dict, **_):

con.close()

return {'children': response.metadata.name}
kopf.info(body, reason='Successful Create', message='Database successfully created')
return {'children': [secret.metadata['uid']]}


@kopf.on.update('postgres.database.k8s.jkroepke.de', 'v1alpha1', 'postgresdatabases')
Expand All @@ -93,10 +96,12 @@ def update(**_):


@kopf.on.delete('postgres.database.k8s.jkroepke.de', 'v1alpha1', 'postgresdatabases')
def delete(spec: dict, meta: dict, **_):
def delete(body: dict, meta: dict, **_):
db_name = lib.generate_db_name(meta.get('namespace'), meta.get('name'))
db_username = lib.generate_db_username(meta.get('namespace'), meta.get('name'))

kopf.info(body, reason='Killing', message='Killing database: {}'.format(db_name))

# connect to DB
try:
con = lib.connect_to_postgres()
Expand All @@ -108,8 +113,8 @@ def delete(spec: dict, meta: dict, **_):
try:
lib.delete_db(con, db_name, db_username)

message = "Delete database {}.".format(db_name)
kopf.info(spec, reason="Database deleted", message=message)
message = "Deleted database: {}.".format(db_name)
kopf.info(body, reason="Database Deleted", message=message)
except Exception as e:
con.close()

Expand All @@ -120,13 +125,14 @@ def delete(spec: dict, meta: dict, **_):
try:
lib.delete_db_username(con, db_username)

message = "Delete user {}.".format(db_username)
kopf.info(spec, reason="Delete user", message=message)
message = "Deleted user: {}.".format(db_username)
kopf.info(body, reason="User deleted", message=message)
except Exception as e:
con.close()

message = "Can't delete postgresql user: {}".format(str(e))
raise kopf.TemporaryError(message, delay=10.0)

con.close()
kopf.info(body, reason='Killed', message='Database successfully killed')
return {'message': message}
42 changes: 23 additions & 19 deletions lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import string
from typing import Optional

import kubernetes.client
import pykube
import psycopg2
from hashlib import sha1

Expand All @@ -17,7 +17,8 @@ def generate_password(length: int) -> str:


def generate_db_name(namespace: str, name: str) -> str:
return sha1("_".join([namespace, name])).hexdigest()
value = "_".join([namespace, name]).encode('utf-8')
return sha1(value).hexdigest()


def generate_db_username(namespace: str, name: str) -> str:
Expand Down Expand Up @@ -114,30 +115,33 @@ def delete_db(con: psycopg2, name: str, owner: str) -> None:

def delete_db_username(con: psycopg2, username: str) -> None:
with con.cursor() as cur:
cur.execute(sql.SQL("DROP USER {};").format(
cur.execute(sql.SQL("DROP USER IF EXISTS {};").format(
sql.Identifier(username)
))


def generate_kubernetes_secret(name: str, db_host: str, db_port: str, db_name: str, db_username: str,
db_password: str) -> dict:
data = {
'DB_HOSTNAME': db_host,
'DB_PORT': db_port,
'DB_DATABASE': db_name,
'DB_USER': db_username,
'DB_PASSWORD': db_password,
return {
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": name,
},
"stringData": {
'DB_HOSTNAME': db_host,
'DB_PORT': db_port,
'DB_DATABASE': db_name,
'DB_USER': db_username,
'DB_PASSWORD': db_password,
}
}

secret = kubernetes.client.V1Secret(
metadata=kubernetes.client.V1ObjectMeta(name=name),
string_data=data,
)

api = kubernetes.client.ApiClient()
return api.sanitize_for_serialization(secret)

def create_kubernetes_secret(doc: dict) -> pykube.Secret:
api = pykube.HTTPClient(pykube.KubeConfig.from_env())
secret = pykube.Secret(api, doc)
secret.create()
api.session.close()

def create_kubernetes_secret(namespace: str, document: dict) -> kubernetes.client.V1Secret:
api = kubernetes.client.CoreV1Api()
return api.create_namespaced_secret(namespace=namespace, body=document)
return secret
11 changes: 0 additions & 11 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,17 @@ aiohttp==3.6.2
aiojobs==0.2.2
async-timeout==3.0.1
attrs==19.3.0
cachetools==4.0.0
certifi==2020.4.5.1
chardet==3.0.4
click==7.1.1
google-auth==1.13.1
idna==2.9
iso8601==0.1.12
kopf==0.26
kubernetes==11.0.0
multidict==4.7.5
oauthlib==3.1.0
psycopg2-binary==2.8.5
pyasn1==0.4.8
pyasn1-modules==0.2.8
pykube-ng==20.4.1
python-dateutil==2.8.1
PyYAML==5.3.1
requests==2.23.0
requests-oauthlib==1.3.0
rsa==4.0
six==1.14.0
typing-extensions==3.7.4.2
urllib3==1.25.8
websocket-client==0.57.0
yarl==1.4.2

0 comments on commit b986c95

Please sign in to comment.