Compare commits

...

7 Commits

Author SHA1 Message Date
Collin J. Doering f11fbdd3f4
infra/Makefile: Remove CI env var check for terraform workspace switching 2021-12-09 12:50:08 -05:00
Collin J. Doering ec708bcf29
Revert ".drone.jsonnet: TEST - why is the setup step not switching workspaces?"
This reverts commit 5d00301c86.
2021-12-09 12:49:52 -05:00
Collin J. Doering 5d00301c86
.drone.jsonnet: TEST - why is the setup step not switching workspaces? 2021-12-09 12:42:00 -05:00
Collin J. Doering b162752ce6
.drone.jsonnet: Do not use guix shell containerization as it fails within non-privileged docker 2021-12-09 12:17:43 -05:00
Collin J. Doering bc19c03d75
.drone.jsonnet: Fix issue specific to running guix shell/environment via drone-ci 2021-12-09 11:59:51 -05:00
Collin J. Doering 6a00da6970
.drone.jsonnet: Explicitly specify manifest to use for deploySteps 2021-12-09 10:42:47 -05:00
Collin J. Doering 920fe7d9f4
Enhance drone pipeline and switch to jsonnet based configuration
* .drone.yml: This is now a generated file, based on .drone.jsonnet

* .drone.jsonnet: Add jsonnet drone pipeline configuration to replace existing .drone.yml
file. Note, currently this is used to manually generate .drone.yml. I need to determine how
to handle jsonnet libraries effectively as drone's built in jsonnet support does not allow
for importing libraries. In addition to converting to jsonnet, the pipeline was enhanced with
promotion and deployment functionality that has not yet been tested.
2021-12-09 10:34:37 -05:00
3 changed files with 242 additions and 9 deletions

134
.drone.jsonnet Normal file
View File

@ -0,0 +1,134 @@
// See: https://github.com/kradalby/drone-jsonnet/blob/master/drone.libsonnet
local droneStatus = ['success', 'failure'];
local pipeline = {
new():: self.withKind("pipeline"),
withName(name):: self + { name: name },
withKind(kind):: self + { kind: kind },
withType(type):: self + { type: type },
withNode(node):: self + { node: node },
withTrigger(trigger):: self + { trigger: trigger },
withDependsOn(n):: self + { depends_on: n },
withNodeSelector(ns):: self + { node_selector: ns },
withSteps(steps):: self + if std.type(steps) == 'array' then { steps: steps } else { steps: [steps] },
step:: {
new(name='', image=''):: self.withName(name).withImage(image).withPullIfNotExists(),
withName(name):: self + { name: name },
withImage(image):: self + if image != '' then { image: image } else {},
withAlwaysPull():: self + { pull: 'always' },
withPullIfNotExists():: self + { pull: 'if-not-exists' },
withCommands(commands):: self + if std.type(commands) == 'array' then { commands: commands } else { commands: [commands] },
withTrigger(trigger):: self + { trigger: trigger }, // TODO: this is duplicated in pipeline object
withEnv(envs):: self + { environment: envs },
withWhen(when):: self + { when: when },
withSettings(settings):: self + { settings: settings },
},
when:: {
new():: self + {},
withBranch(branch):: self + if std.type(branch) == 'array' then { branch: branch } else { branch: [branch] },
withEvent(e):: self + if std.type(e) == 'array' then { event: e } else { event: [e] },
withStatus(s):: self + if std.type(s) == 'array' then { status: s } else { status: [s] },
withStatusAll():: self.withStatus(droneStatus),
},
};
local trigger = {
new():: self + {},
withBranch(branch):: self + if std.type(branch) == 'array' then { branch: branch } else { branch: [branch] },
withEvent(e):: self + if std.type(e) == 'array' then { event: e } else { event: [e] },
withStatus(s):: self + if std.type(s) == 'array' then { status: s } else { status: [s] },
withStatusAll():: self.withStatus(droneStatus),
};
local env_from_secret(dict) = {
[key]: {
from_secret: dict[key],
}
for key in std.objectFields(dict)
};
local guix_pipeline(name) = pipeline.new()
.withName(name)
.withType("docker")
.withNode({ "guix": "on"});
local guix_step(name,
commands,
image="docker.nexus.home.rekahsoft.ca/guix:latest") =
pipeline.step.new(name, image).withPullIfNotExists().withCommands(commands);
local guix_step_time_machine(name,
commands,
cwd=".",
channels="channels.scm",
image="docker.nexus.home.rekahsoft.ca/guix:latest") =
pipeline.step.new(name, image).withPullIfNotExists().withCommands(
// Conditionally change directory
(if cwd == "."
then [] else [std.format("cd %s", cwd)]) +
// Drone-ci does not populate a /etc/passwd which causes issues with guix
["echo 'root:x:0:0:root:/root:/bin/bash' >> /etc/passwd"] +
// Expand provide guix commands into executable shell
std.map(function(i) std.format("guix time-machine -C %s -- %s", [channels, i]),
if std.type(commands) == 'array' then commands else [commands]));
local dronePromoteCmd(env) = [
"export DRONE_SERVER=\"${DRONE_SYSTEM_PROTO}://${DRONE_SYSTEM_HOST}\"",
std.format('DRONE_PROMOTED_PIPELINE_ID=$(drone build promote --format \'{{ .Number }}\' "$DRONE_REPO" "$DRONE_BUILD_NUMBER" "%s")', env),
'while status="$(drone build info $DRONE_REPO $DRONE_PROMOTED_PIPELINE_ID)"; do
case "$status" in
running)
sleep 30s
;;
success)
break
;;
failure|error|killed)
echo "Promoted job with id $DRONE_PROMOTED_PIPELINE_ID failed with status \'$status\'."
exit 1
;;
*)
echo "Unknown pipeline status \'$status\'."
exit 1
esac
done',
];
local promoteStep(env,
secret_name_drone_token="drone_token",
image="docker.nexus.home.rekahsoft.ca/drone/cli:1.4-alpine") = pipeline.step.new(std.format("promote-%s", env), image)
.withWhen(pipeline.when.new()
.withBranch("master")
.withEvent("push"))
.withCommands(dronePromoteCmd(env))
.withEnv(env_from_secret({
DRONE_TOKEN: "drone_token"
}));
local deployStep(name, target=name, args=[]) = guix_step_time_machine(
name,
std.format('shell -m manifest.scm -- make %s ENV="${DRONE_DEPLOY_TO}" %s', [target, std.join(" ", args)]),
cwd="infra",
channels="../channels.scm")
.withEnv({ PLAN: "out.plan" } + env_from_secret({
AWS_ACCESS_KEY_ID: "aws_access_key_id",
AWS_SECRET_ACCESS_KEY: "aws_secret_access_key",
}));
[
guix_pipeline("validate").withTrigger(trigger.new().withEvent(["push", "pull_request", "tag"])).withSteps([
guix_step_time_machine("build", "build -f guix.scm"),
promoteStep("staging"),
promoteStep("production"),
]),
guix_pipeline("deploy").withTrigger(trigger.new().withEvent("promote")).withSteps([
deployStep("init", "setup"),
deployStep("plan"),
deployStep("deploy"),
])
]

View File

@ -1,17 +1,118 @@
---
kind: pipeline
type: docker
name: blog-rekahsoft-ca
name: validate
node:
guix: on
workspace:
path: /drone/blog-rekahsoft-ca
platform:
os: linux
arch: amd64
steps:
- name: build
pull: if-not-exists
image: docker.nexus.home.rekahsoft.ca/guix:latest
commands:
- guix --version
- echo 'root:x:0:0:root:/root:/bin/bash' >> /etc/passwd
- guix time-machine -C channels.scm -- build -f guix.scm
- name: promote-staging
pull: if-not-exists
image: docker.nexus.home.rekahsoft.ca/drone/cli:1.4-alpine
commands:
- export DRONE_SERVER="${DRONE_SYSTEM_PROTO}://${DRONE_SYSTEM_HOST}"
- DRONE_PROMOTED_PIPELINE_ID=$(drone build promote --format '{{ .Number }}' "$DRONE_REPO" "$DRONE_BUILD_NUMBER" "staging")
- "while status=\"$(drone build info $DRONE_REPO $DRONE_PROMOTED_PIPELINE_ID)\"; do\ncase \"$status\" in\n running)\n sleep 30s\n ;;\n success)\n break\n ;;\n failure|error|killed)\n echo \"Promoted job with id $DRONE_PROMOTED_PIPELINE_ID failed with status '$status'.\"\n exit 1\n ;;\n *)\n echo \"Unknown pipeline status '$status'.\"\n exit 1\nesac\ndone"
environment:
DRONE_TOKEN:
from_secret: drone_token
when:
branch:
- master
event:
- push
- name: promote-production
pull: if-not-exists
image: docker.nexus.home.rekahsoft.ca/drone/cli:1.4-alpine
commands:
- export DRONE_SERVER="${DRONE_SYSTEM_PROTO}://${DRONE_SYSTEM_HOST}"
- DRONE_PROMOTED_PIPELINE_ID=$(drone build promote --format '{{ .Number }}' "$DRONE_REPO" "$DRONE_BUILD_NUMBER" "production")
- "while status=\"$(drone build info $DRONE_REPO $DRONE_PROMOTED_PIPELINE_ID)\"; do\ncase \"$status\" in\n running)\n sleep 30s\n ;;\n success)\n break\n ;;\n failure|error|killed)\n echo \"Promoted job with id $DRONE_PROMOTED_PIPELINE_ID failed with status '$status'.\"\n exit 1\n ;;\n *)\n echo \"Unknown pipeline status '$status'.\"\n exit 1\nesac\ndone"
environment:
DRONE_TOKEN:
from_secret: drone_token
when:
branch:
- master
event:
- push
node:
guix: on
trigger:
event:
- push
- pull_request
- tag
---
kind: pipeline
type: docker
name: deploy
platform:
os: linux
arch: amd64
steps:
- name: init
pull: if-not-exists
image: docker.nexus.home.rekahsoft.ca/guix:latest
commands:
- cd infra
- echo 'root:x:0:0:root:/root:/bin/bash' >> /etc/passwd
- "guix time-machine -C ../channels.scm -- shell -m manifest.scm -- make setup ENV=\"${DRONE_DEPLOY_TO}\" "
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
AWS_SECRET_ACCESS_KEY:
from_secret: aws_secret_access_key
PLAN: out.plan
- name: plan
pull: if-not-exists
image: docker.nexus.home.rekahsoft.ca/guix:latest
commands:
- cd infra
- echo 'root:x:0:0:root:/root:/bin/bash' >> /etc/passwd
- "guix time-machine -C ../channels.scm -- shell -m manifest.scm -- make plan ENV=\"${DRONE_DEPLOY_TO}\" "
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
AWS_SECRET_ACCESS_KEY:
from_secret: aws_secret_access_key
PLAN: out.plan
- name: deploy
pull: if-not-exists
image: docker.nexus.home.rekahsoft.ca/guix:latest
commands:
- cd infra
- echo 'root:x:0:0:root:/root:/bin/bash' >> /etc/passwd
- "guix time-machine -C ../channels.scm -- shell -m manifest.scm -- make deploy ENV=\"${DRONE_DEPLOY_TO}\" "
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
AWS_SECRET_ACCESS_KEY:
from_secret: aws_secret_access_key
PLAN: out.plan
node:
guix: on
trigger:
event:
- promote
...

View File

@ -14,10 +14,8 @@ setup: init workspace
.PHONY: workspace
workspace:
ifneq ($(SELECTED_WORKSPACE),$(ENV))
ifndef CI
@terraform workspace select $(ENV)
endif
endif
.PHONY: init
init: