- Add socket activation to systemd unit which triggers nixos-rebuild

- Add call to socket to deployment workflow
- Improve queued deploymentspec error messages and other minor stuff
- Add CI
This commit is contained in:
Marco Streich 2021-01-22 10:35:36 +01:00
parent eb425941eb
commit 96991585cd
5 changed files with 111 additions and 23 deletions

29
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,29 @@
image: docker:latest
services:
- docker:dind
stages:
- build
- release
variables:
BUILD_IMAGE: registry.gitlab.com/infektweb/glv5/hetzner-cloud-environment/deploymentagent:$CI_COMMIT_REF_NAME
RELEASE_IMAGE: registry.gitlab.com/infektweb/glv5/hetzner-cloud-environment/deploymentagent:latest
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
build:
stage: build
script:
- cd deploymentagent/src/deploymentagent && docker build --build-arg CI_JOB_TOKEN=$CI_JOB_TOKEN --pull -t $BUILD_IMAGE .
- docker push $BUILD_IMAGE
release:
stage: release
script:
- docker pull $BUILD_IMAGE
- docker tag $BUILD_IMAGE $RELEASE_IMAGE
- docker push $RELEASE_IMAGE
only:
- master

View File

@ -4,17 +4,21 @@ WORKDIR /go/src/app
COPY . .
RUN apk add --no-cache openssh git && \
git config --global url."git@gitlab.com:".insteadOf "https://gitlab.com/" && \
mkdir /root/.ssh && \
ssh-keyscan gitlab.com >> /root/.ssh/known_hosts
RUN apk add --no-cache openssh git
ARG SSH_KEY
ENV SSH_KEY=${SSH_KEY}
ARG CI_JOB_TOKEN
ENV CI_JOB_TOKEN=${CI_JOB_TOKEN}
RUN printf "$SSH_KEY" | base64 -d > /root/.ssh/id_rsa && chmod 600 /root/.ssh/id_rsa && \
go build -o deploymentagent && \
rm /root/.ssh/id_rsa
RUN test -n "$SSH_KEY" && \
{ mkdir /root/.ssh && ssh-keyscan gitlab.com >> /root/.ssh/known_hosts && printf "$SSH_KEY" | base64 -d > /root/.ssh/id_rsa && chmod 600 /root/.ssh/id_rsa && git config --global url."git@gitlab.com:".insteadOf "https://gitlab.com/"; } || true
RUN test -n "$CI_JOB_TOKEN" && \
{ printf "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc; } || true
RUN go build -o deploymentagent && \
rm -f /root/.ssh/id_rsa
FROM alpine:3.12

View File

@ -5,17 +5,9 @@ import (
"net/http"
)
var (
inputQueue *DeploymentQueue // queued
processQueue *DeploymentQueue // deploying, failed, deployed
)
func main() {
server := newDeploymentAgentServer()
inputQueue = new(DeploymentQueue)
processQueue = new(DeploymentQueue)
go processDeploymentSpecs(&podmanClient{}, &http.Client{Transport: socketHttpTransport}, "http://podman/v1.0.0/libpod")
if err := http.ListenAndServe(":5000", server); err != nil {

View File

@ -3,7 +3,9 @@ package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"sort"
"time"
@ -16,15 +18,23 @@ const (
)
var (
basicAuthUsername string
basicAuthPassword string
deploymentStateFile string
basicAuthUsername string
basicAuthPassword string
deploymentStateFile string
nixosRebuildSocketUrl string
inputQueue *DeploymentQueue // queued
processQueue *DeploymentQueue // deploying, failed, deployed
)
func init() {
basicAuthUsername = settings.GetSetting("BASIC_AUTH_USERNAME", "default")
basicAuthPassword = settings.GetSetting("BASIC_AUTH_PASSWORD", "default")
deploymentStateFile = settings.GetSetting("DEPLOYMENT_STATE_FILE", "./guidelines.json")
nixosRebuildSocketUrl = settings.GetSetting("NIXOS_REBUILD_SOCKET_URL", "localhost:4444")
inputQueue = new(DeploymentQueue)
processQueue = new(DeploymentQueue)
}
type DeploymentAgentServer struct {
@ -181,19 +191,28 @@ func processDeploymentSpecs(pc *podmanClient, hc *http.Client, url string) {
for {
time.Sleep(5 * time.Second)
if len(inputQueue.GetAll()) > 0 {
var err error
dequequedDeploymentSpec := inputQueue.Dequeue()
processQueue.Enqueue(dequequedDeploymentSpec.Id, "deploying", "Deployment in progress", dequequedDeploymentSpec.DeploymentSpec)
err := pc.pullImages(dequequedDeploymentSpec.DeploymentSpec, hc, url)
err = pc.pullImages(dequequedDeploymentSpec.DeploymentSpec, hc, url)
if err != nil {
processQueue.updateStatus(dequequedDeploymentSpec.Id, "failed", err.Error(), nil)
processQueue.updateStatus(dequequedDeploymentSpec.Id, "failed", ("When pulling images with Podman: " + err.Error()), getDeploymentState())
} else {
err := mergeDeploymentState(dequequedDeploymentSpec.DeploymentSpec)
if err != nil {
processQueue.updateStatus(dequequedDeploymentSpec.Id, "failed", err.Error(), getDeploymentState())
processQueue.updateStatus(dequequedDeploymentSpec.Id, "failed", ("When updating the deploymentstate file" + err.Error()), getDeploymentState())
} else {
processQueue.updateStatus(dequequedDeploymentSpec.Id, "deployed", "Deployment successful", getDeploymentState())
err = triggerNixosRebuild()
if err != nil {
processQueue.updateStatus(dequequedDeploymentSpec.Id, "failed", ("When triggering nixos-rebuild with Systemd: " + err.Error()), getDeploymentState())
} else {
processQueue.updateStatus(dequequedDeploymentSpec.Id, "deployed", "Deployment successful", getDeploymentState())
}
}
}
fmt.Println(processQueue.GetAll())
}
}
@ -230,3 +249,27 @@ func mergeDeploymentState(deploymentSpec DeploymentSpec) error {
return nil
}
// triggerNixosRebuild connects to the activation socket of a
// systemd unit which will trigger the nixos-rebuild unit.
// The connection will be kept open and closed as soon as the
// build has been completed, however, there is no way of
// knowing whether there has been an error in the build phase
// and thus the switch has not been applied.
func triggerNixosRebuild() error {
data := make([]byte, 1)
c, err := net.Dial("tcp", nixosRebuildSocketUrl)
if err != nil {
return err
}
if _, err := c.Read(data); err == io.EOF {
fmt.Println("nixos-rebuild switch has finished")
c.Close()
} else {
c.Close()
return err
}
return nil
}

View File

@ -23,9 +23,29 @@
# `systemctl start nixos-rebuild` := `nixos-rebuild switch`
systemd.services.nixos-rebuild = {
serviceConfig.Type = "oneshot";
postStart = "systemctl stop socket-nixos-rebuild-trigger.service && systemctl restart socket-nixos-rebuild-trigger.socket";
script = ''
/run/current-system/sw/bin/nixos-rebuild switch -I nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs -I nixos-config=/etc/nixos/configuration.nix
/run/current-system/sw/bin/nixos-rebuild switch -I nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs -I nixos-config=/etc/nixos/configuration.nix
'';
};
systemd.services.socket-nixos-rebuild-trigger = {
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
};
after = [ "socket-nixos-rebuild-trigger.socket" ];
requires = [ "socket-nixos-rebuild-trigger.socket" ];
script = ''
systemctl start nixos-rebuild
'';
};
systemd.sockets.socket-nixos-rebuild-trigger = {
listenStreams = [ "0.0.0.0:4444" ];
partOf = [ "socket-nixos-rebuild-trigger.service" ];
wantedBy = [ "sockets.target" ];
};
users.extraUsers.operator = {