Skip to content
Snippets Groups Projects
Commit 8a58aaa4 authored by Arie Peterson's avatar Arie Peterson
Browse files

Merge branch 'main' into 1146-switch-onlyoffice-database-to-mariadb

parents 0e3c1bf8 4fadba33
Branches
Tags
No related merge requests found
......@@ -13,7 +13,7 @@ flux:
k3s:
# https://github.com/k3s-io/k3s/releases
version: 'v1.23.1+k3s2'
version: 'v1.23.3+k3s1'
# args to start the k3s server with
# https://rancher.com/docs/k3s/latest/en/installation/install-options/server-config/
# kubelet arguments can be passed with `--kubelet-arg`
......
......@@ -163,10 +163,10 @@ data:
enabled: false
resources:
limits:
cpu: 750m
cpu: 500m
memory: 512Mi
requests:
cpu: 300m
cpu: 200m
memory: 256Mi
livenessProbe:
initialDelaySeconds: 180
......
......@@ -10,7 +10,7 @@ spec:
spec:
# renovate: registryUrl=https://open.greenhost.net/api/v4/projects/27/packages/helm/stable
chart: wordpress
version: 0.5.3
version: 0.5.4
sourceRef:
kind: HelmRepository
name: wordpress-helm
......
......@@ -84,12 +84,14 @@ data:
commonLabels:
stackspin.net/backupSet: "wordpress"
# It's advisable to set resource limits to prevent your K8s cluster from
# crashing
resources:
limits:
cpu: 1000m
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
cpu: 100m
memory: 256Mi
ingress:
......
"""
Generates Kubernetes secrets based on a provided app name.
"""Generates Kubernetes secrets based on a provided app name.
If the `templates` directory contains a secret called `stackspin-{app}-variables`, it
will check if that secret already exists in the cluster, and if not: generate
......@@ -19,9 +18,9 @@ import string
import sys
import jinja2
import jinja2_base64_filters # pylint: disable=unused-import
import yaml
from kubernetes import client, config
from kubernetes.client import api_client
from kubernetes.client.exceptions import ApiException
from kubernetes.utils import create_from_yaml
......@@ -34,10 +33,12 @@ APPS_WITHOUT_OAUTH = [
"alertmanager",
]
def main():
"""Run everything"""
"""Run everything."""
# Add jinja filters we want to use
env = jinja2.Environment(extensions=["jinja2_base64_filters.Base64Filters"])
env = jinja2.Environment(
extensions=["jinja2_base64_filters.Base64Filters"])
env.filters["generate_password"] = generate_password
if len(sys.argv) < 2:
......@@ -46,99 +47,113 @@ def main():
app_name = sys.argv[1]
# Create app variables secret
create_variables_secret(app_name, f"stackspin-{app_name}-variables.yaml.jinja", env)
create_variables_secret(
app_name, f"stackspin-{app_name}-variables.yaml.jinja", env)
# Create a secret that contains the oauth variables for Hydra Maester
if app_name not in APPS_WITHOUT_OAUTH:
create_variables_secret(app_name, "stackspin-oauth-variables.yaml.jinja", env)
create_variables_secret(
app_name, "stackspin-oauth-variables.yaml.jinja", env)
create_basic_auth_secret(app_name, env)
def get_templates_dir():
"""Returns directory that contains the Jinja templates used to create app
secrets"""
return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
"""Returns directory that contains the Jinja templates used to create app secrets."""
return os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates")
def create_variables_secret(app_name, variables_filename, env):
"""Checks if a variables secret for app_name already exists, generates it if necessary"""
variables_filepath = \
os.path.join(get_templates_dir(), variables_filename)
"""Checks if a variables secret for app_name already exists, generates it if necessary."""
variables_filepath = os.path.join(get_templates_dir(), variables_filename)
if os.path.exists(variables_filepath):
# Check if k8s secret already exists, if not, generate it
with open(variables_filepath) as template_file:
with open(variables_filepath, encoding="UTF-8") as template_file:
lines = template_file.read()
secret_name, secret_namespace = get_secret_metadata(lines)
new_secret_dict = yaml.safe_load(
env.from_string(
lines,
globals={"app": app_name}
).render())
current_secret_data = get_kubernetes_secret_data(secret_name,
secret_namespace)
env.from_string(lines, globals={"app": app_name}).render()
)
current_secret_data = get_kubernetes_secret_data(
secret_name, secret_namespace
)
if current_secret_data is None:
# Create new secret
update_secret = False
elif current_secret_data.keys() != new_secret_dict['data'].keys():
elif current_secret_data.keys() != new_secret_dict["data"].keys():
# Update current secret with new keys
update_secret = True
print(f"Secret {secret_name} in namespace {secret_namespace}"
" already exists. Merging...")
print(
f"Secret {secret_name} in namespace {secret_namespace}"
" already exists. Merging..."
)
# Merge dicts. Values from current_secret_data take precedence
new_secret_dict['data'] |= current_secret_data
new_secret_dict["data"] |= current_secret_data
else:
# Do Nothing
print(f"Secret {secret_name} in namespace {secret_namespace}"
" is already in a good state, doing nothing.")
print(
f"Secret {secret_name} in namespace {secret_namespace}"
" is already in a good state, doing nothing."
)
return
print(f"Storing secret {secret_name} in namespace"
f" {secret_namespace} in cluster.")
store_kubernetes_secret(new_secret_dict, secret_namespace,
update=update_secret)
print(
f"Storing secret {secret_name} in namespace"
f" {secret_namespace} in cluster."
)
store_kubernetes_secret(
new_secret_dict, secret_namespace, update=update_secret
)
else:
print(f'Template {variables_filename} does not exist, no action needed')
print(
f"Template {variables_filename} does not exist, no action needed")
def create_basic_auth_secret(app_name, env):
"""Checks if a basic auth secret for app_name already exists, generates it if necessary"""
basic_auth_filename = \
os.path.join(get_templates_dir(), f"stackspin-{app_name}-basic-auth.yaml.jinja")
"""Checks if a basic auth secret for app_name already exists, generates it if necessary."""
basic_auth_filename = os.path.join(
get_templates_dir(), f"stackspin-{app_name}-basic-auth.yaml.jinja"
)
if os.path.exists(basic_auth_filename):
with open(basic_auth_filename) as template_file:
with open(basic_auth_filename, encoding="UTF-8") as template_file:
lines = template_file.read()
secret_name, secret_namespace = get_secret_metadata(lines)
if get_kubernetes_secret_data(secret_name, secret_namespace) is None:
basic_auth_username = 'admin'
basic_auth_username = "admin"
basic_auth_password = generate_password(32)
basic_auth_htpasswd = gen_htpasswd(
basic_auth_username,
basic_auth_password)
print(f"Adding secret {secret_name} in namespace"
f" {secret_namespace} to cluster.")
basic_auth_username, basic_auth_password
)
print(
f"Adding secret {secret_name} in namespace"
f" {secret_namespace} to cluster."
)
template = env.from_string(
lines,
globals={
'pass': basic_auth_password,
'htpasswd': basic_auth_htpasswd
})
lines,
globals={
"pass": basic_auth_password,
"htpasswd": basic_auth_htpasswd,
},
)
secret_dict = yaml.safe_load(template.render())
store_kubernetes_secret(secret_dict, secret_namespace)
else:
print(f"Secret {secret_name} in namespace {secret_namespace}"
" already exists. Not generating new secrets.")
print(
f"Secret {secret_name} in namespace {secret_namespace}"
" already exists. Not generating new secrets."
)
else:
print(f'File {basic_auth_filename} does not exist, no action needed')
print(f"File {basic_auth_filename} does not exist, no action needed")
def get_secret_metadata(yaml_string):
"""Returns secret name and namespace from metadata field in a yaml string"""
"""Returns secret name and namespace from metadata field in a yaml string."""
secret_dict = yaml.safe_load(yaml_string)
secret_name = secret_dict['metadata']['name']
secret_name = secret_dict["metadata"]["name"]
# default namespace is flux-system, but other namespace can be
# provided in secret metadata
if 'namespace' in secret_dict['metadata']:
secret_namespace = secret_dict['metadata']['namespace']
if "namespace" in secret_dict["metadata"]:
secret_namespace = secret_dict["metadata"]["namespace"]
else:
secret_namespace = 'flux-system'
secret_namespace = "flux-system"
return secret_name, secret_namespace
......@@ -153,42 +168,44 @@ def get_kubernetes_secret_data(secret_name, namespace):
return None
return secret
def store_kubernetes_secret(secret_dict, namespace, update=False):
"""Stores either a new secret in the cluster, or updates an existing one"""
api_client = client.api_client.ApiClient()
"""Stores either a new secret in the cluster, or updates an existing one."""
api_client_instance = api_client.ApiClient()
if update:
verb = "updated"
api_response = patch_kubernetes_secret(secret_dict, namespace)
else:
verb = "created"
api_response = create_from_yaml(
api_client,
yaml_objects=[secret_dict],
namespace=namespace)
api_client_instance, yaml_objects=[
secret_dict], namespace=namespace
)
print(f"Secret {verb} with api response: {api_response}")
def patch_kubernetes_secret(secret_dict, namespace):
"""Patches secret in the cluster with new data"""
api_client = client.api_client.ApiClient()
api_instance = client.CoreV1Api(api_client)
name = secret_dict['metadata']['name']
"""Patches secret in the cluster with new data."""
api_client_instance = api_client.ApiClient()
api_instance = client.CoreV1Api(apiclient)
name = secret_dict["metadata"]["name"]
body = {}
body['data'] = secret_dict['data']
body["data"] = secret_dict["data"]
return api_instance.patch_namespaced_secret(name, namespace, body)
def generate_password(length):
"""Generates a password of "length" characters"""
"""Generates a password of "length" characters."""
length = int(length)
password = ''.join((secrets.choice(string.ascii_letters) for i in range(length)))
password = "".join((secrets.choice(string.ascii_letters)
for i in range(length)))
return password
def gen_htpasswd(user, password):
"""generate htpasswd entry for user with password"""
return "{}:{}".format(user, crypt.crypt(
password, crypt.mksalt(crypt.METHOD_SHA512)
),
)
"""Generate htpasswd entry for user with password."""
return f"{user}:{crypt.crypt(password, crypt.mksalt(crypt.METHOD_SHA512))}"
if __name__ == "__main__":
config.load_kube_config()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment