forked from fediversity/fediversity
switch to bash deployment
This commit is contained in:
parent
319a6c391c
commit
ad7a832998
13 changed files with 83 additions and 289 deletions
4
launch/.gitignore
vendored
4
launch/.gitignore
vendored
|
|
@ -1,4 +0,0 @@
|
|||
.auto.tfvars.json
|
||||
.terraform/
|
||||
.terraform.tfstate.lock.info
|
||||
terraform.tfstate*
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# service deployment
|
||||
|
||||
## usage
|
||||
|
||||
### updating TF modules
|
||||
|
||||
```sh
|
||||
$ npins update nixos-anywhere
|
||||
$ cd launch/
|
||||
$ echo "{\"nixos-anywhere\": $(nix-instantiate --eval --json -E '(import ../npins).nixos-anywhere.outPath')}" > .auto.tfvars.json
|
||||
```
|
||||
|
||||
### local development
|
||||
|
||||
```sh
|
||||
$ nix-shell
|
||||
$ rm -rf .terraform/
|
||||
$ tofu init
|
||||
```
|
||||
|
|
@ -9,15 +9,11 @@
|
|||
inherit system;
|
||||
},
|
||||
}:
|
||||
let
|
||||
inherit (pkgs) lib;
|
||||
in
|
||||
{
|
||||
shell = pkgs.mkShellNoCC {
|
||||
packages = [
|
||||
pkgs.npins
|
||||
pkgs.jq # implicit dep of nixos-anywhere TF: https://github.com/nix-community/nixos-anywhere/issues/416
|
||||
(import ./tf.nix { inherit lib pkgs; })
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
16
launch/deploy.sh
Executable file
16
launch/deploy.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -uex -o pipefail
|
||||
declare domain hostname config initialUser
|
||||
eval "$(jq -r '@sh "domain=\(.domain) hostname=\(.hostname) config=\(.config) initialUser=\(.initialUser)"')"
|
||||
TARGET_HOST="${hostname}.abundos.eu"
|
||||
TARGET="root@${TARGET_HOST}"
|
||||
wrapper="$(mktemp -d)/wrapper.nix"
|
||||
echo "(import $(readlink -f "./${config}.nix")).extendModules { specialArgs.terraform = { domain = \"${domain}\"; hostname = \"${hostname}\"; initialUser = builtins.fromJSON ''${initialUser}''; }; }" > "$wrapper"
|
||||
NIXOS_SYSTEM=$(nix build --no-link --json --option show-trace true --file "$wrapper" "config.system.build.toplevel" | jq -r '.[].outputs.out')
|
||||
sshOpts=(-p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no)
|
||||
NIX_SSHOPTS="${sshOpts[*]}" nix copy -s --experimental-features nix-command --to "ssh://$TARGET" "$NIXOS_SYSTEM"
|
||||
switchCommand="nix-env -p /nix/var/nix/profiles/system --set $(printf "%q" "$NIXOS_SYSTEM"); /nix/var/nix/profiles/system/bin/switch-to-configuration switch"
|
||||
deploy_status=0
|
||||
# shellcheck disable=SC2029
|
||||
ssh "${sshOpts[@]}" "$TARGET" "$switchCommand" || deploy_status="$?"
|
||||
exit "$deploy_status"
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
variable "nixos-anywhere" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "domain" {
|
||||
type = string
|
||||
default = "fediversity.net"
|
||||
}
|
||||
|
||||
variable "mastodon" {
|
||||
type = object({
|
||||
enable = bool
|
||||
})
|
||||
default = {
|
||||
enable = false
|
||||
}
|
||||
}
|
||||
|
||||
variable "pixelfed" {
|
||||
type = object({
|
||||
enable = bool
|
||||
})
|
||||
default = {
|
||||
enable = false
|
||||
}
|
||||
}
|
||||
|
||||
variable "peertube" {
|
||||
type = object({
|
||||
enable = bool
|
||||
})
|
||||
default = {
|
||||
enable = false
|
||||
}
|
||||
}
|
||||
|
||||
variable "initialUser" {
|
||||
type = object({
|
||||
displayName = string
|
||||
username = string
|
||||
email = string
|
||||
# TODO: mark (nested) credentials as sensitive
|
||||
# https://discuss.hashicorp.com/t/is-it-possible-to-mark-an-attribute-of-an-object-as-sensitive/24649/2
|
||||
password = string
|
||||
})
|
||||
default = {
|
||||
displayName = "Testy McTestface"
|
||||
username = "test"
|
||||
email = "test@test.com"
|
||||
password = "testtest"
|
||||
}
|
||||
}
|
||||
|
||||
# module "garage" {
|
||||
# source = "./vm"
|
||||
# count = var.mastodon.enable || var.pixelfed.enable || var.peertube.enable ? 1 : 0
|
||||
# domain = var.domain
|
||||
# hostname = "test01"
|
||||
# config = "garage"
|
||||
# initialUser = var.initialUser
|
||||
# nixos-anywhere = var.nixos-anywhere
|
||||
# }
|
||||
|
||||
module "mastodon" {
|
||||
source = "./vm"
|
||||
count = var.mastodon.enable ? 1 : 0
|
||||
domain = var.domain
|
||||
hostname = "test02"
|
||||
config = "mastodon"
|
||||
initialUser = var.initialUser
|
||||
nixos-anywhere = var.nixos-anywhere
|
||||
}
|
||||
|
||||
module "pixelfed" {
|
||||
source = "./vm"
|
||||
count = var.pixelfed.enable ? 1 : 0
|
||||
domain = var.domain
|
||||
hostname = "test04"
|
||||
config = "pixelfed"
|
||||
initialUser = var.initialUser
|
||||
nixos-anywhere = var.nixos-anywhere
|
||||
}
|
||||
|
||||
module "peertube" {
|
||||
source = "./vm"
|
||||
count = var.peertube.enable ? 1 : 0
|
||||
domain = var.domain
|
||||
hostname = "test03"
|
||||
config = "peertube"
|
||||
initialUser = var.initialUser
|
||||
nixos-anywhere = var.nixos-anywhere
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
export host="$host"
|
||||
|
||||
mkdir -p etc/ssh
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
for keyname in ssh_host_ed25519_key ssh_host_ed25519_key.pub; do
|
||||
if [[ $keyname == *.pub ]]; then
|
||||
umask 0133
|
||||
else
|
||||
umask 0177
|
||||
fi
|
||||
cp "$SCRIPT_DIR/../infra/test-machines/${host}/${keyname}" ./etc/ssh/${keyname}
|
||||
done
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
sources ? import ../npins,
|
||||
...
|
||||
}:
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "tf-repo";
|
||||
src = ../.;
|
||||
buildInputs = [
|
||||
(import ./tf.nix { inherit lib pkgs; })
|
||||
];
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
pushd launch/
|
||||
|
||||
# pass nixos-anywhere path to TF through variable
|
||||
# when switching TF to nix take this directly from `inputs`
|
||||
# https://codeberg.org/kiara/e2ed-hetzner/commit/84b2a349d3e48ea2a17340bceff762d834fd4046
|
||||
echo "{\"nixos-anywhere\": \"${sources.nixos-anywhere}\"}" > .auto.tfvars.json
|
||||
|
||||
# point to the relevant providers
|
||||
tofu init -input=false
|
||||
|
||||
popd
|
||||
runHook postBuild
|
||||
'';
|
||||
# FIXME: can the above even work without a connection?
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
cp -r . $out
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# FIXME: use overlays so this gets imported just once?
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
tofuProvider =
|
||||
provider:
|
||||
provider.override (oldArgs: {
|
||||
provider-source-address =
|
||||
lib.replaceStrings [ "https://registry.terraform.io/providers" ] [ "registry.opentofu.org" ]
|
||||
oldArgs.homepage;
|
||||
});
|
||||
tf = pkgs.opentofu;
|
||||
tfPlugins = (
|
||||
p: [
|
||||
p.null
|
||||
p.external
|
||||
]
|
||||
);
|
||||
in
|
||||
# tf.withPlugins tfPlugins
|
||||
# https://github.com/NixOS/nixpkgs/pull/358522
|
||||
tf.withPlugins (p: pkgs.lib.lists.map tofuProvider (tfPlugins p))
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
variable "nixos-anywhere" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "domain" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "hostname" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "config" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "initialUser" {
|
||||
type = object({
|
||||
displayName = string
|
||||
username = string
|
||||
password = string
|
||||
email = string
|
||||
})
|
||||
}
|
||||
|
||||
module "deploy" {
|
||||
# source = "github.com/nix-community/nixos-anywhere//terraform/all-in-one"
|
||||
source = "${var.nixos-anywhere}//terraform/all-in-one"
|
||||
file = "${path.module}/../${var.config}.nix"
|
||||
nixos_system_attr = "config.system.build.toplevel"
|
||||
nixos_partitioner_attr = "config.system.build.diskoScript"
|
||||
# when instance id changes, it will trigger a reinstall
|
||||
instance_id = var.hostname
|
||||
target_user = "root"
|
||||
target_host = "${var.hostname}.abundos.eu"
|
||||
extra_files_script = "${path.module}/../pass-ssh-key.sh"
|
||||
extra_environment = {
|
||||
host = var.hostname
|
||||
}
|
||||
special_args = {
|
||||
terraform = {
|
||||
domain = var.domain
|
||||
hostname = var.hostname
|
||||
initialUser = var.initialUser
|
||||
}
|
||||
}
|
||||
nix_options = {
|
||||
show-trace = true
|
||||
}
|
||||
# build_on_remote = true
|
||||
}
|
||||
|
|
@ -11,6 +11,5 @@
|
|||
pkgs.openssh
|
||||
pkgs.git
|
||||
pkgs.jq # implicit dep of nixos-anywhere TF: https://github.com/nix-community/nixos-anywhere/issues/416
|
||||
(import ../launch/tf.nix { inherit lib pkgs; })
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ let
|
|||
((pkgs.formats.pythonVars { }).generate "settings.py" cfg.settings)
|
||||
(builtins.toFile "extra-settings.py" cfg.extra-settings)
|
||||
];
|
||||
REPO_DIR = import ../../launch/tf-env.nix { inherit lib pkgs; };
|
||||
REPO_DIR = ./..;
|
||||
};
|
||||
|
||||
python-environment = pkgs.python3.withPackages (
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ python3.pkgs.buildPythonPackage {
|
|||
cp -v ${src}/manage.py $out/bin/manage.py
|
||||
chmod +x $out/bin/manage.py
|
||||
wrapProgram $out/bin/manage.py \
|
||||
--set REPO_DIR "${import ../../launch/tf-env.nix { inherit lib pkgs; }}" \
|
||||
--set REPO_DIR "${./..}" \
|
||||
--prefix PYTHONPATH : "$PYTHONPATH"
|
||||
cp ${sources.htmx}/dist/htmx.min.js* $out/${python3.sitePackages}/panel/static/
|
||||
'';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from enum import Enum
|
||||
import json
|
||||
from os.path import expanduser
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
|
|
@ -14,6 +14,8 @@ from django.shortcuts import render
|
|||
from panel import models, settings
|
||||
from panel.configuration import forms
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Index(TemplateView):
|
||||
template_name = 'index.html'
|
||||
|
|
@ -103,54 +105,77 @@ class DeploymentStatus(ConfigurationForm):
|
|||
# Check for deploy button
|
||||
if "deploy" in self.request.POST.keys():
|
||||
deployment_result, deployment_params = self.deployment(obj)
|
||||
if deployment_result.returncode == 0:
|
||||
deployment_status = "Deployment Succeeded"
|
||||
else:
|
||||
deployment_status = "Deployment Failed"
|
||||
deployment_succeeded = deployment_result == 0
|
||||
|
||||
return render(self.request, "partials/deployment_result.html", {
|
||||
"deployment_status": deployment_status,
|
||||
"deployment_succeeded": deployment_succeeded,
|
||||
"services": {
|
||||
"peertube": deployment_params['peertube']['enable'],
|
||||
"pixelfed": deployment_params['pixelfed']['enable'],
|
||||
"mastodon": deployment_params['mastodon']['enable']
|
||||
}
|
||||
})
|
||||
"peertube": {
|
||||
"enable": deployment_params['peertube']['enable'],
|
||||
"url": f"https://peertube.{deployment_params['domain']}",
|
||||
},
|
||||
"pixelfed":{
|
||||
"enable": deployment_params['pixelfed']['enable'],
|
||||
"url": f"https://pixelfed.{deployment_params['domain']}",
|
||||
},
|
||||
"mastodon": {
|
||||
"enable": deployment_params['mastodon']['enable'],
|
||||
"url": f"https://mastodon.{deployment_params['domain']}",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
def deployment(self, obj):
|
||||
submission = obj.parsed_value.model_dump_json()
|
||||
testvms = {
|
||||
"mastodon": "test06",
|
||||
"pixelfed": "test04",
|
||||
"peertube": "test03",
|
||||
}
|
||||
submission = json.loads(obj.parsed_value.model_dump_json())
|
||||
logger.debug(f"submission: {submission}")
|
||||
# FIXME: let the user specify these from the form (#190)
|
||||
dummy_user = {
|
||||
"initialUser": {
|
||||
"initialUser": json.dumps({
|
||||
"displayName": "Testy McTestface",
|
||||
"username": "test",
|
||||
"password": "testtest",
|
||||
"email": "test@test.com",
|
||||
},
|
||||
}),
|
||||
}
|
||||
# serialize back and forth now we still need to manually inject the dummy user
|
||||
deployment_params = dummy_user | json.loads(submission)
|
||||
env = {
|
||||
"PATH": settings.bin_path,
|
||||
# used in nixos-anywhere for ssh-copy-id to make `.ssh` in for ssh-copy-id.
|
||||
# run thru subprocess, HOME points to the read-only `/var/empty`.
|
||||
# in local dev, it will just reject the `/tmp` and make it in HOME after all.
|
||||
"HOME": "/tmp",
|
||||
"XDG_CACHE_HOME": "/tmp",
|
||||
} | {
|
||||
# pass in form info to our deployment
|
||||
# FIXME: ensure sensitive info is protected
|
||||
f"TF_VAR_{k}": v if isinstance(v, str) else json.dumps(v) for k, v in deployment_params.items()
|
||||
}
|
||||
cwd = f"{settings.repo_dir}/launch"
|
||||
cmd = [
|
||||
"tofu",
|
||||
# f"-chdir={cwd}",
|
||||
"apply",
|
||||
f"-state={cwd}/terraform.tfstate", # FIXME: separate users' state
|
||||
"--auto-approve",
|
||||
"-lock=false",
|
||||
]
|
||||
deployment_result = subprocess.run(cmd, cwd=cwd, env=env)
|
||||
print(deployment_result)
|
||||
return deployment_result, deployment_params
|
||||
deployment_result = 0
|
||||
if submission["enable"]:
|
||||
for service in [
|
||||
"mastodon",
|
||||
"pixelfed",
|
||||
"peertube",
|
||||
]:
|
||||
if submission[service]["enable"]:
|
||||
hostname = testvms[service]
|
||||
# serialize back and forth now we still need to manually inject the dummy user
|
||||
deployment_params = json.dumps({
|
||||
"config": service,
|
||||
"hostname": hostname,
|
||||
"initialUser": json.dumps({
|
||||
"displayName": "Testy McTestface",
|
||||
"username": "test",
|
||||
"password": "testtest",
|
||||
"email": "test@test.com",
|
||||
}),
|
||||
} | submission)
|
||||
logger.debug(f"deployment_params: {deployment_params}")
|
||||
deployment_result = deployment_result or subprocess.run(
|
||||
["./deploy.sh"],
|
||||
cwd=f"{settings.repo_dir}/launch",
|
||||
env={
|
||||
"PATH": settings.bin_path,
|
||||
},
|
||||
# pass in form info to our deployment
|
||||
input=deployment_params,
|
||||
text=True,
|
||||
).returncode
|
||||
else:
|
||||
logger.debug(f"service {service} disabled")
|
||||
else:
|
||||
# FIXME: implement disable
|
||||
logger.debug("deployment disabled")
|
||||
return deployment_result, json.loads(deployment_params)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue