Revert "Docker gitea changes"

This reverts commit 0d81433c2d.
This commit is contained in:
Magic_RB 2021-02-18 20:59:11 +01:00
parent 0d81433c2d
commit 594065f99b
28 changed files with 399 additions and 1127 deletions

View file

@ -1,6 +1,5 @@
{ pkgs, nixpkgs, ... }@inputs:
let
ldflags = "-s -w -extldflags '-static'";
csi-driver-nfs = pkgs.buildGoModule {
name = "csi-driver-nfs";
version = "2.0";
@ -11,8 +10,10 @@ let
src = inputs.csi-driver-nfs;
};
init = pkgs.writeShellScriptBin "init" ''
${csi-driver-nfs}/bin/nfsplugin $@
init = with pkgs; pkgs.writeShellScriptBin "init" ''
export "PATH=${busybox}/bin:$PATH"
echo $PATH
exec ${csi-driver-nfs}/bin/nfsplugin $@
'';
in
pkgs.dockerTools.buildLayeredImage {

View file

@ -1,7 +0,0 @@
{ pkgs, lib, config, ... }:
{
security.oauth2JwtSecret = "STUFF";
security.internalToken = "STUFF";
security.secretKey = "STUFF";
lfs.lfsJwtSecret = "STUFF";
}

View file

@ -1,4 +0,0 @@
gid = 5000
uid = 5000
app_ini = "/app.ini"
app_ini_overwrite = true

View file

@ -1,18 +1,8 @@
{ pkgs, system, nixpkgs, ... }:
let
# pkgs = (import nixpkgs { inherit system; }).pkgsMusl;
contents = let
defaults = {
userUid = builtins.toString 5001;
userGid = builtins.toString 5001;
user = "gitea";
data = "/data/gitea";
};
custom = rec {
gitea = pkgs.gitea.override {
inherit openssh git;
pamSupport = false;
};
gitea =
let
openssh = pkgs.openssh.override {
withKerberos = false; withFIDO = false;
};
@ -26,19 +16,29 @@ let
withpcre2 = false;
sendEmailSupport = false;
};
in
pkgs.gitea.override {
inherit openssh git;
pamSupport = false;
};
bashLib = ../bash-lib;
in
pkgs.symlinkJoin { name = "contents"; paths = [ custom.gitea ]; };
init = "${pkgs.rust-runner}/bin/gitea";
init = pkgs.writeShellScriptBin "init" (builtins.readFile ./init);
conf = pkgs.writeText "conf" ''
_prog_busybox="${pkgs.busybox}"
_prog_bashlib="${bashLib}"
_prog_bash="${pkgs.bash}"
_prog_gitea="${pkgs.gitea}"
_conf_user_uid="5000"
_conf_user_gid="5000"
_conf_data="/data/gitea"
'';
in
pkgs.dockerTools.buildLayeredImage {
name = "gitea";
tag = "latest";
inherit contents;
config = {
Entrypoint = [ "${init}" ];
Entrypoint = [ "${init}/bin/init" "${conf}" ];
};
}

View file

@ -6,8 +6,5 @@ services:
- "3000:3000"
volumes:
- type: bind
source: ./config.toml
target: /config.toml
- type: bind
source: ./config.toml
source: $PWD/app.ini
target: /app.ini

71
docker/gitea/init Normal file
View file

@ -0,0 +1,71 @@
# -*- mode: shell-script; -*-
if [[ ! -f /env ]]
then
conf=$1 ; shift 1
source $conf
else
source /env || \
echo_exit "Failed to source env!"
source $conf
fi
source $_prog_bashlib/main.bash
if [[ $($_prog_busybox/bin/id -u) = 0 ]] ; then
$_prog_busybox/bin/cat << EOF
### Gitea Nix Image Manual
##
## USER_UID ? $_conf_user_uid - default user id
## USER_GID ? $_conf_user_gid - default group id
### You must place a \`app.ini\` at \`/app.ini\`
### Volume Mounts
##
## - $_conf_data - Gitea base data folder
EOF
default_opt USER_UID "$_conf_user_uid"
default_opt USER_GID "$_conf_user_gid"
$_prog_busybox/bin/cat << EOF
### Starting with options:
## USER_UID = "$_user_uid"
## USER_GID = "$_user_gid"
EOF
(
set -e
echo "gitea:x:$_user_uid:$_user_gid:Gitea:$_conf_data:$_prog_bash/bin/bash" > /etc/passwd
echo "gitea:x:$_user_gid:" > /etc/group
) || echo_exit "Failed to create user and group!"
[[ ! -d $_conf_data ]] && mkdir_chown $_conf_data "$_user_uid" "$_user_gid"
mkdir_chown /tmp "$_user_uid" "$_user_gid"
$_prog_busybox/bin/mkdir -p /usr/bin
$_prog_busybox/bin/ln -s $_prog_busybox/bin/env /usr/bin/env
check_owner "$_conf_data" "$_user_uid" "$_user_gid"
save_env "_user_uid \
_user_gid \
conf
" > /env # TODO: exited even though it must have succeded || \
# echo_exit "Failed to save environment!"
check_root "$_user_uid"
exec $_prog_busybox/bin/su gitea -c "$0 $@" || \
echo_exit "Failed to switch user!"
else
source /env || \
echo_exit "Failed to source env!"
export GITEA_WORK_DIR=$_conf_data
echo
echo "Starting Gitea!"
$_prog_gitea/bin/gitea -c /app.ini $@
fi

View file

@ -1,337 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config;
useMysql = cfg.database.type == "mysql";
usePostgresql = cfg.database.type == "postgres";
useSqlite = cfg.database.type == "sqlite3";
format = pkgs.formats.ini { mkKeyValue = generators.mkKeyValueDefault {} "="; };
in
{
options = {
run = mkOption {
type = types.package;
description = "Run gitea derivation.";
};
stateDir = mkOption {
default = "/gitea";
type = types.str;
description = "gitea data directory.";
};
uid = mkOption {
default = 5000;
type = types.int;
description = "gitea user id.";
};
gid = mkOption {
default = 5000;
type = types.int;
description = "gitea group id.";
};
logLevel = mkOption {
default = "Info";
type = types.enum [ "Info" "Debug" "Error" ];
description = "Log level for gitea logging.";
};
security = {
secretKey = mkOption {
type = types.str;
description = "gitea secret key.";
};
internalToken = mkOption {
type = types.str;
description = "gitea internal token.";
};
installLock = mkOption {
type = types.bool;
description = "gitea install lock.";
default = false; # TODO figure out what this actually does
};
oauth2JwtSecret = mkOption {
type = types.str;
description = "OAuth2 JWT secret.";
};
};
database = {
type = mkOption {
type = types.enum [ "sqlite3" "mysql" "postgres" ];
example = "mysql";
default = "sqlite3";
description = "Database engine to use.";
};
path = mkOption {
type = types.str;
default = "/data/gitea/gitea.db";
description = "Database file path, if sqlite3 is in use";
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Database host address";
};
port = mkOption {
type = types.int;
default = (if !usePostgresql then 3306 else pg.port);
description = "Databa se host port.";
};
name = mkOption {
type = types.str;
default = "gitea";
description = "Database user.";
};
password = mkOption {
type = types.str;
default = "";
description = "Database password.";
};
createDatabase = mkOption {
type = types.bool;
default = true;
description = "Whether to create a database automatically.";
};
};
ssh = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable external SSH feature.";
};
clonePort = mkOption {
type = types.int;
default = 22;
example = 2222;
description = ''
SSH port displayed in clone URL.
The option is required to configure a service when the external visible port
differs from the local listening port i.e. if port forwarding is used.
'';
};
};
lfs = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable git-lfs support.";
};
contentDir = mkOption {
type = types.str;
default = "${cfg.stateDir}/lfs";
description = "Where to store LFS files.";
};
lfsJwtSecret = mkOption {
type = types.str;
description = "LFS JWT Secret";
};
};
appName = mkOption {
type = types.str;
default = "gitea: Gitea Service";
description = "Application name.";
};
runMode = mkOption {
type = types.enum [ "dev" "prod" "test" ];
description = "run mode.";
default = "prod";
};
repositoryRoot = mkOption {
type = types.str;
default = # "${cfg.stateDir}/repositories"
"";
description = "Path to the git repositories.";
};
domain = mkOption {
type = types.str;
default = "localhost";
description = "Domain name of your server.";
};
rootUrl = mkOption {
type = types.str;
default = "http://localhost:3000/";
description = "Full public URL of gitea server.";
};
httpAddress = mkOption {
type = types.str;
default = "0.0.0.0";
description = "HTTP listen address.";
};
httpPort = mkOption {
type = types.int;
default = 3000;
description = "HTTP listen port.";
};
cookieSecure = mkOption {
type = types.bool;
default = false;
description = ''
Marks session cookies as "secure" as a hint for browsers to only send
them via HTTPS. This option is recommend, if gitea is being served over HTTPS.
'';
};
staticRootPath = mkOption {
type = types.str;
default = "\${pkgs.gitea.data}";
example = "/var/lib/gitea/data";
description = "Upper level of template and static files path.";
};
disableRegistration = mkEnableOption "the registration lock" // {
description = ''
By default any user can create an account on this <literal>gitea</literal> instance.
This can be disabled by using this option.
<emphasis>Note:</emphasis> please keep in mind that this should be added after the initial
deploy unless <link linkend="opt-services.gitea.useWizard">services.gitea.useWizard</link>
is <literal>true</literal> as the first registered user will be the administrator if
no install wizard is used.
'';
};
settings = mkOption {
type = with types; attrsOf (attrsOf (oneOf [ bool int str ]));
default = {};
description = ''
Gitea configuration. Refer to <link xlink:href="https://docs.gitea.io/en-us/config-cheat-sheet/"/>
for details on supported values.
'';
example = literalExample ''
{
"cron.sync_external_users" = {
RUN_AT_START = true;
SCHEDULE = "@every 24h";
UPDATE_EXISTING = true;
};
mailer = {
ENABLED = true;
MAILER_TYPE = "sendmail";
FROM = "do-not-reply@example.org";
SENDMAIL_PATH = "''${pkgs.system-sendmail}/bin/sendmail";
};
other = {
SHOW_FOOTER_VERSION = false;
};
}
'';
};
};
config = {
settings = {
database = mkMerge [
{
DB_TYPE = cfg.database.type;
}
(mkIf (useMysql || usePostgresql) {
HOST = cfg.database.host + ":" + toString cfg.database.port;
NAME = cfg.database.name;
USER = cfg.database.user;
PASSWD = cfg.database.password;
})
(mkIf useSqlite {
PATH = cfg.database.path;
})
(mkIf usePostgresql {
SSL_MODE = "disable";
})
];
repository = {
ROOT = cfg.repositoryRoot;
};
server = mkMerge [
{
DOMAIN = cfg.domain;
# STATIC_ROOT_PATH = cfg.staticRootPath;
LFS_JWT_SECRET = cfg.lfs.lfsJwtSecret;
HTTP_ADDR = cfg.httpAddress;
HTTP_PORT = cfg.httpPort;
}
(mkIf cfg.ssh.enable {
DISABLE_SSH = false;
SSH_PORT = cfg.ssh.clonePort;
})
(mkIf (!cfg.ssh.enable) {
DISABLE_SSH = true;
})
(mkIf cfg.lfs.enable {
LFS_START_SERVER = true;
LFS_CONTENT_PATH = cfg.lfs.contentDir;
})
];
session = {
COOKIE_NAME = "session";
COOKIE_SECURE = cfg.cookieSecure;
};
security = with cfg.security; {
SECRET_KEY = secretKey;
INTERNAL_TOKEN = internalToken;
INSTALL_LOCK = installLock;
};
log = {
ROUTER = "console";
ROUTER_LOG_LEVEL = cfg.logLevel;
};
service = {
DISABLE_REGISTRATION = cfg.disableRegistration;
};
oauth2 = {
JWT_SECRET = cfg.security.oauth2JwtSecret;
};
};
run =
let
appIni = pkgs.writeText "app.ini" ''
APP_NAME=${cfg.appName}
RUN_USER=gitea
RUN_MODE=${cfg.runMode}
${generators.toINI {} cfg.settings}
'';
in pkgs.writeShellScriptBin "run" ''
export GITEA_WORK_FIR=${cfg.stateDir}
exec /bin/gitea -c ${appIni}
'';
};
}

View file

@ -1 +0,0 @@
/nix/store/6cg3m50cm7jz6k308vab9p8pqxz27pfn-gitea.sh

View file

@ -1,16 +0,0 @@
let
nixpkgs = import <nixpkgs> { system = "x86_64-linux"; };
eval = nixpkgs.lib.evalModules {
modules =
[ (import /module.nix) ] ++
(if (builtins.pathExists /config.nix) then [ (import /config.nix) ] else []);
args = {
pkgs = nixpkgs;
lib = nixpkgs.lib;
};
};
in
eval.config.run
# export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt

View file

@ -0,0 +1,26 @@
{ pkgs, system, nixpkgs, nixpkgs-unstable, ... }:
let
bashLib = ../bash-lib;
init = pkgs.writeShellScriptBin "init" (builtins.readFile ./init);
conf = pkgs.writeText "conf" ''
_prog_busybox="${pkgs.busybox}"
_prog_bashlib="${bashLib}"
_prog_bash="${pkgs.bash}"
_prog_mariadb="${(import nixpkgs-unstable { inherit system; }).mariadb}"
_prog_nettools="${pkgs.nettools}"
_conf_user_uid="5000"
_conf_user_gid="5000"
_conf_data="/data/mariadb"
_file_mariadb_conf=${./mariadb.cnf}
'';
in
pkgs.dockerTools.buildLayeredImage {
name = "mariadb";
tag = "latest";
config = {
Entrypoint = [ "${init}/bin/init" "${conf}" ];
};
}

68
docker/mariadb/init Normal file
View file

@ -0,0 +1,68 @@
# -*- mode: shell-script; -*-
if [[ ! -f /env ]]
then
conf=$1 ; shift 1
source $conf
else
source /env || \
echo_exit "Failed to source env!"
source $conf
fi
source $_prog_bashlib/main.bash
if [[ $($_prog_busybox/bin/id -u) = 0 ]] ; then
$_prog_busybox/bin/cat <<EOF
### MariaDB Nix Image Manual
##
## USER_UID ? $_conf_user_uid - default user id
## USER_GID ? $_conf_user_gid - default group id
### Place additional config files in \`/etc/mysql/mariadb.conf.d\`
EOF
default_opt USER_UID "$_conf_user_uid"
default_opt USER_GID "$_conf_user_gid"
$_prog_busybox/bin/cat <<EOF
### Starting with options:
## USER_UID = "$_user_uid"
## USER_GID = "$_user_gid"
EOF
(
set -e
echo "mariadb:x:$_user_uid:$_user_gid:MariaDB:$_conf_data:$_prog_bash/bin/bash" > /etc/passwd
echo "mariadb:x:$_user_gid:" > /etc/group
) || echo_exit "Failed to create user and group!"
mkdir_chown /tmp "$_user_uid" "$_user_gid"
mkdir_chown /run/mysqld/ "$_user_uid" "$_user_gid"
mkdir_chown /etc/mysql 0 0
mkdir_chown /etc/mysql/mariadb.conf.d 0 0
$_prog_busybox/bin/ln -s "$_file_mariadb_conf" /etc/mysql/my.cnf
[[ ! -d $_conf_data ]] && (mkdir_chown $_conf_data "$_user_uid" "$_user_gid" || echo_exit "Failed to create \`$_conf_data\`")
if [[ ! -d $_conf_data/mysql ]]
then
PATH=$_prog_busybox/bin:$_prog_nettools/bin $_prog_mariadb/bin/mysql_install_db --user=mariadb --datadir=$_conf_data --defaults-file=/etc/mysql/my.cnf
fi
check_owner "$_conf_data" "$_user_uid" "$_user_gid"
save_env "_user_uid \
_user_gid \
conf
" > /env
check_root "$_user_uid"
exec $_prog_busybox/bin/su mariadb -c "$0 $@" || /
echo_exit "Failed to switch user!"
else
echo
echo "Starting MariaDB!"
$_prog_mariadb/bin/mysqld $@
fi

View file

@ -0,0 +1,23 @@
# The MariaDB configuration file
#
# The MariaDB/MySQL tools read configuration files in the following order:
# 1. "/etc/mysql/mariadb.cnf" (this file) to set global defaults,
# 2. "/etc/mysql/conf.d/*.cnf" to set global options.
# 3. "/etc/mysql/mariadb.conf.d/*.cnf" to set MariaDB-only options.
# 4. "~/.my.cnf" to set user-specific options.
#
# If the same option is defined multiple times, the last one will apply.
#
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# This group is read both both by the client and the server
# use it for options that affect everything
#
[client-server]
datadir=/data/mariadb
# Import all .cnf files from configuration directory
!includedir /etc/mysql/mariadb.conf.d/

View file

@ -1,39 +0,0 @@
{ pkgs, nixpkgs, ... }:
let
env = let
defaults = {
user = "postgres";
db = "postgres";
host_auth_method = "scram-sha-256";
data = "/pgdata";
waldir = "/waldir";
uid = builtins.toString 5000;
gid = builtins.toString 5000;
};
postgres = pkgs.postgresql_12;
bashLib = ../bash-lib;
in
with pkgs; with defaults; pkgs.writeShellScriptBin "conf" ''
_conf_user=${user};
_conf_database=${db};
_conf_host_auth_method=${host_auth_method}
_conf_data=${data}
_conf_waldir=${waldir}
_conf_user_uid=${uid}
_conf_user_gid=${gid}
_prog_busybox=${busybox}
_prog_postgres=${postgres}
_prog_bash=${bash}
_prog_bash_lib=${bashLib}
'';
init = pkgs.writeShellScript "init" (builtins.readFile ./init);
in
pkgs.dockerTools.buildLayeredImage {
name = "postgresql";
tag = "latest";
config = {
Cmd = [ "${init}" "${env}/bin/conf" ];
};
}

View file

@ -1,242 +0,0 @@
# -*- mode: shell-script; -*-
conf=$1
source $conf
source $_prog_bash_lib/main.bash
if [[ $(${_prog_busybox}/bin/id -u) = 0 ]] ; then
${_prog_busybox}/bin/cat << EOF
### PostgreSQL Nix Image MANUAL
##
## USER_UID ? $_conf_user_uid - default user id
## USER_GID ? $_conf_user_gid - default group id
## PASSWORD - password for POSTGRES_USER
## DATABASE ? $_conf_database - default database
## [ NO_CREATE_DB ] - disables the creation of a default user + db # Currently UNUSED !!
## INITDB_ARGS ? "" - passed to \`initdb\`
## [ INITDB_WALDIR ] ? $_conf_waldir - write-ahead log directory
## HOST_AUTH_METHOD ? $_conf_host_auth_method - password authentication method
## [ PG_HBA ] - overrides the creation of pg_hba.conf, if not set a default one is created
## [ POSTGRES_CONF ] - postgres.conf file location for PostgreSQL
## [ POSTGRES_CONF_OVERWRITE ] -
## PGDATA ? $_conf_data - PostgreSQL data folder
### Recommended volumes (many directories which exist in normal Docker containers, do not exist in this one)
##
## - ${_conf_data} - PostgreSQL data folder
## - ${_conf_waldir} - PostgreSQL waldir
EOF
_user_uid="${USER_UID:-${_conf_user_uid}}"
_user_gid="${USER_GID:-${_conf_user_gid}}"
if [[ ! -z "${PASSWORD:-}" ]] ; then
_password="$PASSWORD"
else
echo 'You must specify the `PASSWORD` parameter!' ; exit 1
fi
_database="${DATABASE:-${_conf_database}}"
_no_create_db="''${NO_CREATE_DB:-}"
_initdb_args="''${INITDB_ARGS:-}"
if [[ ! -z "${INITDB_WALDIR+x}" ]] ; then
_initdb_waldir="''${INITDB_WALDIR:-${_conf_waldir}}"
else
_initdb_waldir=""
fi
_host_auth_method="${HOST_AUTH_METHOD:-${_conf_host_auth_method}}"
if [[ ! -z "${PG_HBA+x}" ]] ; then
if [[ ! -z "${PG_HBA:-}" ]] ; then
if [[ -f "$PG_HBA" ]] ; then
export _pg_hba="$PG_HBA"
else
echo "FILE \"$PG_HBA\" specified in \`PG_HBA'\ does not exist!" ; exit 1
fi
else
echo 'Parameter `PG_HBA` is set, but empty!' ; exit 1
fi
else
_pg_hba=""
fi
export _pgdata="${PGDATA:-${_conf_data}}"
${_prog_busybox}/bin/cat << EOF
## Starting with options:
## USER_UID = "$_user_uid"
## USER_GID = "$_user_gid"
## USER = "$_conf_user"
## PASSWORD = <REDACTED>
## DATABASE = "$_database"
## NO_CREATE_DB = "$([[ ! -z "$_no_create_db" ]] && echo true || echo false)"
## INITDB_ARGS = "$_initdb_args"
## INITDB_WALDIR = "$([[ ! -z "$_initdb_waldir" ]] && echo $_initdb_waldir || echo null)"
## HOST_AUTH_METHOD = "$_host_auth_method"
## PG_HBA = "$([[ ! -z "$_pg_hba" ]] && echo $_pg_hba || echo null)"
## PGDATA="$_pgdata"
EOF
echo "$_conf_user:x:$_user_uid:$_user_gid:PostgreSQL:$_pgdata:${_prog_bash}/bin/bash" > /etc/passwd
echo "$_conf_user:x:$_user_gid:" > /etc/group
if [[ ! -d "$_pgdata" ]] ; then
(
set -e
echo "Creating \`PGDATA\` and chown-ing to \"$_user_uid:$_user_gid\""
${_prog_busybox}/bin/mkdir -p "$_pgdata"
${_prog_busybox}/bin/chown postgres:postgres "$_pgdata"
) || \
echo_exit "Failed to create PGDATA!"
else
_pgdata_uid=$(${_prog_busybox}/bin/stat -c "%u" "$_pgdata" || \
echo_exit "Failed to get uid of PGDATA!")
_pgdata_gid=$(${_prog_busybox}/bin/stat -c "%g" "$_pgdata" || \
echo_exit "Failed to get gid of PGDATA!")
if [[ $_pgdata_uid != $_user_uid ]] || [[ $_pgdata_gid != $_user_gid ]] ; then
echo_exit \
"\`PGDATA\` already exists but has incorrect owner! \
$_pgdata_uid:$_pgdata_gid"
fi
fi
if [[ -s "$_pgdata/PG_VERSION" ]] ; then
_database_exists="true"
else
_database_exists=""
fi
if [[ ! -z "$_initdb_waldir" ]] ; then
if [[ ! -d "$_initdb_waldir" ]] ; then
(
set -e
echo "Creating \`INITDB_WALDIR\` and chown-ing to \"$_user_uid:$_user_gid\""
${busybox}/bin/mkdir -p "$_initdb_waldir"
${busybox}/bin/chown postgres:postgres "$_postgres_initdb_waldir"
) || \
echo_exit "Failed to create INITDB_WALDIR!"
else
_waldir_uid=$(${busybox}/bin/stat -c "%U" "$_postgres_initdb_waldir" || \
echo_exit "Faile to get uid of INITDB_WALDIR")
_waldir_gid=$(${busybox}/bin/stat -c "%G" "$_postgres_initdb_waldir" || \
echo_exit "Faile to get gid of INITDB_WALDIR")
if [[ $_waldir_uid != $_user_uid ]] || [[ $_waldir_gid != $_user_gid ]] ; then
echo_exit \
"\`INITDB_WALDIR\` already exists but has incorrect owner! \
$_waldir_uid:$_waldir_gid"
fi
fi
fi
$_prog_busybox/bin/mkdir -p /tmp /bin /run/postgresql || \
echo_exit "Failed to create necessary directories!"
$_prog_busybox/bin/chown postgres:postgres /tmp /run/postgresql || \
echo_exit "Failed to chown directories!"
## Required due to popen failing with `Cannot allocate memory` of all things
$_prog_busybox/bin/ln -s ${_prog_busybox}/bin/sh /bin/sh || \
echo_exit "Failed to symlink /bin/sh!"
save_env "_conf_user \
_pgdata \
_database \
_password \
_pg_hba \
_initdb_waldir \
_initdb_args \
_host_auth_method \
_prog_postgres" > /env
exec $_prog_busybox/bin/su postgres -c "$0 $@" || \
echo_exit "Failed to switch user!"
else
source /env || \
echo_exit "Failed to source env!"
## Next 4 functions are "borrowed" straight from:
## https://github.com/docker-library/postgres/blob/master/12/docker-entrypoint.sh
## Thanks!
# start socket-only postgresql server for setting up or running scripts
# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
temp_server_start() {
set -- "$@" -c listen_addresses="" -p "5432"
PGUSER="$_conf_user" \
$_prog_postgres/bin/pg_ctl -D "$_pgdata" \
-o "$(printf '%q ' "$@")" \
-w start
}
# stop postgresql server after done setting up user and running scripts
temp_server_stop() {
PGUSER="$_conf_user" \
$_prog_postgres/bin/pg_ctl -D "$_pgdata" -m fast -w stop
}
# Execute sql script, passed via stdin (or -f flag of pqsl)
# usage: docker_process_sql [psql-cli-args]
# ie: docker_process_sql --dbname=mydb <<<'INSERT ...'
# ie: docker_process_sql -f my-file.sql
# ie: docker_process_sql <my-file.sql
process_sql() {
local query_runner=( $_prog_postgres/bin/psql -v ON_ERROR_STOP=1 --username "$_conf_user" --no-password )
if [ -n "$_database" ]; then
query_runner+=( --dbname "$_database" )
fi
if [[ "$_host_auth_method" = "scram-sha-256" ]] ; then
query_runner+=( --auth-host=scram-sha-256 )
fi
"${query_runner[@]}" "$@"
}
# create initial database
# uses environment variables for input: POSTGRES_DB
setup_db() {
local dbAlreadyExists
dbAlreadyExists="$(
POSTGRES_DB= process_sql --dbname "$_database" --set db="$_database" --tuples-only <<-'EOSQL'
SELECT 1 FROM pg_database WHERE datname = :'db' ;
EOSQL
)"
if [ -z "$dbAlreadyExists" ]; then
POSTGRES_DB= process_sql --dbname postgres --set db="$_database" <<-'EOSQL'
CREATE DATABASE :"db" ;
EOSQL
echo
fi
}
if [[ -z "${_database_exists:-}" ]] ; then
$_prog_postgres/bin/initdb \
--username="$_conf_user" \
--pwfile=<(echo "$_password") \
$([[ "$_initdb_waldir" != "null" ]] && echo "$_initdb_waldir") \
$_initdb_args \
--pgdata="$_pgdata"
export PGPASSWORD="$_password"
temp_server_start
setup_db
temp_server_stop
unset PGPASSWORD
if [[ -z "$_pg_hba" ]] ; then
echo "host all all all $_host_auth_method" >> "$_pgdata/pg_hba.conf"
else
cp "$_pg_hba" "$_pgdata/pg_hba.conf"
fi
fi
echo
echo "Starting PostgreSQL"
export PGDATA="$_pgdata"
exec $_prog_postgres/bin/postgres
fi

View file

@ -63,12 +63,26 @@
"type": "indirect"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1613226215,
"narHash": "sha256-3rA5cGIrBHD6yeKhNhsF7/t461ww25oJY8KyBb0IhjU=",
"path": "/nix/store/nm00hhm641807yih5qxf98d9hxixzfg6-source",
"rev": "ff96a0fa5635770390b184ae74debea75c3fd534",
"type": "path"
},
"original": {
"id": "nixpkgs-unstable",
"type": "indirect"
}
},
"root": {
"inputs": {
"csi-driver-nfs": "csi-driver-nfs",
"klippy": "klippy",
"moonraker": "moonraker",
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable"
}
}
},

View file

@ -1,6 +1,7 @@
{
inputs = {
nixpkgs.url = "nixpkgs";
nixpkgs-unstable.url = "nixpkgs-unstable";
csi-driver-nfs = {
flake = false;
@ -39,6 +40,8 @@
"postgresql"
"gitea"
"csi-driver-nfs"
"nix"
"mariadb"
];
containerTest = let
all-modules = import <nixpkgs/nixos/modules/module-list.nix>;
@ -52,9 +55,5 @@
}).config.services.mysql.dataDir;
in {
inherit flakes dockerImages containerTest;
nginx-test = import ./infrastructure/nginx-test {
inherit rlib inputs pkgs;
};
};
}

View file

@ -1,3 +1,5 @@
# -*- mode: conf; -*-
APP_NAME = Red Alder Gitea
RUN_MODE = prod
RUN_USER = gitea
@ -9,7 +11,7 @@ ROOT = /data/gitea/git/repositories
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload]
TEMP_PATH = /data/gitea/uploads
TEMP_PATH = /data/gitea/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
@ -21,44 +23,42 @@ SSH_PORT = 22
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
LFS_CONTENT_PATH = /data/gitea/git/lfs
DOMAIN = gitea.redalder.org
DOMAIN = localhost
LFS_JWT_SECRET = {{ with secret "kv/gitea" }}{{ .Data.lfs_jwt_secret }}{{ end }}
OFFLINE_MODE = false
[database]
PATH = /data/gitea/gitea.db
DB_TYPE = postgres
HOST = localhost
POST = 5764
DB_TYPE = mysql
HOST = {{ env "NOMAD_HOST_ADDR_db" }}
NAME = gitea
USER = gitea
PASSWD = gitea
USER = {{ with secret "kv/gitea" }}{{ .Data.db_user }}{{ end }}
PASSWD = {{ with secret "kv/gitea" }}{{ .Data.db_passwd }}{{ end }}
SCHEMA =
SSL_MODE = disable
CHARSET = utf8
[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
ISSUE_INDEXER_PATH = /data/gitea/gitea/indexers/issues.bleve
REPO_INDEXER_PATH = /data/gitea/gitea/indexers/repos.bleve
[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER_CONFIG = /data/gitea/gitea/sessions
PROVIDER = file
[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
AVATAR_UPLOAD_PATH = /data/gitea/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/gitea/repo-avatars
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = true
[attachment]
PATH = /data/gitea/attachments
[log]
ROOT_PATH = /data/gitea/log
MODE = file
LEVEL = info
PATH = /data/gitea/gitea/attachments
[security]
INSTALL_LOCK = true
SECRET_KEY = {{ with secret "kv/gitea" }}{{ .Data.secret_key }}{{ end }}
INTERNAL_TOKEN = {{ with secret "kv/gitea" }}{{ .Data.internal_token }}{{ end }}
[service]
DISABLE_REGISTRATION = false
@ -72,6 +72,9 @@ DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.localhost
[oauth2]
JWT_SECRET = {{ with secret "kv/gitea" }}{{ .Data.jwt_secret }}{{ end }}
[mailer]
ENABLED = false

View file

@ -0,0 +1,15 @@
type = "csi"
id = "gitea-data"
name = "gitea-data"
plugin_id = "nfs"
access_mode = "single-node-writer"
attachment_mode = "file-system"
context {
server = "blowhole.in.redalder.org"
share = "/gitea-data"
}
mount_options {
fs_type = "nfs"
}

View file

@ -0,0 +1,15 @@
type = "csi"
id = "gitea-db"
name = "gitea-db"
plugin_id = "nfs"
access_mode = "single-node-writer"
attachment_mode = "file-system"
context {
server = "blowhole.in.redalder.org"
share = "/gitea-db"
}
mount_options {
fs_type = "nfs"
}

View file

@ -0,0 +1,117 @@
job "gitea" {
datacenters = [ "homelab-1" ]
type = "service"
group "svc" {
count = 1
volume "gitea-data" {
type = "csi"
source = "gitea-data"
read_only = false
}
volume "gitea-db" {
type = "csi"
source = "gitea-db"
read_only = false
}
restart {
attempts = 5
delay = "5s"
}
network {
port "db" {
to = "3306"
}
port "http" {
static = "3666"
to = "3000"
}
}
service {
name = "gitea"
port = "http"
check {
type = "http"
path = "/"
interval = "2s"
timeout = "2s"
}
}
task "app" {
driver = "docker"
volume_mount {
volume = "gitea-data"
destination = "/data/gitea"
read_only = false
}
config {
image = "gitea:local"
ports = ["http"]
volumes = [
"local/app.ini:/app.ini",
]
labels = {
"traefik.http.routers.gitea.rule" = "Host(`gitea.redalder.org`)"
"traefik.http.services.gitea.loadbalancer.server.address" = "${NOMAD_HOST_ADDR_http}"
"traefik.enable" = "true"
}
}
env {
USER_UID = "5001"
USER_GID = "5001"
}
resources {
cpu = 500
memory = 1024
}
vault {
policies = ["gitea-policy"]
}
template {
data = file("./app.ini.tpl")
destination = "local/app.ini"
}
}
task "db" {
driver = "docker"
volume_mount {
volume = "gitea-db"
destination = "/data/mariadb"
read_only = false
}
config {
image = "mariadb:local"
ports = ["db"]
}
env {
USER_UID = "84"
USER_GID = "84"
}
resources {
cpu = 500
memory = 512
}
}
}
}

View file

@ -1,10 +0,0 @@
{ pkgs, rlib, inputs }:
let
lockedNixpkgs =
(builtins.fromJSON (builtins.readFile ../../flake.lock))
.nodes.nixpkgs.locked;
in
rlib.substitute pkgs.runCommandNoCC "nginx-test.hcl" ./job.hcl {
"nixpkgs.rev" = lockedNixpkgs.rev;
"nixpkgs.sha" = lockedNixpkgs.narHash;
}

View file

@ -1,166 +0,0 @@
job "nginx-test" {
datacenters = [ "homelab-1" ]
type = "service"
group "nginx-test" {
count = 1
network {
port "http" {
static = "8087"
to = "80"
}
}
task "nix-prestart" {
lifecycle {
hook = "prestart"
sidecar = false
}
driver = "raw_exec"
template {
data = <<EOF
#!/usr/bin/env bash
_profile_dir=/nix/var/nix/profiles/nomad/${NOMAD_GROUP_NAME}-${NOMAD_ALLOC_INDEX}
_gcroots_dir=/nix/var/nix/gcroots/nomad/${NOMAD_GROUP_NAME}-${NOMAD_ALLOC_INDEX}
if [[ ! -d ${_profile_dir} ]]
then
mkdir -p "${_profile_dir}"
else
echo "${_profile_dir} exists when it shouldn't! Exiting..." ; exit 1
fi
if [[ ! -d ${_gcroots} ]]
then
mkdir -p "${_gcroots_dir}"
else
echo "${_gcroots_dir} exists when it shouldn't! Exiting..." ; exit 1
fi
/nix/var/nix/profiles/default/bin/nix-build "${NOMAD_TASK_DIR}/default.nix" -o "${_profile_dir}/system"
EOF
destination = "/local/prepare.sh"
}
template {
data = <<EOF
let
nixpkgs = builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/tarball/@nixpkgs.rev@";
sha256 = "@nixpkgs.sha@";
};
pkgs = import nixpkgs {};
nixosSystem = import /nix/store/v61f12269zsqsliilpl0jqwg8xsvbvai-nixpkgs-21.03pre268117.64c12484642/nixpkgs/nixos;
nspawn-init = pkgs.writeShellScriptBin "nspawn-init" ''
${pkgs.bash}/bin/bash /nix/var/nix/profiles/system/activate
exec /nix/var/nix/profiles/system/sw/bin/init
'';
in
(nixosSystem {
system = "x86_64-linux";
configuration = _: {
boot.isContainer = true;
time.timeZone = "Europe/Bratislava";
environment.systemPackages = [
nspawn-init
];
systemd.extraConfig = ''
DefaultStandardOutput=tty
'';
networking.firewall.enable = false;
services.nginx = {
enable = true;
};
};
}).config.system.build.toplevel
EOF
destination = "/local/default.nix"
}
config {
command = "bash"
args = [ "${NOMAD_TASK_DIR}/prepare.sh" ]
}
}
task "app" {
driver = "nspawn"
config {
image = "/nomad-nspawn-empty-dir"
resolv_conf = "off"
ephemeral = true
bind_read_only = {
"/nix/store" = "/nix/store"
"/nix/var/nix/db" = "/nix/var/nix/db"
"/nix/var/nix/daemon-socket" = "/nix/var/nix/daemon-socket"
}
bind = {
"/run/systemd/notify" = "/var/lib/provate/host-notify"
"/nix/var/nix/profiles/nomad/${NOMAD_GROUP_NAME}-${NOMAD_ALLOC_INDEX}":"/nix/var/nix/profiles"
"/nix/var/nix/gcroots/nomad/${NOMAD_GROUP_NAME}-${NOMAD_ALLOC_INDEX}":"/nix/var/nix/gcroots"
}
user_namespacing = false
boot = false
command = [
"/nix/var/nix/profiles/system/sw/bin/bash",
"/nix/var/nix/profiles/system/sw/bin/nspawn-init"
]
ports = ["http"]
}
}
task "nix-poststop" {
lifecycle {
hook = "poststop"
sidecar = false
}
driver = "raw_exec"
template {
data = <<EOF
#!/usr/bin/env bash
_profile_dir=/nix/var/nix/profiles/nomad/${NOMAD_GROUP_NAME}-${NOMAD_ALLOC_INDEX}
_gcroots_dir=/nix/var/nix/gcroots/nomad/${NOMAD_GROUP_NAME}-${NOMAD_ALLOC_INDEX}
if [[ -d ${_profile_dir} ]]
then
rm -r ${_profile_dir}
else
echo "${_profile_dir} does not exist! Exiting..." ; exit 1
fi
if [[ -d ${_gcroots_dir} ]]
then
rm -r ${_gcroots_dir}
else
echo "${_gcroots_dir} does not exist! Exiting..." ; exit 1
fi
EOF
destination = "/local/cleanup.sh"
}
config {
command = "bash"
args = [ "${NOMAD_TASK_DIR}/cleanup.sh" ]
}
}
}
}

View file

@ -1,2 +0,0 @@
[build]
target = "x86_64-unknown-linux-musl"

View file

@ -1,14 +0,0 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust
### Rust ###
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# End of https://www.toptal.com/developers/gitignore/api/rust

View file

@ -1,17 +0,0 @@
[package]
name = "rust-runner"
version = "0.1.0"
authors = ["Magic_RB <magic_rb@redalder.org>"]
edition = "2018"
[[bin]]
name = "gitea"
path = "src/gitea.rs"
[dependencies]
toml = "0.5.8"
serde = { version = "1.0.122", features = ["derive"] }
nix = "0.19.1"
simplelog = "0.9.0"
log = "0.4.13"
privdrop = "0.5.0"

View file

@ -1,32 +0,0 @@
{
inputs = {
nixpkgs.url = "nixpkgs";
};
outputs = { self, nixpkgs, ... }@inputs:
let
supportedSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
in
{
overlay = final: prev:
with final; {
rust-runner = rustPlatform.buildRustPackage rec {
pname = "rust-runner";
version = "0.1";
src = ./.;
buildType = "debug";
cargoSha256 = "Z/Q66St/Q/suG8BxJXNwevdPvTQJgGzmvgGeCzP01KY=";
};
};
defaultPackage = forAllSystems (system: (import nixpkgs {
inherit system;
overlays = [ self.overlay ];
}).rust-runner);
};
}

View file

@ -1,187 +0,0 @@
extern crate log;
extern crate nix;
extern crate serde;
extern crate simplelog;
extern crate toml;
use std::{
error::Error,
fs::File,
io::Read,
path::{Path, PathBuf},
};
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
fn mkdir_chown<S: AsRef<str>>(s: S, uid: u32, gid: u32) -> Result<(), String> {
use nix::{
dir::Dir,
fcntl::OFlag,
sys::stat::{stat, Mode},
unistd::{chown, mkdir},
unistd::{Gid, Uid},
};
use std::fs::create_dir_all;
let s = s.as_ref();
if let Ok(_) = Dir::open(s, OFlag::empty(), Mode::empty()) {
let stat = stat(s).map_err(|err| format!("Failed to stat: {} {}", s, err))?;
if stat.st_uid != uid || stat.st_gid != gid {
warn!(
"Directory {} exists, but has incorrect o/g: {}:{}, trying to chown...",
s, uid, gid
);
chown(s, Some(Uid::from_raw(uid)), Some(Gid::from_raw(gid)))
.map_err(|err| format!("Failed to chown: {}, {}", s, err))
} else {
Ok(())
}
} else {
create_dir_all(s).map_err(|err| format!("Failed to mkdir: {} {}", s, err))?;
chown(s, Some(Uid::from_raw(uid)), Some(Gid::from_raw(gid)))
.map_err(|err| format!("Failed to chown: {} {}", s, err))?;
Ok(())
}
}
fn drop_privileges<S: AsRef<str>>(user: S) -> Result<(), String> {
use privdrop::PrivDrop;
let user = user.as_ref();
PrivDrop::default()
.user(user)
.group(user)
.apply()
.map_err(|err| format!("Failed to drop priviledges to {}:{} {}", user, user, err))
}
fn adduser<S: AsRef<str>>(name: S, uid: u32, gid: u32, home: S, shell: S) -> Result<(), String> {
use std::{fs::OpenOptions, io::Write};
let passwd = "/etc/passwd";
let group = "/etc/group";
let mut file = OpenOptions::new()
.read(false)
.write(true)
.append(true)
.create(true)
.open(passwd)
.map_err(|_| format!("Cannot open: {}", passwd))?;
file.write_all(
format!(
"{}:x:{}:{}:User:{}:{}",
name.as_ref(),
uid,
gid,
home.as_ref(),
shell.as_ref(),
)
.as_bytes(),
)
.map_err(|_| format!("Write to {} failed", passwd))?;
let mut file = OpenOptions::new()
.read(false)
.write(true)
.append(true)
.create(true)
.open(group)
.map_err(|err| format!("Cannot open: {} {}", group, err))?;
file.write_all(format!("{}:x:{}:", name.as_ref(), gid,).as_bytes())
.map_err(|err| format!("Write to {} failed {}", passwd, err))?;
Ok(())
}
fn exec<S: AsRef<str>>(command: S, args: &[S]) -> Result<(), String> {
use std::ffi::CString;
use nix::unistd::execv;
let command = command.as_ref();
let args = args.iter().map(|arg| arg.as_ref());
let args = [command]
.iter()
.map(|command| *command)
.chain(args)
.map(|arg| CString::new(arg))
.collect::<Result<Vec<CString>, _>>()
.map_err(|err| format!("Failed to create CString {}", err))?;
let command = CString::new(command).map_err(|err| format!("Failed to create CString {}", err))?;
execv(command.as_c_str(), args.as_ref()).map_err(|err| format!("execv failed {}", err))?;
Ok(())
}
mod defaults {
pub fn uid() -> u32 {
5000
}
pub fn gid() -> u32 {
5000
}
}
#[derive(Serialize, Deserialize)]
struct Configuration<'a> {
#[serde(default = "defaults::uid")]
gid: u32,
#[serde(default = "defaults::gid")]
uid: u32,
app_ini: Option<&'a str>,
app_ini_overwrite: bool,
}
fn main() -> Result<(), Box<dyn Error>> {
{
use simplelog::{Config, LevelFilter, TermLogger, TerminalMode};
TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed)
};
let mut file = File::open("/config.toml").map_err(|err| format!("Failed to open config {}", err))?;
let mut str = String::new();
file.read_to_string(&mut str).map_err(|err| format!("Failed read config {}", err))?;
let config = toml::from_str::<Configuration>(str.as_str())?;
mkdir_chown("/tmp/", config.uid, config.gid)?;
mkdir_chown("/data/gitea/", config.uid, config.gid)?;
mkdir_chown("/etc/", 0, 0)?;
adduser("gitea", config.uid, config.gid, "/data/gitea/", "/bin/sh")?; // TODO /bin/sh doesn't exist, we need busybox
info!("Dropping privileges to config.uid:config.gid");
drop_privileges("gitea")?;
if let Some(app_ini) = config.app_ini {
use nix::sys::stat::stat;
use std::fs::copy;
let stat = stat(app_ini);
if stat.is_err() {
copy(app_ini, "/data/gitea/app.ini").map_err(|err| format!("Failed to copy app.ini {}", err))?;
} else {
if config.app_ini_overwrite {
copy(app_ini, "/data/gitea/app.ini").map_err(|err| format!("Failed to copy app.ini {}", err))?;
} else {
error!("app.ini exists, but not overwriting!");
}
}
}
use std::env::set_var;
set_var("HOME", "/data/gitea/");
set_var("GITEA_WORK_DIR", "/data/gitea/");
exec("/bin/gitea", &["-c", "/data/gitea/app.ini"])?;
Ok(())
}

View file

@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}