Remove woodpecker (with CI coming to Gitea itself)
This commit is contained in:
parent
a427f185e7
commit
fccd7f9e5e
|
@ -29,7 +29,6 @@ this includes the setup for this server, which is being constructed using:
|
|||
In future, the following may be set up too:
|
||||
+ Dendrite/Conduit (Matrix servers)
|
||||
+ My TMiO blog
|
||||
+ Woodpecker (continuous integration that works with Gitea)
|
||||
+ Kopia (backups)
|
||||
+ Koel (music streaming)
|
||||
"
|
||||
|
@ -39,10 +38,5 @@ In future, the following may be set up too:
|
|||
virtualHosts."git.tecosaur.net".extraConfig =
|
||||
"reverse_proxy localhost:${toString config.services.gitea.httpPort}";
|
||||
})
|
||||
(mkIf (builtins.hasAttr "woodpecker-server" config.services &&
|
||||
config.services.woodpecker-server.enable) {
|
||||
virtualHosts."ci.tecosaur.net".extraConfig =
|
||||
"reverse_proxy localhost:${toString config.services.woodpecker-server.httpPort}";
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./woodpecker-server.nix
|
||||
./woodpecker-agent.nix
|
||||
];
|
||||
|
||||
age.secrets.woodpecker-client-id = {
|
||||
owner = "woodpecker-server";
|
||||
group = "users";
|
||||
file = ../../secrets/woodpecker-client-id.age;
|
||||
};
|
||||
|
||||
age.secrets.woodpecker-client-secret = {
|
||||
owner = "woodpecker-server";
|
||||
group = "users";
|
||||
file = ../../secrets/woodpecker-client-secret.age;
|
||||
};
|
||||
|
||||
age.secrets.woodpecker-agent-secret = {
|
||||
owner = "woodpecker-server";
|
||||
group = "users";
|
||||
mode = "0440";
|
||||
file = ../../secrets/woodpecker-agent-secret.age;
|
||||
};
|
||||
|
||||
services.woodpecker-server = {
|
||||
enable = true;
|
||||
rootUrl = "https://ci.tecosaur.net";
|
||||
httpPort = 3030;
|
||||
admins = "tec";
|
||||
database = {
|
||||
type = "postgres";
|
||||
};
|
||||
giteaClientIdFile = config.age.secrets.woodpecker-client-id.path;
|
||||
giteaClientSecretFile = config.age.secrets.woodpecker-client-secret.path;
|
||||
agentSecretFile = config.age.secrets.woodpecker-agent-secret.path;
|
||||
};
|
||||
|
||||
services.woodpecker-agent = {
|
||||
enable = false;
|
||||
};
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let cfg = config.services.woodpecker-agent;
|
||||
servercfg = config.services.woodpecker-server;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.woodpecker-agent = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = lib.mdDoc "Enable Woodpecker agent.";
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
default = pkgs.woodpecker-agent;
|
||||
type = types.package;
|
||||
defaultText = literalExpression "pkgs.woodpecker-agent";
|
||||
description = lib.mdDoc "woodpecker-agent derivation to use";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "woodpecker-agent";
|
||||
description = lib.mdDoc "User account under which woodpecker agent runs.";
|
||||
};
|
||||
|
||||
agentSecretFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = servercfg.agentSecretFile;
|
||||
description = lib.mdDoc "Read the agent secret from this file path.";
|
||||
};
|
||||
|
||||
maxProcesses = mkOption {
|
||||
type = types.int;
|
||||
default = 1;
|
||||
description = lib.mdDoc "The maximum number of processes per agent.";
|
||||
};
|
||||
|
||||
backend = mkOption {
|
||||
type = types.enum [ "auto-detect" "docker" "local" "ssh" ];
|
||||
default = "auto-detect";
|
||||
description = lib.mdDoc "Configures the backend engine to run pipelines on.";
|
||||
};
|
||||
|
||||
server = mkOption {
|
||||
type = types.str;
|
||||
default = "localhost:${if servercfg.enable then toString servercfg.gRPCPort else "9000"}";
|
||||
description = lib.mdDoc "The gPRC address of the server.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.woodpecker-agent = {
|
||||
description = "woodpecker-agent";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = "woodpecker-agent";
|
||||
ExecStart = "${cfg.package}/bin/woodpecker-agent";
|
||||
Restart = "always";
|
||||
# TODO add security/sandbox params.
|
||||
};
|
||||
environment = mkMerge [
|
||||
{
|
||||
WOODPECKER_SERVER=cfg.server;
|
||||
WOODPECKER_MAX_PROCS=toString cfg.maxProcesses;
|
||||
WOODPECKER_BACKEND=cfg.backend;
|
||||
}
|
||||
(mkIf (cfg.agentSecretFile != null) {
|
||||
WOODPECKER_AGENT_SECRET_FILE=cfg.agentSecretFile;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
users.users = mkIf (cfg.user == "woodpecker-agent") {
|
||||
woodpecker-agent = {
|
||||
# createHome = true;
|
||||
# home = cfg.stateDir;
|
||||
useDefaultShell = true;
|
||||
group = "woodpecker-agent";
|
||||
extraGroups = [ "woodpecker" ];
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
users.groups.woodpecker-agent = { };
|
||||
};
|
||||
}
|
|
@ -1,268 +0,0 @@
|
|||
{ config, lib, options, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.woodpecker-server;
|
||||
useMysql = cfg.database.type == "mysql";
|
||||
usePostgresql = cfg.database.type == "postgres";
|
||||
useSqlite = cfg.database.type == "sqlite3";
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.woodpecker-server = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = lib.mdDoc "Enable Woodpecker Server.";
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
default = pkgs.woodpecker-server;
|
||||
type = types.package;
|
||||
defaultText = literalExpression "pkgs.woodpecker-server";
|
||||
description = lib.mdDoc "woodpecker-server derivation to use";
|
||||
};
|
||||
|
||||
stateDir = mkOption {
|
||||
default = "/var/lib/woodpecker-server";
|
||||
type = types.str;
|
||||
description = lib.mdDoc "woodpecker server data directory.";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "woodpecker-server";
|
||||
description = lib.mdDoc "User account under which woodpecker server runs.";
|
||||
};
|
||||
|
||||
rootUrl = mkOption {
|
||||
default = "http://localhost:3030";
|
||||
type = types.str;
|
||||
description = lib.mkDoc "Full public URL of Woodpecker server";
|
||||
};
|
||||
|
||||
httpPort = mkOption {
|
||||
type = types.port;
|
||||
default = 3030;
|
||||
description = lib.mdDoc "HTTP listen port.";
|
||||
};
|
||||
|
||||
gRPCPort = mkOption {
|
||||
type = types.port;
|
||||
default = 9000;
|
||||
description = lib.mdDoc "The gPRC listener port.";
|
||||
};
|
||||
|
||||
admins = mkOption {
|
||||
default = "";
|
||||
type = types.str;
|
||||
description = lib.mdDoc "Woodpecker admin users.";
|
||||
};
|
||||
|
||||
agentSecretFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = lib.mdDoc "Read the agent secret from this file path.";
|
||||
};
|
||||
|
||||
database = {
|
||||
type = mkOption {
|
||||
type = types.enum [ "sqlite3" "mysql" "postgres" ];
|
||||
example = "mysql";
|
||||
default = "sqlite3";
|
||||
description = lib.mdDoc "Database engine to use.";
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = lib.mdDoc "Database host address.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = (if !usePostgresql then 3306 else config.services.postgresql.port);
|
||||
defaultText = literalExpression ''
|
||||
if config.${opt.database.type} != "postgresql"
|
||||
then 3306
|
||||
else config.${options.services.postgresql.port}
|
||||
'';
|
||||
description = lib.mdDoc "Database host port.";
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
default = "woodpecker_server";
|
||||
description = lib.mdDoc "Database name.";
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = lib.mdDoc ''
|
||||
The password corresponding to {option}`database.user`.
|
||||
Warning: this is stored in cleartext in the Nix store!
|
||||
Use {option}`database.passwordFile` instead.
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "woodpecker-server";
|
||||
description = lib.mdDoc "Database user.";
|
||||
};
|
||||
|
||||
socket = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = if (cfg.database.createDatabase && usePostgresql) then "/run/postgresql" else if (cfg.database.createDatabase && useMysql) then "/run/mysqld/mysqld.sock" else null;
|
||||
defaultText = literalExpression "null";
|
||||
example = "/run/mysqld/mysqld.sock";
|
||||
description = lib.mdDoc "Path to the unix socket file to use for authentication.";
|
||||
};
|
||||
|
||||
createDatabase = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc "Whether to create a local database automatically.";
|
||||
};
|
||||
};
|
||||
|
||||
limitMem = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = lib.mdDoc "The maximum amount of memory a single pipeline container can use, configured in bytes. There is no limit if 0.";
|
||||
};
|
||||
|
||||
limitSwap = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = lib.mdDoc "The maximum amount of memory a single pipeline container is allowed to swap to disk, configured in bytes. There is no limit if 0.";
|
||||
};
|
||||
|
||||
limitCPU = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = lib.mdDoc "The number of microseconds per CPU period that the container is limited to before throttled. There is no limit if 0.";
|
||||
};
|
||||
|
||||
useGitea = mkOption {
|
||||
default = config.services.gitea.enable;
|
||||
type = types.bool;
|
||||
description = lib.mkDoc "Whether to integrate with gitea.";
|
||||
};
|
||||
|
||||
giteaUrl = mkOption {
|
||||
default = config.services.gitea.rootUrl;
|
||||
type = types.str;
|
||||
description = lib.mkDoc "Full public URL of gitea server.";
|
||||
};
|
||||
|
||||
giteaClientIdFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
};
|
||||
|
||||
giteaClientSecretFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{ assertion = cfg.database.createDatabase -> cfg.database.user == cfg.user;
|
||||
message = "services.woodpecker-server.database.user must match services.woodpecker-server.user if the database is to be automatically provisioned";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.services.woodpecker-server = {
|
||||
description = "woodpecker-server";
|
||||
after = [ "network.target" ] ++ lib.optional usePostgresql "postgresql.service" ++ lib.optional useMysql "mysql.service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = mkMerge [
|
||||
{
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = "woodpecker-server";
|
||||
WorkingDirectory = cfg.stateDir;
|
||||
Restart = "always";
|
||||
# TODO add security/sandbox params.
|
||||
}
|
||||
(if cfg.useGitea then {
|
||||
# HACK For some godforsaken reason this seems to be needed.
|
||||
ExecStart="/bin/sh -c '" +
|
||||
"WOODPECKER_GITEA_CLIENT=$(cat \"${cfg.giteaClientIdFile}\") " +
|
||||
"WOODPECKER_GITEA_SECRET=$(cat \"${cfg.giteaClientSecretFile}\") " +
|
||||
"\"${cfg.package}/bin/woodpecker-server\"'";
|
||||
} else {
|
||||
ExecStart = "${cfg.package}/bin/woodpecker-server";
|
||||
})
|
||||
];
|
||||
environment = mkMerge [
|
||||
{
|
||||
WOODPECKER_OPEN="false";
|
||||
WOODPECKER_ADMIN=cfg.admins;
|
||||
WOODPECKER_HOST=cfg.rootUrl;
|
||||
WOODPECKER_SERVER_ADDR=":${toString cfg.httpPort}";
|
||||
WOODPECKER_GRPC_ADDR=":${toString cfg.gRPCPort}";
|
||||
WOODPECKER_LIMIT_MEM_SWAP=toString cfg.limitSwap;
|
||||
WOODPECKER_LIMIT_MEM=toString cfg.limitMem;
|
||||
WOODPECKER_LIMIT_CPU_QUOTA=toString cfg.limitCPU;
|
||||
}
|
||||
(mkIf cfg.useGitea {
|
||||
WOODPECKER_GITEA="true";
|
||||
WOODPECKER_GITEA_URL=cfg.giteaUrl;
|
||||
# WOODPECKER_GITEA_CLIENT_FILE=cfg.giteaClientIdFile;
|
||||
# WOODPECKER_GITEA_SECRET_FILE=cfg.giteaClientSecretFile;
|
||||
})
|
||||
(mkIf usePostgresql {
|
||||
WOODPECKER_DATABASE_DRIVER="postgres";
|
||||
WOODPECKER_DATABASE_DATASOURCE=
|
||||
"postgres://${cfg.database.user}:${cfg.database.password}" +
|
||||
"@/${cfg.database.name}" +
|
||||
"?host=${if cfg.database.socket != null then cfg.database.socket else cfg.database.host + ":" + toString cfg.database.port}";
|
||||
})
|
||||
(mkIf (cfg.agentSecretFile != null) {
|
||||
WOODPECKER_AGENT_SECRET_FILE=cfg.agentSecretFile;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
services.postgresql = optionalAttrs (usePostgresql && cfg.database.createDatabase) {
|
||||
enable = mkDefault true;
|
||||
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
ensureUsers = [
|
||||
{ name = cfg.database.user;
|
||||
ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.mysql = optionalAttrs (useMysql && cfg.database.createDatabase) {
|
||||
enable = mkDefault true;
|
||||
package = mkDefault pkgs.mariadb;
|
||||
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
ensureUsers = [
|
||||
{ name = cfg.database.user;
|
||||
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
users.users = mkIf (cfg.user == "woodpecker-server") {
|
||||
woodpecker-server = {
|
||||
createHome = true;
|
||||
home = cfg.stateDir;
|
||||
useDefaultShell = true;
|
||||
group = "woodpecker-server";
|
||||
extraGroups = [ "woodpecker" ];
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
users.groups.woodpecker-server = { };
|
||||
};
|
||||
}
|
|
@ -6,7 +6,4 @@ in
|
|||
{
|
||||
"postgres-gitea.age".publicKeys = systems;
|
||||
"fastmail.age".publicKeys = systems;
|
||||
"woodpecker-client-id.age".publicKeys = systems;
|
||||
"woodpecker-client-secret.age".publicKeys = systems;
|
||||
"woodpecker-agent-secret.age".publicKeys = systems;
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -1,9 +0,0 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 eobz4w v1Bc0BdCfgiN7dTmuHgYd8haeEer2r+YT15yMZKjb0g
|
||||
9RgF4DClwpKmyTwzJVsDYYHinnqWE6HvnqTw5vqu9Po
|
||||
-> ssh-ed25519 kfYPBA Y+ObzE8+k6YU+jwJvVfjjqQ6B7L6GkNOo5uWPWZkuiI
|
||||
krMwU5xP3vxgAQeTkJS7Fls0DPJRMGaoykb2phS+39A
|
||||
-> &c-grease WABF'z !%]UQi WqPSzW #slup3
|
||||
RrOi8Q
|
||||
--- ay1ApsHJc6hlQ1p0oWR3Rf1W1YR3XAyfg5mPINrJDvM
|
||||
óixþQïDêa®º»-¡î¶˜”3‡#Ña
‚Ÿ4UKšDÐkê*,½þ»Z*wÚÎIçö.e>•~÷qZºÏ
|
|
@ -1,10 +0,0 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 eobz4w CycaujAgrBsG5P6i5196hreJtnOxReq6k1GlJRhiqxA
|
||||
rRuPITF5VTkzets/bCRqVF7o462dvjJdohNX+0iN+2A
|
||||
-> ssh-ed25519 kfYPBA ttSZFpctapkEbRmrw8VNkr+cTd0XkRx4Vlqv6obxKBw
|
||||
uZojzuzLiTzZd0SjlyCDYDPNeBGTQE8SrrQxSYFogtY
|
||||
-> !s*M_-grease B@C0U:D *)+1 m
|
||||
xj2sW2uN/ZVeM0oH73SOilLHvn83CXyjYVxgTWnWglpS+WN/Tq7NvCuilXu0ZJiS
|
||||
zUZxFCqe
|
||||
--- IPpz1GE6p+itJUERyejUAgyga/vOOOhTFnrNUJe/8qs
|
||||
Û¼^b2ÎNšÕ…Ôæ(a™B7‰¼u‹ÕdÆ
»ùä€3ôKÐÜÖeFÅgál }±…Þ ]·A–rñ`:‹âß,´´öíM•8À—ð…F¼ŸRdˆ¹…ëÿ
|
Loading…
Reference in New Issue