hswaw: add kasownik

Change-Id: I48739f9d4ecb8244a2baff5d38a308f7612940eb
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1990
Reviewed-by: informatic <informatic@hackerspace.pl>
changes/90/1990/19
radex 2024-07-05 16:15:38 +02:00
parent 5249a9aa06
commit 2f93220889
5 changed files with 237 additions and 0 deletions

View File

@ -385,6 +385,7 @@ local admins = import "lib/admins.libsonnet";
{ namespace: "cebulacamp", dns: "cebula.camp" },
{ namespace: "engelsystem-prod", dns: "engelsystem.hackerspace.pl" },
{ namespace: "invoicer", dns: "invoicer.hackerspace.pl" },
{ namespace: "kasownik", dns: "kasownik.hackerspace.pl" },
{ namespace: "labelmaker", dns: "label.hackerspace.pl" },
{ namespace: "labelmaker", dns: "*.label.hackerspace.pl" },
{ namespace: "ldapweb", dns: "profile.hackerspace.pl" },
@ -484,6 +485,9 @@ local admins = import "lib/admins.libsonnet";
"arsenicum",
"radex",
],
"kasownik": [
"radex",
],
"labelmaker": [
"radex",
],

3
hswaw/kasownik/OWNERS Normal file
View File

@ -0,0 +1,3 @@
owners:
- informatic
- radex

5
hswaw/kasownik/README.md Normal file
View File

@ -0,0 +1,5 @@
# kasownik
Warsaw Hackerspace Membership Management System
Source and docs: https://code.hackerspace.pl/hswaw/kasownik

View File

@ -0,0 +1,42 @@
local kube = import "../../kube/hscloud.libsonnet";
// NOTE: Run `kubectl -n kasownik delete job/kasownik-clear-lockfile; kubecfg update hswaw/kasownik/clear_lockfile.jsonnet` to clear lockfile
// This will not work if cronjob pod is still running (volume won't be mounted)
{
local top = self,
local cfg = self.cfg,
cfg:: {
name: 'kasownik',
namespace: 'kasownik',
},
local ns = kube.Namespace(cfg.namespace),
clear_lockfile: ns.Contain(kube.Job(cfg.name + '-clear-lockfile')) {
spec+: {
ttlSecondsAfterFinished: 10, // NOTE: does not work, requires k8s 1.23
template+: {
spec+: {
containers_: {
default: kube.Container("default") {
image: 'alpine:3.20.1',
volumeMounts_: {
data: { mountPath: '/data' },
},
command: ["sh", "-c", |||
set -e -x
rm /data/kasownik.lock
|||]
}
},
volumes_: {
data: {
persistentVolumeClaim: { claimName: cfg.name + '-fetch-data' },
},
}
}
}
}
}
}

183
hswaw/kasownik/prod.jsonnet Normal file
View File

@ -0,0 +1,183 @@
local kube = import "../../kube/hscloud.libsonnet";
local postgres = import "../../kube/postgres.libsonnet";
// Setup:
// - create `kasownik` and `kasownik-fetch` secrets
// - run `./manage.py syncdb` to create db
// - create `cache` folder in the fetch_data PVC
{
local top = self,
local cfg = self.cfg,
cfg:: {
name: 'kasownik',
namespace: 'kasownik',
domain: 'kasownik.hackerspace.pl',
image: 'registry.k0.hswaw.net/radex/kasownik:20240710124006',
oauthClientId: 'd5770622-a661-45d1-9356-b8cb77de708c',
storageClassName: "waw-hdd-redundant-3",
},
secretRefs:: {
oauth: { secretKeyRef: { name: cfg.name, key: 'oauth_secret' } },
secret_key: { secretKeyRef: { name: cfg.name, key: 'secret_key' } },
ldap: { secretKeyRef: { name: cfg.name, key: 'ldap_password' } },
postgres: { secretKeyRef: { name: cfg.name, key: 'postgres_password' } },
smtp: { secretKeyRef: { name: cfg.name, key: 'smtp_password' } },
fetch: {
local name = cfg.name + '-fetch',
tdid: { secretKeyRef: { name: name, key: 'tdid' } },
alias: { secretKeyRef: { name: name, key: 'alias' } },
password: { secretKeyRef: { name: name, key: 'password' } },
user_agent: { secretKeyRef: { name: name, key: 'user-agent' } },
}
},
local ns = kube.Namespace(cfg.namespace),
env:: {
// Quirk: Must be alphabetically before SQLALCHEMY_DATABASE_URI
POSTGRES_PASSWORD: top.secretRefs.postgres,
SQLALCHEMY_DATABASE_URI: 'postgresql+psycopg2://%s:%s@%s:%s/%s' % [
top.postgres.cfg.username,
'$(POSTGRES_PASSWORD)',
top.postgres.svc.host,
top.postgres.svc.port,
top.postgres.cfg.database,
],
SPACEAUTH_CONSUMER_KEY: cfg.oauthClientId,
SPACEAUTH_CONSUMER_SECRET: top.secretRefs.oauth,
SECRET_KEY: top.secretRefs.secret_key,
DISABLE_LDAP: 'false',
LDAP_URI: 'ldap://ldap.hackerspace.pl',
LDAP_BIND_DN: 'cn=kasownik,ou=Services,dc=hackerspace,dc=pl',
LDAP_BIND_PASSWORD: top.secretRefs.ldap,
SMTP_USER: 'kasownik',
SMTP_PASSWORD: top.secretRefs.smtp,
MEMBERSHIP_FEES: std.manifestJson({
starving: 75,
fatty: 150,
}),
},
deployment: ns.Contain(kube.Deployment(cfg.name)) {
spec+: {
replicas: 1,
template+: {
spec+: {
containers_: {
default: kube.Container("default") {
image: cfg.image,
ports_: {
http: { containerPort: 5000 },
},
env_: top.env,
livenessProbe: {
httpGet: { path: '/', port: 5000 },
initialDelaySeconds: 20,
periodSeconds: 5 * 60,
},
},
},
},
},
},
},
cronjob: ns.Contain(kube.CronJob(cfg.name + '-cronjob')) {
spec+: {
schedule: "05 11,15,18 * * *", // after Elixir sessions
jobTemplate+: {
spec+: {
template+: {
spec+: {
containers_: {
default: kube.Container("default") {
image: cfg.image,
volumeMounts_: {
data: { mountPath: '/data' },
config: { mountPath: '/config' },
},
command: ["sh", "-c", |||
set -e -x
python /usr/src/fetch/banking-pekaobiznes.py --config /config/config.ini
./manage.py automatch
./manage.py ldapsync --dry-run
|||],
env_: top.env + {
SCRAPER_TDID: top.secretRefs.fetch.tdid,
SCRAPER_ALIAS: top.secretRefs.fetch.alias,
SCRAPER_PASSWORD: top.secretRefs.fetch.password,
SCRAPER_USER_AGENT: top.secretRefs.fetch.user_agent,
},
},
},
volumes_: {
data: top.fetch_data.volume,
config: top.fetch_config.volume,
}
}
}
}
}
}
},
fetch_config: ns.Contain(kube.ConfigMap(cfg.name + '-fetch-config')) {
data: {
"config.ini": std.manifestIni({
sections: {
general: {
cache_dir: '/data/cache',
lockfile: '/data/kasownik.lock',
},
database: {
uri: '${SQLALCHEMY_DATABASE_URI}'
},
scraper: {
tdid: '${SCRAPER_TDID}',
alias: '${SCRAPER_ALIAS}',
password: '${SCRAPER_PASSWORD}',
user_agent: '${SCRAPER_USER_AGENT}',
},
logging: {
level: 'DEBUG',
}
}
})
},
},
// used for lockfile and fetch cache
fetch_data: ns.Contain(kube.PersistentVolumeClaim(cfg.name + '-fetch-data')) {
storage:: "1Gi",
storageClass:: cfg.storageClassName,
spec+: {
accessModes: ['ReadWriteMany']
}
},
postgres: ns.Contain(postgres) {
cfg+: {
prefix: cfg.name + '-',
appName: cfg.name,
storageClassName: cfg.storageClassName,
version: '15.4',
database: 'kasownik',
username: 'kasownik',
password: top.secretRefs.postgres,
}
},
service: ns.Contain(kube.Service(cfg.name)) {
target:: top.deployment,
},
ingress: ns.Contain(kube.SimpleIngress(cfg.name)) {
hosts:: [cfg.domain],
target:: top.service,
},
}