Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions docs/k8s_apps/experimental/ghost.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,22 @@ apps:
init:
enabled: false
values:
# admin info
admin_user: ""
admin_email: ""
# smtp info
smtp_host: ""
smtp_user: ""
smtp_port: ""
smtp_protocol: "SMTP"
# smtp from email (verified sender)
smtp_from_address: example.com
smtp_password:
value_from:
env: GHOST_SMTP_PASSWORD
backups:
# cronjob syntax schedule to run ghost pvc backups
pvc_schedule: 10 0 * * *
# cronjob syntax (with SECONDS field) for ghost postgres backups
# must happen at least 10 minutes before pvc backups, to avoid corruption
# due to missing files. This is because the backup shows as completed before
# it actually is
postgres_schedule: 0 0 0 * * *
s3:
# these are for pushing remote backups of your local s3 storage, for speed and cost optimization
endpoint: ""
Expand Down Expand Up @@ -60,18 +65,10 @@ apps:
# affinity_value: ""
# hostname that users go to in the browser
hostname: ""
# admin username
admin_user: "ghost"
# admin email
admin_email: ""
# admin hostname that users go to in the browser
admin_hostname: ""
# title of your title
blog_title: ""
# smtp server
smtp_host: ""
# smtp port
smtp_port: ""
# smtp username
smtp_user: ""
# ghost mysql pvc capacity
mysql_pvc_capacity: 5Gi
# ghost pvc capacity
Expand All @@ -98,6 +95,7 @@ apps:
source_repos:
- registry-1.docker.io
- seaweedfs.github.io/seaweedfs/helm
- https://small-hack.github.io/ghost-helm-chart
destination:
# automatically includes the app's namespace and argocd's namespace
namespaces: []
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "smol_k8s_lab"
version = "7.0.0b2"
version = "7.0.0b3"
description = "CLI and TUI to quickly install slimmer Kubernetes distros and then manage apps declaratively using Argo CD"
authors = ["Jesse Hitch <[email protected]>",
"Max Roby <[email protected]>"]
Expand Down
2 changes: 2 additions & 0 deletions smol_k8s_lab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ def main(config: str = "",
apps.get('ingress_nginx', {}),
apps.get('cert_manager', {}),
apps.get('cnpg_operator', {}),
apps.get('pxc_operator', {}),
apps['argo_cd'],
SECRETS,
bw)
Expand Down Expand Up @@ -270,6 +271,7 @@ def main(config: str = "",
apps.pop('minio_operator', {'enabled': False}),
apps.pop('seaweedfs', {'enabled': False}),
apps.pop('cnpg_operator', {'enabled': False}),
apps.pop('pxc_operator', {'enabled': False}),
apps.pop('postgres_operator', {'enabled': False}),
apps.pop('openbao', {'enabled': False}),
bw)
Expand Down
30 changes: 15 additions & 15 deletions smol_k8s_lab/config/default_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -619,17 +619,22 @@ apps:
init:
enabled: true
values:
# admin info
admin_user: ""
admin_email: ""
# smtp info
smtp_host: ""
smtp_user: ""
smtp_port: ""
smtp_protocol: "SMTP"
# smtp from email (verified sender)
smtp_from_address: example.com
smtp_password:
value_from:
env: GHOST_SMTP_PASSWORD
backups:
# cronjob syntax schedule to run ghost pvc backups
pvc_schedule: 10 0 * * *
# cronjob syntax (with SECONDS field) for ghost postgres backups
# must happen at least 10 minutes before pvc backups, to avoid corruption
# due to missing files. This is because the backup shows as completed before
# it actually is
postgres_schedule: 0 0 0 * * *
s3:
# these are for pushing remote backups of your local s3 storage, for speed and cost optimization
endpoint: ""
Expand Down Expand Up @@ -657,18 +662,10 @@ apps:
# affinity_value: ""
# hostname that users go to in the browser
hostname: ""
# admin username
admin_user: "ghost"
# admin email
admin_email: ""
# admin hostname that users go to in the browser
admin_hostname: ""
# title of your title
blog_title: ""
# smtp server
smtp_host: ""
# smtp port
smtp_port: ""
# smtp username
smtp_user: ""
# ghost mysql pvc capacity
mysql_pvc_capacity: 5Gi
# ghost pvc capacity
Expand Down Expand Up @@ -703,6 +700,7 @@ apps:
source_repos:
- registry-1.docker.io
- seaweedfs.github.io/seaweedfs/helm
- https://small-hack.github.io/ghost-helm-chart
destination:
# automatically includes the app's namespace and argocd's namespace
namespaces: []
Expand Down Expand Up @@ -2469,6 +2467,8 @@ apps:
s3_endpoint: ""
# capacity for the PVC backing your local s3 instance
s3_pvc_capacity: 100Gi
# StorageClass for the PVC backing your local s3 instance
s3_storage_class: local-path

# git repo to install the Argo CD app from
repo: https://github.com/small-hack/argocd-apps
Expand Down
3 changes: 3 additions & 0 deletions smol_k8s_lab/k8s_apps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ def setup_base_apps(k8s_obj: K8s,
ingress_dict: dict = {},
cert_manager_dict: dict = {},
cnpg_operator_dict: dict = {},
pxc_operator_dict: dict = {},
argocd_dict: dict = {},
plugin_secrets: dict = {},
bw: BwCLI = None) -> ArgoCD:
Expand All @@ -169,6 +170,7 @@ def setup_base_apps(k8s_obj: K8s,
cilium_enabled = cilium_dict.get('enabled', False)
ingress_nginx_enabled = ingress_dict.get('enabled', False)
cnpg_operator_enabled = cnpg_operator_dict.get('enabled', False)
pxc_operator_enabled = pxc_operator_dict.get('enabled', False)
argocd_enabled = argocd_dict.get('enabled', False)
cert_manager_enabled = cert_manager_dict.get('enabled', False)
argo_secrets_plugin_enabled = argocd_dict['argo']['directory_recursion']
Expand All @@ -177,6 +179,7 @@ def setup_base_apps(k8s_obj: K8s,
metallb_enabled,
cilium_enabled,
cnpg_operator_enabled,
pxc_operator_enabled,
argocd_enabled,
argo_secrets_plugin_enabled)

Expand Down
2 changes: 1 addition & 1 deletion smol_k8s_lab/k8s_apps/monitoring/grafana_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def configure_grafana_stack(argocd: ArgoCD,

if init_enabled:
# configure backup s3 credentials
backup_vals = process_backup_vals(cfg.get('backups', ''), 'grafana-stack', argocd)
backup_vals = process_backup_vals(cfg.get('backups', ''), 'grafana_stack', argocd)

# initial secrets to deploy this app from scratch
if init_enabled and not app_installed:
Expand Down
5 changes: 5 additions & 0 deletions smol_k8s_lab/k8s_apps/operators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def setup_operators(argocd: ArgoCD,
cnpg_config: dict = {},
pg_config: dict = {},
openbao_config: dict = {},
pxc_config: dict = {},
bitwarden: BwCLI = None) -> None:
"""
deploy all k8s operators that can block other apps:
Expand Down Expand Up @@ -57,6 +58,10 @@ def setup_operators(argocd: ArgoCD,
if cnpg_config and cnpg_config.get('enabled', False):
argocd.install_app('cnpg-operator', cnpg_config['argo'])

# pxc operator is a mysql operator for creating mysql clusters
if pxc_config and pxc_config.get('enabled', False):
argocd.install_app('pxc-operator', pxc_config['argo'])

# zalando postgres operator is a postgres operator for creating postgresql clusters
if pg_config and pg_config.get('enabled', False):
configure_postgres_operator(argocd, pg_config, bitwarden)
2 changes: 1 addition & 1 deletion smol_k8s_lab/k8s_apps/social/forgejo.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async def configure_forgejo(argocd: ArgoCD,
# configure OIDC
if zitadel and not restore_enabled:
log.debug("Creating a forgejo OIDC application in Zitadel...")
redirect_uris = f"https://{forgejo_hostname}/auth/callback"
redirect_uris = f"https://{forgejo_hostname}/user/oauth2/Zitadel/callback"
logout_uris = [f"https://{forgejo_hostname}"]
oidc_creds = zitadel.create_application(
"forgejo",
Expand Down
92 changes: 27 additions & 65 deletions smol_k8s_lab/k8s_apps/social/ghost.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
k8up_restore_pvc)
from smol_k8s_lab.utils.passwords import create_password
from smol_k8s_lab.utils.rich_cli.console_logging import sub_header, header
from smol_k8s_lab.utils.run.subproc import subproc
from smol_k8s_lab.utils.value_from import extract_secret, process_backup_vals

# external libraries
Expand Down Expand Up @@ -82,6 +81,8 @@ async def configure_ghost(argocd: ArgoCD,
mail_user = init_values.get('smtp_user', '')
mail_host = init_values.get('smtp_host', '')
mail_port = init_values.get('smtp_port', '')
mail_from_address = init_values.get('smtp_from_address', '')
mail_protocol = init_values.get('smtp_protocol', '')
mail_pass = extract_secret(init_values.get('smtp_password'))

# configure s3 credentials
Expand Down Expand Up @@ -127,7 +128,10 @@ async def configure_ghost(argocd: ArgoCD,
backup_vals['s3_password'],
backup_vals['restic_repo_pass'],
ghost_admin_username,
ghost_admin_email,
mail_host,
mail_protocol,
mail_from_address,
mail_port,
mail_user,
mail_pass,
Expand Down Expand Up @@ -171,66 +175,13 @@ async def configure_ghost(argocd: ArgoCD,
# wait for all the ghost apps to come up, give it extra time
argocd.sync_app(app='ghost-web-app', sleep_time=4)
argocd.wait_for_app('ghost-web-app')

# create admin credentials
password = create_user(ghost_admin_username,
ghost_admin_email,
cfg['argo']['namespace'])
if bitwarden:
sub_header("Creating secrets in Bitwarden")
bitwarden.create_login(
name='ghost-admin-credentials',
item_url=ghost_hostname,
user=ghost_admin_username,
password=password,
fields=[create_custom_field("email", ghost_admin_email)]
)
else:
log.info("ghost already installed 🎉")

if bitwarden and init_enabled:
refresh_bweso(argocd, ghost_hostname, bitwarden)


def create_user(user: str, email: str, pod_namespace: str) -> str:
"""
given a username, email, and namespace of the ghost pod, we'll create a
new ghost user using a kubectl exec command and then we return
their autogenerated password
"""
sub_header(f"Creating a ghost user for: {user}")
# first, go get the exact name of the pod we need to exec a command on
pod_cmd = (
f"kubectl get pods -n {pod_namespace} "
"-l app.kubernetes.io/instance=ghost-web-app,app.kubernetes.io/component=web"
" --no-headers "
"-o custom-columns=NAME:.metadata.name"
)
pod = subproc([pod_cmd]).rstrip()
log.info(f"ghost web app pod is: {pod}")

# generate a random password
password = create_password()

# then run the user creation command
cmd = (f'kubectl exec -n {pod_namespace} {pod} -- /bin/sh -c "./ghost '
'--config-path ../config/config.yaml admin account create '
f'--username {user} --email {email} --password \'{password}\'"')

# then process the output from the command
subproc([cmd], shell=True, universal_newlines=True)

# then run the user promotion (to admin) command
cmd = (f'kubectl exec -n {pod_namespace} {pod} -- /bin/sh -c '
'"./ghost --config-path ../config/config.yaml admin '
f'account promote --username {user}"')

# then process the output from the command
subproc([cmd], shell=True, universal_newlines=True).split()[3]

return password


def refresh_bweso(argocd: ArgoCD,
ghost_hostname: str,
bitwarden: BwCLI) -> None:
Expand Down Expand Up @@ -290,7 +241,10 @@ def setup_bitwarden_items(argocd: ArgoCD,
backups_s3_password: str,
restic_repo_pass: str,
admin_user: str,
admin_email: str,
mail_host: str,
mail_protocol: str,
mail_from_address: str,
mail_port: str,
mail_user: str,
mail_pass: str,
Expand Down Expand Up @@ -347,35 +301,42 @@ def setup_bitwarden_items(argocd: ArgoCD,
ghost_mysql_password = bitwarden.generate()
mysql_pass_obj = create_custom_field("mysqlPassword",
ghost_mysql_password)
mysql_database_obj = create_custom_field("database", "ghost")
mysql_port_obj = create_custom_field("port", "3306")
db_id = bitwarden.create_login(
name='ghost-mysql-credentials',
item_url=ghost_hostname,
user='ghost',
password=ghost_mysql_password,
fields=[mysql_pass_obj]
fields=[mysql_pass_obj, mysql_database_obj, mysql_port_obj]
)

# SMTP credentials
ghost_smtp_host_obj = create_custom_field("smtpHostname", mail_host)
ghost_smtp_port_obj = create_custom_field("smtpPort", mail_port)
ghost_smtp_protocol_obj = create_custom_field("smtpProtocol", mail_protocol)
ghost_smtp_from_address_obj = create_custom_field("smtpFromAddress", mail_from_address)
smtp_id = bitwarden.create_login(
name='ghost-smtp-credentials',
item_url=ghost_hostname,
user=mail_user,
password=mail_pass,
fields=[ghost_smtp_host_obj, ghost_smtp_port_obj]
fields=[ghost_smtp_host_obj,
ghost_smtp_port_obj,
ghost_smtp_protocol_obj,
ghost_smtp_from_address_obj]
)

# admin credentials for ghost itself
# admin_password = create_password()
# email_obj = create_custom_field("email", ghost_admin_email)
# admin_id = bitwarden.create_login(
# name='ghost-admin-credentials',
# item_url=ghost_hostname,
# user=ghost_admin_username,
# password=admin_password,
# fields=[email_obj]
# )
admin_password = create_password()
email_obj = create_custom_field("email", admin_email)
admin_id = bitwarden.create_login(
name='ghost-admin-credentials',
item_url=ghost_hostname,
user=admin_user,
password=admin_password,
fields=[email_obj]
)

# oidc credentials if they were given, else they're probably already there
if oidc_creds:
Expand All @@ -400,6 +361,7 @@ def setup_bitwarden_items(argocd: ArgoCD,
'ghost_oidc_credentials_bitwarden_id': oidc_id,
'ghost_mysql_credentials_bitwarden_id': db_id,
'ghost_s3_admin_credentials_bitwarden_id': s3_admin_id,
'ghost_admin_credentials_bitwarden_id': admin_id,
'ghost_s3_ghost_credentials_bitwarden_id': s3_id,
'ghost_s3_backups_credentials_bitwarden_id': s3_backups_id})

Expand Down
Loading