Skip to content

Commit

Permalink
feat: components/azure-db (#62)
Browse files Browse the repository at this point in the history
* feat: components/azure-db

* fix: azure-db

* feat: add utils/getPgServerHostname.ts

* feat: add components/pg-secret

* fix: tests

* fix: typo

* fix: dont use fixed names for azure-db and pg-secret

* fix: getPgServerHostname
  • Loading branch information
Julien Bouquillon committed Jul 1, 2020
1 parent ca8decb commit 90de6d4
Show file tree
Hide file tree
Showing 11 changed files with 522 additions and 0 deletions.
167 changes: 167 additions & 0 deletions src/components/azure-db/__snapshots__/index.test.ts.snap
@@ -0,0 +1,167 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should return a create-db job 1`] = `
Object {
"createDbJob": Object {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": Object {
"labels": Object {
"app": "test-job",
},
"name": "test-job",
"namespace": "sample-42-my-test",
},
"spec": Object {
"backoffLimit": 0,
"template": Object {
"spec": Object {
"containers": Array [
Object {
"command": Array [
"create-db-user",
],
"env": Array [
Object {
"name": "NEW_DB_NAME",
"value": "some-db",
},
Object {
"name": "NEW_USER",
"value": "tester",
},
Object {
"name": "NEW_PASSWORD",
"value": "passw0rd",
},
Object {
"name": "NEW_DB_EXTENSIONS",
"value": "hstore pgcrypto citext",
},
],
"envFrom": Array [
Object {
"secretRef": Object {
"name": "azure-pg-admin-user",
},
},
],
"image": "registry.gitlab.factory.social.gouv.fr/socialgouv/docker/azure-db:0.28.0",
"imagePullPolicy": "IfNotPresent",
"name": "create-db-user",
"resources": Object {
"limits": Object {
"cpu": "300m",
"memory": "256Mi",
},
"requests": Object {
"cpu": "100m",
"memory": "64Mi",
},
},
},
],
"restartPolicy": "Never",
},
},
},
},
}
`;

exports[`should throw because of missing variables 1`] = `
"BadArgument:
├─ required property \\"database\\"
│ └─ cannot decode undefined, should be string
├─ required property \\"password\\"
│ └─ cannot decode undefined, should be string
└─ required property \\"user\\"
└─ cannot decode undefined, should be string"
`;

exports[`should throw because of missing variables 2`] = `
"BadArgument:
├─ required property \\"database\\"
│ └─ cannot decode undefined, should be string
└─ required property \\"password\\"
└─ cannot decode undefined, should be string"
`;

exports[`should throw because of missing variables 3`] = `
"BadArgument:
├─ required property \\"database\\"
│ └─ cannot refine \\"\\", should be NonEmptyString
├─ required property \\"password\\"
│ └─ cannot refine \\"\\", should be NonEmptyString
└─ required property \\"user\\"
└─ cannot refine \\"\\", should be NonEmptyString"
`;

exports[`should use custom extensions 1`] = `
Object {
"createDbJob": Object {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": Object {
"labels": Object {
"app": "test-job",
},
"name": "test-job",
"namespace": "sample-42-my-test",
},
"spec": Object {
"backoffLimit": 0,
"template": Object {
"spec": Object {
"containers": Array [
Object {
"command": Array [
"create-db-user",
],
"env": Array [
Object {
"name": "NEW_DB_NAME",
"value": "some-db",
},
Object {
"name": "NEW_USER",
"value": "tester",
},
Object {
"name": "NEW_PASSWORD",
"value": "passw0rd",
},
Object {
"name": "NEW_DB_EXTENSIONS",
"value": "pgjwt",
},
],
"envFrom": Array [
Object {
"secretRef": Object {
"name": "azure-pg-admin-user",
},
},
],
"image": "registry.gitlab.factory.social.gouv.fr/socialgouv/docker/azure-db:0.28.0",
"imagePullPolicy": "IfNotPresent",
"name": "create-db-user",
"resources": Object {
"limits": Object {
"cpu": "300m",
"memory": "256Mi",
},
"requests": Object {
"cpu": "100m",
"memory": "64Mi",
},
},
},
],
"restartPolicy": "Never",
},
},
},
},
}
`;
74 changes: 74 additions & 0 deletions src/components/azure-db/create-db.job.ts
@@ -0,0 +1,74 @@
import { metadataFromParams } from "@socialgouv/kosko-charts/components/app/metadata";
import { Job } from "kubernetes-models/batch/v1/Job";

import { Params } from "./params";

const DEFAULT_EXTENSIONS = "hstore pgcrypto citext";

// needs azure-pg-admin-user secret
export const createDbJob = ({
database,
user,
password,
extensions = DEFAULT_EXTENSIONS,
...params
}: Params): Job => {
const job = new Job({
metadata: {
...metadataFromParams(params),
},
spec: {
backoffLimit: 0,
template: {
spec: {
containers: [
{
command: ["create-db-user"],
env: [
{
name: "NEW_DB_NAME",
value: database,
},
{
name: "NEW_USER",
value: user,
},
{
name: "NEW_PASSWORD",
value: password,
},
{
name: "NEW_DB_EXTENSIONS",
value: extensions,
},
],
envFrom: [
{
secretRef: {
name: `azure-pg-admin-user`,
},
},
],
image:
"registry.gitlab.factory.social.gouv.fr/socialgouv/docker/azure-db:0.28.0",
imagePullPolicy: "IfNotPresent",
name: "create-db-user",
resources: {
limits: {
cpu: "300m",
memory: "256Mi",
},
requests: {
cpu: "100m",
memory: "64Mi",
},
},
},
],
restartPolicy: "Never",
},
},
},
});
return job;
};
47 changes: 47 additions & 0 deletions src/components/azure-db/index.test.ts
@@ -0,0 +1,47 @@
import { GlobalEnvironment } from "@socialgouv/kosko-charts/types";

import { create } from "./index";
import { CreateDbJobParameters, Params } from "./params";

test.each([
["because of missing variables", {} as Params],
["because of missing variables", { user: "zorro" } as Params],
[
"because of missing variables",
{ database: "", password: "", user: "" } as Params,
],
])("should throw %s", (_: string, params: Params) => {
expect(() => create(params)).toThrowErrorMatchingSnapshot();
});

const validParams: CreateDbJobParameters = {
database: "some-db",
name: "test-job",
password: "passw0rd",
user: "tester",
};

const globalParams: GlobalEnvironment = {
domain: "",
namespace: { name: "sample-42-my-test" },
subdomain: "",
};

test("should return a create-db job", () => {
expect(
create({
...globalParams,
...validParams,
})
).toMatchSnapshot();
});

test("should use custom extensions", () => {
expect(
create({
...globalParams,
...validParams,
extensions: "pgjwt",
})
).toMatchSnapshot();
});
18 changes: 18 additions & 0 deletions src/components/azure-db/index.ts
@@ -0,0 +1,18 @@
import { onDecodeError } from "@socialgouv/kosko-charts/utils/onDecodeError";
import { fold } from "fp-ts/lib/Either";
import { pipe } from "fp-ts/lib/pipeable";
import { Job } from "kubernetes-models/batch/v1/Job";

import { createDbJob } from "./create-db.job";
import { CreateDbComponentParams, Params } from "./params";

const mapper = (params: Params): { createDbJob: Job } => ({
createDbJob: createDbJob(params),
});

export const create = (params: Params): { createDbJob: Job } =>
pipe(
params,
CreateDbComponentParams.decode,
fold(onDecodeError, () => mapper(params))
);
26 changes: 26 additions & 0 deletions src/components/azure-db/params.ts
@@ -0,0 +1,26 @@
import {
GlobalEnvironment,
NamedComponentEnvironment,
} from "@socialgouv/kosko-charts/types";
import { NonEmptyString } from "@socialgouv/kosko-charts/utils/NonEmptyString";
import * as D from "io-ts/lib/Decoder";

export const CreateDbComponentParams = D.intersection(
D.type({
database: NonEmptyString,
password: NonEmptyString,
user: NonEmptyString,
}),
D.partial({
extensions: NonEmptyString,
})
);

export interface CreateDbJobParameters extends NamedComponentEnvironment {
database: string;
user: string;
password: string;
extensions?: string;
}

export type Params = CreateDbJobParameters & GlobalEnvironment;
58 changes: 58 additions & 0 deletions src/components/pg-secret/__snapshots__/index.test.ts.snap
@@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should return a new PG secret 1`] = `
Object {
"createSecret": Object {
"apiVersion": "v1",
"kind": "Secret",
"metadata": Object {
"labels": Object {
"app": "test-job",
},
"name": "test-job",
"namespace": "sample-42-my-test",
},
"stringData": Object {
"DATABASE_URL": "postgresql://tester%40pouet.com:passw0rd@pouet.com/some-db?sslmode=require",
"HASURA_GRAPHQL_DATABASE_URL": "postgresql://tester%40pouet.com:passw0rd@pouet.com/some-db?sslmode=require",
"PGDATABASE": "some-db",
"PGHOST": "pouet.com",
"PGPASSWORD": "passw0rd",
"PGSSLMODE": "require",
"PGUSER": "tester@pouet.com",
},
},
}
`;

exports[`should throw because of missing variables 1`] = `
"BadArgument:
├─ required property \\"database\\"
│ └─ cannot decode undefined, should be string
├─ required property \\"host\\"
│ └─ cannot decode undefined, should be string
├─ required property \\"password\\"
│ └─ cannot decode undefined, should be string
└─ required property \\"user\\"
└─ cannot decode undefined, should be string"
`;

exports[`should throw because of missing variables 2`] = `
"BadArgument:
├─ required property \\"database\\"
│ └─ cannot decode undefined, should be string
├─ required property \\"host\\"
│ └─ cannot decode undefined, should be string
└─ required property \\"password\\"
└─ cannot decode undefined, should be string"
`;

exports[`should throw because of missing variables 3`] = `
"BadArgument:
├─ required property \\"database\\"
│ └─ cannot refine \\"\\", should be NonEmptyString
├─ required property \\"password\\"
│ └─ cannot refine \\"\\", should be NonEmptyString
└─ required property \\"user\\"
└─ cannot refine \\"\\", should be NonEmptyString"
`;

0 comments on commit 90de6d4

Please sign in to comment.