From 9bad5739c6222b857948cadbb1d0a94b68ef35dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 1 Jul 2024 01:00:58 +0100 Subject: [PATCH] feat: add mongodb resource for creating db users --- dev/wireguard/01-wireguard.yaml | 104 --------- dev/wireguard/add-vpn.sh | 11 - services/pulumi/package.json | 5 +- services/pulumi/resources/mongodb.ts | 202 ++++++++++++++++++ .../pulumi/services/ementas/deployments.ts | 13 +- services/pulumi/sync-crds.sh | 2 +- services/pulumi/utils/pulumi.ts | 16 ++ 7 files changed, 232 insertions(+), 121 deletions(-) delete mode 100644 dev/wireguard/01-wireguard.yaml delete mode 100755 dev/wireguard/add-vpn.sh create mode 100644 services/pulumi/resources/mongodb.ts create mode 100644 services/pulumi/utils/pulumi.ts diff --git a/dev/wireguard/01-wireguard.yaml b/dev/wireguard/01-wireguard.yaml deleted file mode 100644 index 4ab390f..0000000 --- a/dev/wireguard/01-wireguard.yaml +++ /dev/null @@ -1,104 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: wireguard - labels: - name: wireguard ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: pv-claim-wireguard - namespace: wireguard -spec: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10M ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: wireguard-configmap - namespace: wireguard -data: - PUID: "1000" - PGID: "1000" - TZ: "Europe/Lisbon" - SERVERPORT: "31820" - PEERS: "5" - PEERDNS: "10.96.0.10" - ALLOWEDIPS: "0.0.0.0/0, ::/0" - INTERNAL_SUBNET: "10.13.13.0" ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: wireguard - namespace: wireguard - labels: - app: wireguard -spec: - replicas: 1 - selector: - matchLabels: - app: wireguard - template: - metadata: - labels: - app: wireguard - spec: - containers: - - name: wireguard - image: ghcr.io/linuxserver/wireguard - envFrom: - - configMapRef: - name: wireguard-configmap - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_MODULE - privileged: true - volumeMounts: - - name: wg-config - mountPath: /config - - name: host-volumes - mountPath: /lib/modules - ports: - - containerPort: 51820 - protocol: UDP - resources: - requests: - memory: "64Mi" - cpu: "100m" - limits: - memory: "128Mi" - cpu: "200m" - volumes: - - name: wg-config - persistentVolumeClaim: - claimName: pv-claim-wireguard - - name: host-volumes - hostPath: - path: /lib/modules - type: Directory ---- -kind: Service -apiVersion: v1 -metadata: - labels: - k8s-app: wireguard - name: wireguard-service - namespace: wireguard -spec: - type: NodePort - ports: - - port: 51820 - nodePort: 31820 - protocol: UDP - targetPort: 51820 - selector: - app: wireguard \ No newline at end of file diff --git a/dev/wireguard/add-vpn.sh b/dev/wireguard/add-vpn.sh deleted file mode 100755 index ba261bc..0000000 --- a/dev/wireguard/add-vpn.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -cd "$(dirname "$0")" - -kubectl apply -f 01-wireguard.yaml - -kubectl wait --for=jsonpath='.status.readyReplicas'=1 -n wireguard deployment/wireguard -sleep 5 - -kubectl -n wireguard exec deployment/wireguard -- cat /config/peer1/peer1.conf > ~/peer1.conf -nmcli connection import type wireguard file ~/peer1.conf \ No newline at end of file diff --git a/services/pulumi/package.json b/services/pulumi/package.json index 69ea140..2ed6f8f 100644 --- a/services/pulumi/package.json +++ b/services/pulumi/package.json @@ -10,7 +10,10 @@ "@pulumi/pulumi": "^3.113.0" }, "imports": { - "#crds": "./crds/nodejs/index.ts" + "#crds": "./crds/nodejs/index.ts", + "#resources/": "./resources/", + "#services/": "./services/", + "#utils/": "./utils/" }, "packageManager": "pnpm@9.1.0+sha512.67f5879916a9293e5cf059c23853d571beaf4f753c707f40cb22bed5fb1578c6aad3b6c4107ccb3ba0b35be003eb621a16471ac836c87beb53f9d54bb4612724" } diff --git a/services/pulumi/resources/mongodb.ts b/services/pulumi/resources/mongodb.ts new file mode 100644 index 0000000..43890e6 --- /dev/null +++ b/services/pulumi/resources/mongodb.ts @@ -0,0 +1,202 @@ +import { PulumiInputify } from "#utils/pulumi.js"; +import * as pulumi from "@pulumi/pulumi"; +import * as k8s from "@pulumi/kubernetes"; +import * as crds from "#crds"; +import { resolve } from "path"; + +type Role = + // Database user roles + | "read" + | "readWrite" + // Database administration roles + | "dbAdmin" + | "dbOwner" + | "userAdmin" + // Cluster administration roles + | "clusterAdmin" + | "clusterManager" + | "clusterMonitor" + | "enableSharding" + | "hostManager" + // Backup and restoration roles + | "backup" + | "restore" + // All database roles + | "readAnyDatabase" + | "readWriteAnyDatabase" + | "userAdminAnyDatabase" + | "dbAdminAnyDatabase" + // Superuser roles + | "root"; +// User-defined roles +// | (string & {}); + +type User = { + db: Databases; + password: string; + connectionStringSecretMetadata?: { + namespace?: string; + name?: string; + }; + roles: { + name: Role; + db: Databases; + }[]; +}; + +type Args = { + readonly dbs: Databases[]; + metadata?: Omit; + spec?: Omit< + crds.types.input.mongodbcommunity.v1.MongoDBCommunitySpecArgs, + "users" + >; +}; + +export class MongoDBCommunity< + const Databases extends string +> extends pulumi.ComponentResource<{}> { + private name: string; + private namespace: pulumi.Output; + private users: pulumi.Output[]; + private secrets: k8s.core.v1.Secret[]; + + private resourcePromise: Promise; + private resolveResourcePromise: () => void; + + constructor( + name: string, + args: Args, + opts?: pulumi.ComponentResourceOptions + ) { + super("niployments:mongodb:MongoDBCommunity", name, {}, opts); + + this.name = name; + this.users = []; + this.secrets = []; + + this.resolveResourcePromise = () => { throw new Error("resolveResourcePromise not set") }; + this.resourcePromise = new Promise((resolve) => { + this.resolveResourcePromise = resolve; + }); + + this.namespace = pulumi.output(args.metadata?.namespace); + + const operatorName = `${this.name}-operator`; + new crds.mongodbcommunity.v1.MongoDBCommunity( + operatorName, + { + metadata: { + ...args.metadata, + name: operatorName, + }, + spec: args.spec && { + ...args.spec, + users: pulumi.output(this.resourcePromise.then(() => this.users)), + }, + }, + { parent: this } + ); + } + + protected async initialize(args: pulumi.Inputs): Promise<{}> { + await this.resourcePromise; + pulumi.log.error("MongoDBCommunity initialized"); + return {}; + } + + public addUser(name: string, user: PulumiInputify>) { + const resolvedUser = pulumi.output(user); + + const credentialsSecretName = `${this.name}-${name}-credentials-secret`; + const credentialsSecret = new k8s.core.v1.Secret( + credentialsSecretName, + { + metadata: this.namespace.apply((namespace) => ({ + namespace, + name: credentialsSecretName, + })), + stringData: { + password: resolvedUser.password, + }, + }, + { parent: this } + ); + + this.secrets.push(credentialsSecret); + + this.users.push( + pulumi.all([resolvedUser, credentialsSecret.metadata]).apply(([user, credentialsSecretMetadata]) => ({ + connectionStringSecretName: user.connectionStringSecretMetadata?.name, + connectionStringSecretNamespace: + user.connectionStringSecretMetadata?.namespace, + db: user.db, + name, + passwordSecretRef: { + name: credentialsSecretMetadata.name, + }, + roles: user.roles, + scramCredentialsSecretName: `${this.name}-${name}-scram-credentials-secret`, + })) + ); + } + + public finish() { + pulumi.log.error("MongoDBCommunity finishing"); + this.resolveResourcePromise(); + } +} + + +const db = new MongoDBCommunity("mongodb", { + dbs: ["admin", "nimentas", "fkjkhgkdjf"], + metadata: { + namespace: "mongodb", + }, + spec: { + type: "ReplicaSet", + members: 3, + version: "6.0.5", + security: { + authentication: { + modes: ["SCRAM"], + }, + }, + additionalMongodConfig: { + "storage.wiredTiger.engineConfig.journalCompressor": "zlib", + }, + statefulSet: { + spec: { + volumeClaimTemplates: [ + { + metadata: { + name: "data-volume", + }, + spec: { + accessModes: ["ReadWriteOnce"], + resources: { + requests: { + storage: "5Gi", + }, + }, + }, + }, + ], + }, + }, + }, +}); + +db.addUser("ni", { + db: "fkjkhgkdjf", + password: "pass", + roles: [ + { + db: "admin", + name: "root", + }, + ], +}) +; + +db.finish(); \ No newline at end of file diff --git a/services/pulumi/services/ementas/deployments.ts b/services/pulumi/services/ementas/deployments.ts index 4f24e8c..ecaf85e 100644 --- a/services/pulumi/services/ementas/deployments.ts +++ b/services/pulumi/services/ementas/deployments.ts @@ -34,12 +34,17 @@ export const website = new k8s.apps.v1.Deployment("ementas-website", { containerPort, }, ], - envFrom: [ + env: [ { - secretRef: { - name: secrets.metadata.name, + name: "DATABASE_URL", + valueFrom: { + secretKeyRef: { + name: secrets.metadata.name, + key: "connectionString.standard", + optional: false, + }, }, - }, + } ], }, ], diff --git a/services/pulumi/sync-crds.sh b/services/pulumi/sync-crds.sh index 5f91092..1f6efa0 100755 --- a/services/pulumi/sync-crds.sh +++ b/services/pulumi/sync-crds.sh @@ -96,7 +96,7 @@ function download_crds { local chart_id="$(echo "$helm_crd" | yq '.chart')" local chart_version="$(echo "$helm_crd" | yq '.version // "*"')" - echo "[Helm CRDs] Downloading CRDs for $chart_id:chart_version" 1>&2 + echo "[Helm CRDs] Downloading CRDs for $chart_id:$chart_version" 1>&2 crds+=("$(download_crds_from_helm "$chart_id" "$chart_version" "$dir")") done diff --git a/services/pulumi/utils/pulumi.ts b/services/pulumi/utils/pulumi.ts new file mode 100644 index 0000000..32571b9 --- /dev/null +++ b/services/pulumi/utils/pulumi.ts @@ -0,0 +1,16 @@ +import * as pulumi from "@pulumi/pulumi"; + +type RecursivePulumiInput = + T extends object + ? pulumi.Input<{ [K in keyof T]: RecursivePulumiInput }> + : T extends undefined + ? undefined + : pulumi.Input; + +type X = RecursivePulumiInput; + +export type PulumiInputify = RecursivePulumiInput>; + +export function applyInDeployment(value: pulumi.Output, inDryRun: pulumi.Input, inDeployment: (value: Input) => pulumi.Input) { + return value.apply((value) => pulumi.output(pulumi.runtime.isDryRun() ? inDryRun : inDeployment(value))); +}