summaryrefslogtreecommitdiff
path: root/worker/scripts/ansible_playbook.ts
diff options
context:
space:
mode:
Diffstat (limited to 'worker/scripts/ansible_playbook.ts')
-rwxr-xr-xworker/scripts/ansible_playbook.ts113
1 files changed, 113 insertions, 0 deletions
diff --git a/worker/scripts/ansible_playbook.ts b/worker/scripts/ansible_playbook.ts
new file mode 100755
index 0000000..fe2810b
--- /dev/null
+++ b/worker/scripts/ansible_playbook.ts
@@ -0,0 +1,113 @@
+#!/usr/bin/env -S deno run --allow-env --allow-net --allow-run --allow-read --allow-write
+
+import {
+ Either,
+ getRequiredEnvVars,
+ getStdout,
+ type IEither,
+ LogTraceable,
+ LogMetricTraceable,
+ Metric,
+ prependWith,
+ TraceUtil,
+} from "@emprespresso/pengueno";
+import type { AnsiblePlaybookJob } from "@emprespresso/ci_model";
+import { Bitwarden, type SecureNote } from "@emprespresso/ci_worker";
+
+const eitherJob = getRequiredEnvVars([
+ "path",
+ "playbooks",
+])
+ .mapRight((baseArgs) => (
+ <AnsiblePlaybookJob> {
+ type: "ansible_playbook",
+ arguments: baseArgs,
+ }
+ ));
+
+const eitherVault = Bitwarden.getConfigFromEnvironment()
+ .mapRight((config) => new Bitwarden(config));
+
+const playbookMetric = Metric.fromName("ansiblePlaybook.playbook");
+const _logJob = LogTraceable.of(eitherJob).bimap(TraceUtil.withTrace("ansible_playbook"));
+await LogMetricTraceable.ofLogTraceable(_logJob).bimap(TraceUtil.withMetricTrace(playbookMetric))
+ .peek((tEitherJob) =>
+ tEitherJob.trace.trace("starting ansible playbook job! (⑅˘꒳˘)")
+ )
+ .map((tEitherJob) =>
+ tEitherJob.get().flatMapAsync((job) =>
+ eitherVault.flatMapAsync(async (vault) => {
+ const eitherKey = await vault.unlock(tEitherJob);
+ return eitherKey.mapRight((key) => ({ job, key, vault }));
+ })
+ )
+ )
+ .map(async (tEitherJobVault) => {
+ tEitherJobVault.trace.trace(
+ "getting ansible secwets uwu~",
+ );
+ const eitherJobVault = await tEitherJobVault.get();
+
+ const eitherSshKey = await eitherJobVault
+ .flatMapAsync(({ key, vault }) =>
+ vault.fetchSecret<SecureNote>(tEitherJobVault, key, "ssh_key")
+ );
+ const eitherSshKeyFile = await eitherSshKey.mapRight(({ notes }) => notes)
+ .flatMapAsync(saveToTempFile);
+ const eitherAnsibleSecrets = await eitherJobVault
+ .flatMapAsync(({ key, vault }) =>
+ vault.fetchSecret<SecureNote>(tEitherJobVault, key, "ansible_playbooks")
+ );
+ const eitherAnsibleSecretsFile = await eitherAnsibleSecrets.mapRight((
+ { notes },
+ ) => notes).flatMapAsync(saveToTempFile);
+
+ return eitherJobVault.flatMapAsync(async ({ job, vault, key }) => {
+ const eitherLocked = await vault.lock(tEitherJobVault, key);
+ return eitherLocked.flatMap((_locked) =>
+ eitherSshKeyFile.flatMap((sshKeyFile) =>
+ eitherAnsibleSecretsFile.mapRight((secretsFile) => ({
+ job,
+ sshKeyFile,
+ secretsFile,
+ }))
+ )
+ );
+ });
+ })
+ .map(async (tEitherJobAndSecrets) => {
+ const eitherJobAndSecrets = await tEitherJobAndSecrets.get();
+ return eitherJobAndSecrets.flatMapAsync(
+ ({ job, sshKeyFile, secretsFile }) => {
+ const volumes = [
+ `${job.arguments.path}:/ansible`,
+ `${sshKeyFile}:/root/id_rsa`,
+ `${secretsFile}:/ansible/secrets.yml`,
+ ];
+ const playbookCmd =
+ `ansible-playbook -e @secrets.yml ${job.arguments.playbooks}`;
+ const deployCmd = [
+ "docker",
+ "run",
+ ...prependWith(volumes, "-v"),
+ "willhallonline/ansible:latest",
+ ...playbookCmd.split(" "),
+ ];
+ tEitherJobAndSecrets.trace.trace(
+ `running ansible magic~ (◕ᴗ◕✿) ${deployCmd}`,
+ );
+ return tEitherJobAndSecrets.move(deployCmd).map(getStdout).get();
+ },
+ );
+ })
+ .get();
+
+const saveToTempFile = (text: string): Promise<IEither<Error, string>> =>
+ Either.fromFailableAsync(
+ () => Deno.makeTempDir({ dir: Deno.cwd() })
+ .then((dir) => Deno.makeTempFile({ dir }))
+ .then(async (f) => {
+ await Deno.writeTextFile(f, text);
+ return f;
+ }),
+ );