diff options
author | makefu <makefu@nixos.dev> | 2016-01-18 12:50:20 +0100 |
---|---|---|
committer | makefu <makefu@nixos.dev> | 2016-01-18 12:50:20 +0100 |
commit | f4754010336a1d7c876bc6797a44f30e3d4b4ead (patch) | |
tree | de4dff5340b76d970cc404146e688726e4446e0f /krebs | |
parent | b86daca11669019d3c2218e623bfb57b5a8033d7 (diff) | |
parent | de891cf43181d28cbc9526993df4e55022d230da (diff) |
Merge branch 'master' of gum:stockholm
Diffstat (limited to 'krebs')
36 files changed, 1312 insertions, 156 deletions
diff --git a/krebs/3modules/Reaktor.nix b/krebs/3modules/Reaktor.nix index 1ec49b81e..92400139c 100644 --- a/krebs/3modules/Reaktor.nix +++ b/krebs/3modules/Reaktor.nix @@ -1,25 +1,15 @@ -{ config, pkgs,lib, ... }: - +{ config, lib, pkgs, ... }: +with lib; let - inherit (lib) - mkIf - mkOption - types - singleton - isString - optionalString - concatStrings - escapeShellArg - ; - ReaktorConfig = pkgs.writeText "config.py" '' ${if (isString cfg.overrideConfig ) then '' # Overriden Config ${cfg.overrideConfig} '' else ""} ## Extra Config + ${concatStringsSep "\n" (map (plug: plug.config) cfg.plugins)} ${cfg.extraConfig} ''; cfg = config.krebs.Reaktor; @@ -46,7 +36,6 @@ let ''; }; - overrideConfig = mkOption { default = null; type = types.nullOr types.str; @@ -55,6 +44,9 @@ let Reaktor default cfg can be retrieved via `reaktor get-config` ''; }; + plugins = mkOption { + default = [pkgs.ReaktorPlugins.nixos-version]; + }; extraConfig = mkOption { default = ""; type = types.string; @@ -62,6 +54,14 @@ let configuration appended to the default or overridden configuration ''; }; + + workdir = mkOption { + default = "/var/lib/Reaktor"; + type = types.str; + description = '' + Reaktor working directory + ''; + }; extraEnviron = mkOption { default = {}; type = types.attrsOf types.str; @@ -70,12 +70,17 @@ let REAKTOR_HOST REAKTOR_PORT REAKTOR_STATEDIR - REAKTOR_CHANNELS debug and nickname can be set separately via the Reaktor api ''; }; - + channels = mkOption { + default = [ "#krebs" ]; + type = types.listOf types.str; + description = '' + Channels the Reaktor should connect to at startup. + ''; + }; debug = mkOption { default = false; description = '' @@ -86,12 +91,11 @@ let imp = { # for reaktor get-config - users.extraUsers = singleton { + users.extraUsers = singleton rec { name = "Reaktor"; - # uid = config.ids.uids.Reaktor; - uid = 2066439104; #genid Reaktor + uid = genid name; description = "Reaktor user"; - home = "/var/lib/Reaktor"; + home = cfg.workdir; createHome = true; }; @@ -113,6 +117,9 @@ let GIT_SSL_CAINFO = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; REAKTOR_NICKNAME = cfg.nickname; REAKTOR_DEBUG = (if cfg.debug then "True" else "False"); + REAKTOR_CHANNELS = lib.concatStringsSep "," cfg.channels; + state_dir = cfg.workdir; + } // cfg.extraEnviron; serviceConfig= { ExecStartPre = pkgs.writeScript "Reaktor-init" '' diff --git a/krebs/3modules/apt-cacher-ng.nix b/krebs/3modules/apt-cacher-ng.nix index 75296bafb..371d39b6f 100644 --- a/krebs/3modules/apt-cacher-ng.nix +++ b/krebs/3modules/apt-cacher-ng.nix @@ -119,16 +119,14 @@ let imp = { users.extraUsers.acng = { - # uid = config.ids.uids.acng; - uid = 897955083; #genid Reaktor + uid = genid "acng"; description = "apt-cacher-ng"; home = acng-home; createHome = false; }; users.extraGroups.acng = { - gid = 897955083; #genid Reaktor - # gid = config.ids.gids.Reaktor; + gid = genid "acng"; }; systemd.services.apt-cacher-ng = { diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix new file mode 100644 index 000000000..01bb16a2b --- /dev/null +++ b/krebs/3modules/backup.nix @@ -0,0 +1,286 @@ +{ config, lib, pkgs, ... }: +with lib; +let + out = { + options.krebs.backup = api; + config = mkIf cfg.enable imp; + }; + + cfg = config.krebs.backup; + + api = { + enable = mkEnableOption "krebs.backup" // { default = true; }; + plans = mkOption { + default = {}; + type = types.attrsOf (types.submodule ({ + # TODO enable = mkEnableOption "TODO" // { default = true; }; + options = { + method = mkOption { + type = types.enum ["pull" "push"]; + }; + name = mkOption { + type = types.str; + }; + src = mkOption { + type = types.krebs.file-location; + }; + dst = mkOption { + type = types.krebs.file-location; + }; + startAt = mkOption { + type = types.str; + }; + snapshots = mkOption { + type = types.attrsOf (types.submodule { + options = { + format = mkOption { + type = types.str; # TODO date's +FORMAT + }; + retain = mkOption { + type = types.nullOr types.int; + default = null; # null = retain all snapshots + }; + }; + }); + }; + }; + })); + }; + }; + + imp = { + users.groups.backup.gid = genid "backup"; + users.users = {} + // { + root.openssh.authorizedKeys.keys = + map (plan: plan.dst.host.ssh.pubkey) + (filter isPullSrc (attrValues cfg.plans)) + ++ + map (plan: plan.src.host.ssh.pubkey) + (filter isPushDst (attrValues cfg.plans)) + ; + } + ; + systemd.services = + flip mapAttrs' (filterAttrs (_:isPullDst) cfg.plans) (name: plan: { + name = "backup.${name}.pull"; + value = makePullService plan; + }) + // + flip mapAttrs' (filterAttrs (_:isPushSrc) cfg.plans) (name: plan: { + name = "backup.${name}.push"; + value = makePushService plan; + }) + ; + }; + + isPushSrc = plan: + plan.method == "push" && + plan.src.host.name == config.krebs.build.host.name; + + isPullSrc = plan: + plan.method == "pull" && + plan.src.host.name == config.krebs.build.host.name; + + isPushDst = plan: + plan.method == "push" && + plan.dst.host.name == config.krebs.build.host.name; + + isPullDst = plan: + plan.method == "pull" && + plan.dst.host.name == config.krebs.build.host.name; + + # TODO push destination needs this in the dst.user's PATH + service-path = [ + pkgs.coreutils + pkgs.gnused + pkgs.openssh + pkgs.rsync + pkgs.utillinux + ]; + + # TODO if there is plan.user, then use its privkey + makePushService = plan: assert isPushSrc plan; { + path = service-path; + serviceConfig = { + ExecStart = push plan; + Type = "oneshot"; + }; + startAt = plan.startAt; + }; + + makePullService = plan: assert isPullDst plan; { + path = service-path; + serviceConfig = { + ExecStart = pull plan; + Type = "oneshot"; + }; + startAt = plan.startAt; + }; + + push = plan: let + # We use writeDashBin and return the absolute path so systemd will produce + # nice names in the log, i.e. without the Nix store hash. + out = "${main}/bin/${main.name}"; + + main = writeDashBin "backup.${plan.name}.push" '' + set -efu + dst=${shell.escape plan.dst.path} + + mkdir -m 0700 -p "$dst" + exec flock -n "$dst" ${critical-section} + ''; + + critical-section = writeDash "backup.${plan.name}.push.critical-section" '' + # TODO check if there is a previous + set -efu + identity=${shell.escape plan.src.host.ssh.privkey.path} + src=${shell.escape plan.src.path} + dst_target=${shell.escape "root@${getFQDN plan.dst.host}"} + dst_path=${shell.escape plan.dst.path} + dst=$dst_target:$dst_path + + # Export NOW so runtime of rsync doesn't influence snapshot naming. + export NOW + NOW=$(date +%s) + + echo >&2 "update snapshot: current; $src -> $dst" + rsync >&2 \ + -aAXF --delete \ + -e "ssh -F /dev/null -i $identity" \ + --rsync-path ${shell.escape + "mkdir -m 0700 -p ${shell.escape plan.dst.path} && rsync"} \ + --link-dest="$dst_path/current" \ + "$src/" \ + "$dst/.partial" + + exec ssh -F /dev/null \ + -i "$identity" \ + "$dst_target" \ + -T \ + env NOW="$NOW" /bin/sh < ${remote-snapshot} + EOF + ''; + + remote-snapshot = writeDash "backup.${plan.name}.push.remote-snapshot" '' + set -efu + dst=${shell.escape plan.dst.path} + + if test -e "$dst/current"; then + mv "$dst/current" "$dst/.previous" + fi + mv "$dst/.partial" "$dst/current" + rm -fR "$dst/.previous" + echo >&2 + + (${(take-snapshots plan).text}) + ''; + + in out; + + # TODO admit plan.dst.user and its ssh identity + pull = plan: let + # We use writeDashBin and return the absolute path so systemd will produce + # nice names in the log, i.e. without the Nix store hash. + out = "${main}/bin/${main.name}"; + + main = writeDashBin "backup.${plan.name}.pull" '' + set -efu + dst=${shell.escape plan.dst.path} + + mkdir -m 0700 -p "$dst" + exec flock -n "$dst" ${critical-section} + ''; + + critical-section = writeDash "backup.${plan.name}.pull.critical-section" '' + # TODO check if there is a previous + set -efu + identity=${shell.escape plan.dst.host.ssh.privkey.path} + src=${shell.escape "root@${getFQDN plan.src.host}:${plan.src.path}"} + dst=${shell.escape plan.dst.path} + + # Export NOW so runtime of rsync doesn't influence snapshot naming. + export NOW + NOW=$(date +%s) + + echo >&2 "update snapshot: current; $dst <- $src" + mkdir -m 0700 -p ${shell.escape plan.dst.path} + rsync >&2 \ + -aAXF --delete \ + -e "ssh -F /dev/null -i $identity" \ + --link-dest="$dst/current" \ + "$src/" \ + "$dst/.partial" + mv "$dst/current" "$dst/.previous" + mv "$dst/.partial" "$dst/current" + rm -fR "$dst/.previous" + echo >&2 + + exec ${take-snapshots plan} + ''; + in out; + + take-snapshots = plan: writeDash "backup.${plan.name}.take-snapshots" '' + set -efu + NOW=''${NOW-$(date +%s)} + dst=${shell.escape plan.dst.path} + + snapshot() {( + : $ns $format $retain + name=$(date --date="@$NOW" +"$format") + if ! test -e "$dst/$ns/$name"; then + echo >&2 "create snapshot: $ns/$name" + mkdir -m 0700 -p "$dst/$ns" + rsync >&2 \ + -aAXF --delete \ + --link-dest="$dst/current" \ + "$dst/current/" \ + "$dst/$ns/.partial.$name" + mv "$dst/$ns/.partial.$name" "$dst/$ns/$name" + echo >&2 + fi + case $retain in + ([0-9]*) + delete_from=$(($retain + 1)) + ls -r "$dst/$ns" \ + | sed -n "$delete_from,\$p" \ + | while read old_name; do + echo >&2 "delete snapshot: $ns/$old_name" + rm -fR "$dst/$ns/$old_name" + done + ;; + (ALL) + : + ;; + esac + )} + + ${concatStringsSep "\n" (mapAttrsToList (ns: { format, retain ? null, ... }: + toString (map shell.escape [ + "ns=${ns}" + "format=${format}" + "retain=${if retain == null then "ALL" else toString retain}" + "snapshot" + ])) + plan.snapshots)} + ''; + + # TODO getFQDN: admit hosts in other domains + getFQDN = host: "${host.name}.${config.krebs.search-domain}"; + + writeDash = name: text: pkgs.writeScript name '' + #! ${pkgs.dash}/bin/dash + ${text} + ''; + + writeDashBin = name: text: pkgs.writeTextFile { + executable = true; + destination = "/bin/${name}"; + name = name; + text = '' + #! ${pkgs.dash}/bin/dash + ${text} + ''; + }; + +in out diff --git a/krebs/3modules/bepasty-server.nix b/krebs/3modules/bepasty-server.nix index c99c3d11a..e74841205 100644 --- a/krebs/3modules/bepasty-server.nix +++ b/krebs/3modules/bepasty-server.nix @@ -130,12 +130,12 @@ let ) cfg.servers; users.extraUsers.bepasty = { - uid = 2796546855; #genid bepasty + uid = genid "bepasty"; group = "bepasty"; home = "/var/lib/bepasty-server"; }; users.extraGroups.bepasty = { - gid = 2796546855; #genid bepasty + gid = genid "bepasty"; }; }; diff --git a/krebs/3modules/buildbot/master.nix b/krebs/3modules/buildbot/master.nix new file mode 100644 index 000000000..74385a433 --- /dev/null +++ b/krebs/3modules/buildbot/master.nix @@ -0,0 +1,385 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + buildbot = pkgs.buildbot; + buildbot-master-config = pkgs.writeText "buildbot-master.cfg" '' + # -*- python -*- + from buildbot.plugins import * + import re + import json + c = BuildmasterConfig = {} + + c['slaves'] = [] + slaves = json.loads('${builtins.toJSON cfg.slaves}') + slavenames = [ s for s in slaves ] + for k,v in slaves.items(): + c['slaves'].append(buildslave.BuildSlave(k, v)) + + # TODO: configure protocols? + c['protocols'] = {'pb': {'port': 9989}} + + ####### Build Inputs + c['change_source'] = cs = [] + + ${ concatStringsSep "\n" + (mapAttrsToList (n: v: '' + #### Change_Source: Begin of ${n} + ${v} + #### Change_Source: End of ${n} + '') cfg.change_source )} + + ####### Build Scheduler + c['schedulers'] = sched = [] + + ${ concatStringsSep "\n" + (mapAttrsToList (n: v: '' + #### Schedulers: Begin of ${n} + ${v} + #### Schedulers: End of ${n} + '') cfg.scheduler )} + + ###### Builder + c['builders'] = bu = [] + + # Builder Pre: Begin + ${cfg.builder_pre} + # Builder Pre: End + + ${ concatStringsSep "\n" + (mapAttrsToList (n: v: '' + #### Builder: Begin of ${n} + ${v} + #### Builder: End of ${n} + '') cfg.builder )} + + + ####### Status + c['status'] = st = [] + + # If you want to configure this url, override with extraConfig + c['buildbotURL'] = "http://${config.networking.hostName}:${toString cfg.web.port}/" + + ${optionalString (cfg.web.enable) '' + from buildbot.status import html + from buildbot.status.web import authz, auth + authz_cfg=authz.Authz( + auth=auth.BasicAuth([ ("${cfg.web.username}","${cfg.web.password}") ]), + # TODO: configure harder + gracefulShutdown = False, + forceBuild = 'auth', + forceAllBuilds = 'auth', + pingBuilder = False, + stopBuild = 'auth', + stopAllBuilds = 'auth', + cancelPendingBuild = 'auth' + ) + # TODO: configure krebs.nginx + st.append(html.WebStatus(http_port=${toString cfg.web.port}, authz=authz_cfg)) + ''} + + ${optionalString (cfg.irc.enable) '' + from buildbot.status import words + irc = words.IRC("${cfg.irc.server}", "${cfg.irc.nick}", + channels=${builtins.toJSON cfg.irc.channels}, + notify_events={ + 'success': 1, + 'failure': 1, + 'exception': 1, + 'successToFailure': 1, + 'failureToSuccess': 1, + }${optionalString cfg.irc.allowForce ",allowForce=True"}) + c['status'].append(irc) + ''} + + ${ concatStringsSep "\n" + (mapAttrsToList (n: v: '' + #### Status: Begin of ${n} + ${v} + #### Status: End of ${n} + '') cfg.status )} + + ####### PROJECT IDENTITY + c['title'] = "${cfg.title}" + c['titleURL'] = "http://krebsco.de" + + + ####### DB URL + # TODO: configure + c['db'] = { + 'db_url' : "sqlite:///state.sqlite", + } + ${cfg.extraConfig} + ''; + + cfg = config.krebs.buildbot.master; + + api = { + enable = mkEnableOption "Buildbot Master"; + title = mkOption { + default = "Buildbot CI"; + type = types.str; + description = '' + Title of the Buildbot Installation + ''; + }; + workDir = mkOption { + default = "/var/lib/buildbot/master"; + type = types.str; + description = '' + Path to build bot master directory. + Will be created on startup. + ''; + }; + + secrets = mkOption { + default = []; + type = types.listOf types.str; + example = [ "cac.json" ]; + description = '' + List of all the secrets in <secrets> which should be copied into the + buildbot master directory. + ''; + }; + + slaves = mkOption { + default = {}; + type = types.attrsOf types.str; + description = '' + Attrset of slavenames with their passwords + slavename = slavepassword + ''; + }; + + change_source = mkOption { + default = {}; + type = types.attrsOf types.str; + example = { + stockholm = '' + cs.append(changes.GitPoller( + 'http://cgit.gum/stockholm', + workdir='stockholm-poller', branch='master', + project='stockholm', + pollinterval=120)) + ''; + }; + description = '' + Attrset of all the change_sources which should be configured. + It will be directly included into the master configuration. + + At the end an change object should be appended to <literal>cs</literal> + ''; + }; + + scheduler = mkOption { + default = {}; + type = types.attrsOf types.str; + example = { + force-scheduler = '' + sched.append(schedulers.ForceScheduler( + name="force", + builderNames=["full-tests"])) + ''; + }; + description = '' + Attrset of all the schedulers which should be configured. + It will be directly included into the master configuration. + + At the end an change object should be appended to <literal>sched</literal> + ''; + }; + + builder_pre = mkOption { + default = ""; + type = types.lines; + example = '' + grab_repo = steps.Git(repourl=stockholm_repo, mode='incremental') + ''; + description = '' + some code before the builders are being assembled. + can be used to define functions used by multiple builders + ''; + }; + + builder = mkOption { + default = {}; + type = types.attrsOf types.str; + example = { + fast-test = '' + ''; + }; + description = '' + Attrset of all the builder which should be configured. + It will be directly included into the master configuration. + + At the end an change object should be appended to <literal>bu</literal> + ''; + }; + + status = mkOption { + default = {}; + type = types.attrsOf types.str; + description = '' + Attrset of all the extra status which should be configured. + It will be directly included into the master configuration. + + At the end an change object should be appended to <literal>st</literal> + + Right now IRC and Web status can be configured by setting + <literal>buildbot.master.irc.enable</literal> and + <literal>buildbot.master.web.enable</literal> + ''; + }; + + # Configurable Stati + web = mkOption { + default = {}; + type = types.submodule ({ config2, ... }: { + options = { + enable = mkEnableOption "Buildbot Master Web Status"; + username = mkOption { + default = "krebs"; + type = types.str; + description = '' + username for web authentication + ''; + }; + hostname = mkOption { + default = config.networking.hostName; + type = types.str; + description = '' + web interface Hostname + ''; + }; + password = mkOption { + default = "bob"; + type = types.str; + description = '' + password for web authentication + ''; + }; + port = mkOption { + default = 8010; + type = types.int; + description = '' + port for buildbot web status + ''; + }; + }; + }); + }; + + irc = mkOption { + default = {}; + type = types.submodule ({ config, ... }: { + options = { + enable = mkEnableOption "Buildbot Master IRC Status"; + channels = mkOption { + default = [ "nix-buildbot-meetup" ]; + type = with types; listOf str; + description = '' + irc channels the bot should connect to + ''; + }; + allowForce = mkOption { + default = false; + type = types.bool; + description = '' + Determines if builds can be forced via IRC + ''; + }; + nick = mkOption { + default = "nix-buildbot"; + type = types.str; + description = '' + nickname for IRC + ''; + }; + server = mkOption { + default = "irc.freenode.net"; + type = types.str; + description = '' + Buildbot Status IRC Server to connect to + ''; + }; + }; + }); + }; + + extraConfig = mkOption { + default = ""; + type = types.lines; + description = '' + extra config appended to the generated master.cfg + ''; + }; + }; + + imp = { + + users.extraUsers.buildbotMaster = { + uid = genid "buildbotMaster"; + description = "Buildbot Master"; + home = cfg.workDir; + createHome = false; + }; + + users.extraGroups.buildbotMaster = { + gid = 672626386; + }; + + systemd.services.buildbotMaster = { + description = "Buildbot Master"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + # TODO: add extra dependencies to master like svn and cvs + path = [ pkgs.git ]; + environment = { + SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + }; + serviceConfig = let + workdir="${lib.shell.escape cfg.workDir}"; + secretsdir="${lib.shell.escape (toString <secrets>)}"; + in { + PermissionsStartOnly = true; + Type = "forking"; + PIDFile = "${workdir}/twistd.pid"; + # TODO: maybe also prepare buildbot.tac? + ExecStartPre = pkgs.writeScript "buildbot-master-init" '' + #!/bin/sh + set -efux + if [ ! -e ${workdir} ];then + mkdir -p ${workdir} + ${buildbot}/bin/buildbot create-master -r -l 10 -f ${workdir} + fi + # always override the master.cfg + cp ${buildbot-master-config} ${workdir}/master.cfg + + # copy secrets + ${ concatMapStringsSep "\n" + (f: "cp ${secretsdir}/${f} ${workdir}/${f}" ) cfg.secrets } + # sanity + ${buildbot}/bin/buildbot checkconfig ${workdir} + + # TODO: maybe upgrade? not sure about this + # normally we should write buildbot.tac by our own + # ${buildbot}/bin/buildbot upgrade-master ${workdir} + + chmod 700 -R ${workdir} + chown buildbotMaster:buildbotMaster -R ${workdir} + ''; + ExecStart = "${buildbot}/bin/buildbot start ${workdir}"; + ExecStop = "${buildbot}/bin/buildbot stop ${workdir}"; + ExecReload = "${buildbot}/bin/buildbot reconfig ${workdir}"; + PrivateTmp = "true"; + User = "buildbotMaster"; + Restart = "always"; + RestartSec = "10"; + }; + }; + }; +in +{ + options.krebs.buildbot.master = api; + config = mkIf cfg.enable imp; +} diff --git a/krebs/3modules/buildbot/slave.nix b/krebs/3modules/buildbot/slave.nix new file mode 100644 index 000000000..0e7796d8a --- /dev/null +++ b/krebs/3modules/buildbot/slave.nix @@ -0,0 +1,186 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + buildbot-slave-init = pkgs.writeText "buildbot-slave.tac" '' + import os + + from buildslave.bot import BuildSlave + from twisted.application import service + + basedir = '${cfg.workDir}' + rotateLength = 10000000 + maxRotatedFiles = 10 + + application = service.Application('buildslave') + + from twisted.python.logfile import LogFile + from twisted.python.log import ILogObserver, FileLogObserver + logfile = LogFile.fromFullPath(os.path.join(basedir, "twistd.log"), rotateLength=rotateLength, + maxRotatedFiles=maxRotatedFiles) + application.setComponent(ILogObserver, FileLogObserver(logfile).emit) + + buildmaster_host = '${cfg.masterhost}' + # TODO: masterport? + port = 9989 + slavename = '${cfg.username}' + passwd = '${cfg.password}' + keepalive = 600 + usepty = 0 + umask = None + maxdelay = 300 + allow_shutdown = None + + ${cfg.extraConfig} + + s = BuildSlave(buildmaster_host, port, slavename, passwd, basedir, + keepalive, usepty, umask=umask, maxdelay=maxdelay, + allow_shutdown=allow_shutdown) + s.setServiceParent(application) + ''; + default-packages = [ pkgs.git pkgs.bash ]; + cfg = config.krebs.buildbot.slave; + + api = { + enable = mkEnableOption "Buildbot Slave"; + + workDir = mkOption { + default = "/var/lib/buildbot/slave"; + type = types.str; + description = '' + Path to build bot slave directory. + Will be created on startup. + ''; + }; + + masterhost = mkOption { + default = "localhost"; + type = types.str; + description = '' + Hostname/IP of the buildbot master + ''; + }; + + username = mkOption { + type = types.str; + description = '' + slavename used to authenticate with master + ''; + }; + + password = mkOption { + type = types.str; + description = '' + slave password used to authenticate with master + ''; + }; + + contact = mkOption { + default = "nix slave <buildslave@${config.networking.hostName}>"; + type = types.str; + description = '' + contact to be announced by buildslave + ''; + }; + + description = mkOption { + default = "Nix Generated BuildSlave"; + type = types.str; + description = '' + description for hostto be announced by buildslave + ''; + }; + + packages = mkOption { + default = [ pkgs.git ]; + type = with types; listOf package; + description = '' + packages which should be in path for buildslave + ''; + }; + + extraEnviron = mkOption { + default = {}; + example = { + NIX_PATH = "nixpkgs=/path/to/my/nixpkgs"; + }; + type = types.attrsOf types.str; + description = '' + extra environment variables to be provided to the buildslave service + if you need nixpkgs, e.g. for running nix-shell you can set NIX_PATH here. + ''; + }; + + extraConfig = mkOption { + default = ""; + type = types.lines; + example = '' + port = 443 + keepalive = 600 + ''; + description = '' + extra config evaluated before calling BuildSlave init in .tac file + ''; + }; + }; + + imp = { + + users.extraUsers.buildbotSlave = { + uid = genid "buildbotSlave"; + description = "Buildbot Slave"; + home = cfg.workDir; + createHome = false; + }; + + users.extraGroups.buildbotSlave = { + gid = 1408105834; + }; + + systemd.services."buildbotSlave-${cfg.username}-${cfg.masterhost}" = { + description = "Buildbot Slave for ${cfg.username}@${cfg.masterhost}"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = default-packages ++ cfg.packages; + + environment = { + SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + NIX_REMOTE="daemon"; + } // cfg.extraEnviron; + + serviceConfig = let + workdir = "${lib.shell.escape cfg.workDir}"; + contact = "${lib.shell.escape cfg.contact}"; + description = "${lib.shell.escape cfg.description}"; + buildbot = pkgs.buildbot-slave; + # TODO:make this + in { + PermissionsStartOnly = true; + Type = "forking"; + PIDFile = "${workdir}/twistd.pid"; + # TODO: maybe also prepare buildbot.tac? + ExecStartPre = pkgs.writeScript "buildbot-master-init" '' + #!/bin/sh + set -efux + mkdir -p ${workdir}/info + cp ${buildbot-slave-init} ${workdir}/buildbot.tac + echo ${contact} > ${workdir}/info/admin + echo ${description} > ${workdir}/info/host + + chown buildbotSlave:buildbotSlave -R ${workdir} + chmod 700 -R ${workdir} + ''; + ExecStart = "${buildbot}/bin/buildslave start ${workdir}"; + ExecStop = "${buildbot}/bin/buildslave stop ${workdir}"; + PrivateTmp = "true"; + User = "buildbotSlave"; + Restart = "always"; + RestartSec = "10"; + }; + }; + }; +in +{ + options.krebs.buildbot.slave = api; + config = mkIf cfg.enable imp; +} diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix index 740ba67b8..ba1f425d9 100644 --- a/krebs/3modules/default.nix +++ b/krebs/3modules/default.nix @@ -7,8 +7,11 @@ let out = { imports = [ ./apt-cacher-ng.nix + ./backup.nix ./bepasty-server.nix ./build.nix + ./buildbot/master.nix + ./buildbot/slave.nix ./current.nix ./exim-retiolum.nix ./exim-smarthost.nix diff --git a/krebs/3modules/exim-retiolum.nix b/krebs/3modules/exim-retiolum.nix index e1315d8c8..ea012c38c 100644 --- a/krebs/3modules/exim-retiolum.nix +++ b/krebs/3modules/exim-retiolum.nix @@ -1,14 +1,12 @@ { config, pkgs, lib, ... }: -with builtins; with lib; let cfg = config.krebs.exim-retiolum; out = { options.krebs.exim-retiolum = api; - config = - mkIf cfg.enable imp; + config = mkIf cfg.enable imp; }; api = { @@ -16,13 +14,13 @@ let }; imp = { - services.exim = - # This configuration makes only sense for retiolum-enabled hosts. - # TODO modular configuration - assert config.krebs.retiolum.enable; - { - enable = true; - config = '' + services.exim = { + enable = true; + config = + # This configuration makes only sense for retiolum-enabled hosts. + # TODO modular configuration + assert config.krebs.retiolum.enable; + '' primary_hostname = ${retiolumHostname} domainlist local_domains = @ : localhost domainlist relay_to_domains = *.retiolum @@ -134,7 +132,7 @@ let begin authenticators ''; - }; + }; }; # TODO get the hostname from somewhere else. diff --git a/krebs/3modules/fetchWallpaper.nix b/krebs/3modules/fetchWallpaper.nix index 83ecf4177..f320c7505 100644 --- a/krebs/3modules/fetchWallpaper.nix +++ b/krebs/3modules/fetchWallpaper.nix @@ -51,7 +51,7 @@ let imp = { users.users.fetchWallpaper = { name = "fetchWallpaper"; - uid = 3332383611; #genid fetchWallpaper + uid = genid "fetchWallpaper"; description = "fetchWallpaper user"; home = cfg.stateDir; createHome = true; diff --git a/krebs/3modules/git.nix b/krebs/3modules/git.nix index 234129497..e6267d7e6 100644 --- a/krebs/3modules/git.nix +++ b/krebs/3modules/git.nix @@ -145,14 +145,14 @@ let ]) (filter (x: hasAttr "allow-receive-ref" x.perm) cfg.rules)); }; - users.extraUsers = singleton { + users.extraUsers = singleton rec { description = "Git repository hosting user"; name = "git"; shell = "/bin/sh"; openssh.authorizedKeys.keys = mapAttrsToList (_: makeAuthorizedKey git-ssh-command) config.krebs.users; - uid = 129318403; # genid git + uid = genid name; }; }; @@ -238,9 +238,9 @@ let }; }; - fcgitwrap-user = { + fcgitwrap-user = rec { name = "fcgiwrap"; - uid = 2867890860; # genid fcgiwrap + uid = genid name; group = "fcgiwrap"; }; diff --git a/krebs/3modules/github-hosts-sync.nix b/krebs/3modules/github-hosts-sync.nix index 5503ee8d6..2aa18d53a 100644 --- a/krebs/3modules/github-hosts-sync.nix +++ b/krebs/3modules/github-hosts-sync.nix @@ -56,9 +56,9 @@ let }; }; - user = { + user = rec { name = "github-hosts-sync"; - uid = 3220554646; # genid github-hosts-sync + uid = genid name; }; # TODO move to lib? diff --git a/krebs/3modules/go.nix b/krebs/3modules/go.nix index 793d1f60d..08a93dab7 100644 --- a/krebs/3modules/go.nix +++ b/krebs/3modules/go.nix @@ -1,6 +1,5 @@ { config, lib, pkgs, ... }: -with builtins; with lib; let @@ -31,9 +30,9 @@ let bind = mkDefault "127.0.0.1"; }; - users.extraUsers.go = { + users.extraUsers.go = rec { name = "go"; - uid = 42774411; #genid go + uid = genid name; description = "go url shortener user"; home = "/var/lib/go"; createHome = true; diff --git a/krebs/3modules/makefu/default.nix b/krebs/3modules/makefu/default.nix index 1970a0777..31516d591 100644 --- a/krebs/3modules/makefu/default.nix +++ b/krebs/3modules/makefu/default.nix @@ -83,6 +83,9 @@ with lib; ''; }; }; + ssh.privkey.path = <secrets/ssh_host_ed25519_key>; + ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHDM0E608d/6rGzXqGbNSuMb2RlCojCJSiiz6QcPOC2G root@pornocauster"; + }; vbob = { @@ -108,6 +111,8 @@ with lib; ''; }; }; + ssh.privkey.path = <secrets/ssh_host_ed25519_key>; + ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICPLTMl+thSq77cjYa2XF7lz5fA7JMftrLo8Dy/OBXSg root@nixos"; }; flap = rec { cores = 1; @@ -238,6 +243,8 @@ with lib; ''; }; }; + ssh.privkey.path = <secrets/ssh_host_ed25519_key>; + ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4Tjx9qK6uWtxT1HCpeC0XvDZKO/kaPygyKatpAqU6I root@wry"; }; filepimp = rec { cores = 1; @@ -287,6 +294,8 @@ with lib; ''; }; }; + ssh.privkey.path = <secrets/ssh_host_ed25519_key>; + ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIujMZ3ZFxKpWeB/cjfKfYRr77+VRZk0Eik+92t03NoA root@servarch"; }; gum = rec { cores = 1; @@ -327,6 +336,8 @@ with lib; ''; }; }; + ssh.privkey.path = <secrets/ssh_host_ed25519_key>; + ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIcxWFEPzke/Sdd9qNX6rSJgXal8NmINYajpFCxXfYdj root@gum"; }; }; users = addNames rec { diff --git a/krebs/3modules/realwallpaper.nix b/krebs/3modules/realwallpaper.nix index 7e02538f5..b377368f7 100644 --- a/krebs/3modules/realwallpaper.nix +++ b/krebs/3modules/realwallpaper.nix @@ -1,13 +1,7 @@ arg@{ config, lib, pkgs, ... }: +with lib; let - inherit (lib) - mkEnableOption - mkOption - types - mkIf - ; - cfg = config.krebs.realwallpaper; out = { @@ -89,7 +83,7 @@ let }; users.extraUsers.realwallpaper = { - uid = 2009435407; #genid realwallpaper + uid = genid "realwallpaper"; home = cfg.workingDir; createHome = true; }; diff --git a/krebs/3modules/retiolum.nix b/krebs/3modules/retiolum.nix index 28ac67306..e0e2692a8 100644 --- a/krebs/3modules/retiolum.nix +++ b/krebs/3modules/retiolum.nix @@ -133,9 +133,9 @@ let }; }; - user = { + user = rec { name = "retiolum"; - uid = 301281149; # genid retiolum + uid = genid name; }; tinc = cfg.tincPackage; diff --git a/krebs/3modules/shared/default.nix b/krebs/3modules/shared/default.nix index b332676c6..518e46587 100644 --- a/krebs/3modules/shared/default.nix +++ b/krebs/3modules/shared/default.nix @@ -7,6 +7,7 @@ let "test-arch" "test-centos6" "test-centos7" + "test-all-krebs-modules" ] (name: { inherit name; cores = 1; diff --git a/krebs/3modules/tinc_graphs.nix b/krebs/3modules/tinc_graphs.nix index ba81dd416..1f32c2e59 100644 --- a/krebs/3modules/tinc_graphs.nix +++ b/krebs/3modules/tinc_graphs.nix @@ -120,7 +120,7 @@ let }; users.extraUsers.tinc_graphs = { - uid = 3925439960; #genid tinc_graphs + uid = genid "tinc_graphs"; home = "/var/spool/tinc_graphs"; }; diff --git a/krebs/3modules/urlwatch.nix b/krebs/3modules/urlwatch.nix index 206bc5697..31cbfcf6e 100644 --- a/krebs/3modules/urlwatch.nix +++ b/krebs/3modules/urlwatch.nix @@ -5,7 +5,6 @@ # cache = url: "${cfg.dataDir}/.urlwatch/cache/${hashString "sha1" url}" # TODO hooks.py -with builtins; with lib; let cfg = config.krebs.urlwatch; @@ -136,9 +135,9 @@ let }; }; - user = { + user = rec { name = "urlwatch"; - uid = 3467631196; # genid urlwatch + uid = genid name; }; in out diff --git a/krebs/4lib/default.nix b/krebs/4lib/default.nix index 1cabeae27..dfc51bbe4 100644 --- a/krebs/4lib/default.nix +++ b/krebs/4lib/default.nix @@ -7,6 +7,8 @@ let out = rec { eq = x: y: x == y; + mod = x: y: x - y * (x / y); + addName = name: set: set // { inherit name; }; @@ -17,6 +19,7 @@ let out = rec { dir.has-default-nix = path: pathExists (path + "/default.nix"); dns = import ./dns.nix { inherit lib; }; + genid = import ./genid.nix { lib = lib // out; }; git = import ./git.nix { lib = lib // out; }; listset = import ./listset.nix { inherit lib; }; shell = import ./shell.nix { inherit lib; }; diff --git a/krebs/4lib/genid.nix b/krebs/4lib/genid.nix new file mode 100644 index 000000000..0aed1d351 --- /dev/null +++ b/krebs/4lib/genid.nix @@ -0,0 +1,37 @@ +{ lib, ... }: +with lib; +with builtins; +let out = genid; + + # id = genid s = (hash s + min) % max + # min <= genid s < max + # + # min = 2^24 = 16777216 = 0x001000000 + # max = 2^32 = 4294967296 = 0x100000000 + # + # id is bigger than UID of nobody and GID of nogroup + # see <nixos/modules/misc/ids.nix> and some spare for stuff like lxd. + # + # :: str -> uint32 + genid = s: sum16 (addmod16_16777216 (hash s)); + + # :: str -> list8 uint4 + hash = s: + map hexint (stringToCharacters (substring 32 8 (hashString "sha1" s))); + + # :: list uint -> uint + sum16 = foldl (a: i: a * 16 + i) 0; + + # :: list8 uint4 -> list1 uint8 ++ list6 uint4 + addmod16_16777216 = x: let + a = 16 * head x + head (tail x); + d = tail (tail x); + in [(mod (a + 1) 256)] ++ d; + + # :: char -> uint4 + hexint = x: hexvals.${toLower x}; + + # :: attrset char uint4 + hexvals = listToAttrs (imap (i: c: { name = c; value = i - 1; }) + (stringToCharacters "0123456789abcdef")); +in out diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix index c52afa246..81ce659bd 100644 --- a/krebs/4lib/types.nix +++ b/krebs/4lib/types.nix @@ -177,4 +177,21 @@ types // rec { addr6 = str; hostname = str; label = str; + + krebs.file-location = types.submodule { + options = { + # TODO user + host = mkOption { + type = host; + }; + # TODO merge with ssl.privkey.path + path = mkOption { + type = types.either types.path types.str; + apply = x: { + path = toString x; + string = x; + }.${typeOf x}; + }; + }; + }; } diff --git a/krebs/5pkgs/Reaktor/plugins.nix b/krebs/5pkgs/Reaktor/plugins.nix new file mode 100644 index 000000000..7490be4ca --- /dev/null +++ b/krebs/5pkgs/Reaktor/plugins.nix @@ -0,0 +1,120 @@ +{ stdenv, lib, pkgs, makeWrapper }: + +rec { + # Begin API + buildBaseReaktorPlugin = { name + , config # python extra configuration for plugin + , phases ? [] + , ... } @ attrs: + stdenv.mkDerivation (attrs // { + name = "Reaktor-plugin-" + name; + isReaktorPlugin = true; + }); + + buildSimpleReaktorPlugin = name: { script + , path ? [] + , env ? {} + , append_rule ? false # append the rule instead of insert + , pattern ? "" + , ... } @ attrs: + let + path_env = { "PATH" = lib.makeSearchPath "bin" (path ++ [ pkgs.coreutils ]); }; + src_dir = pkgs.substituteAll ( { + inherit name; + dir = "bin"; + isExecutable = true; + src = script; + }); + src_file = "${src_dir}/bin/${name}"; + config = '' + public_commands.${if append_rule then "append(" else "insert(0," }{ + 'capname' : "${name}", + 'pattern' : ${if pattern == "" then + ''indirect_pattern.format("${name}")'' else + ''"${pattern}"'' }, + 'argv' : ["${src_file}"], + 'env' : ${builtins.toJSON (path_env // env)} }) + ''; + config_file = pkgs.writeText "plugin.py" config; + in buildBaseReaktorPlugin (attrs // rec { + inherit name config; + + phases = [ "installPhase" ]; + buildInputs = [ makeWrapper ]; + installPhase = '' + mkdir -p $out/bin $out/etc/Reaktor + ln -s ${src_file} $out/bin + wrapProgram $out/bin/${name} \ + --prefix PATH : ${path_env.PATH} + ln -s ${config_file} $out/etc/Reaktor/plugin.py + ''; + + }); + # End API + + # Begin Plugins + random-emoji = buildSimpleReaktorPlugin "emoji" { + path = with pkgs; [ gnused gnugrep xmlstarlet curl ]; + script = ./scripts/random-emoji.sh; + }; + + sed-plugin = buildSimpleReaktorPlugin "sed-plugin" { + path = [ pkgs.gnused pkgs.python3 ]; + # only support s///gi the plugin needs to see every msg + # TODO: this will eat up the last regex, fix Reaktor to support fallthru + append_rule = true; + pattern = "^(?P<args>.*)$$"; + script = ./scripts/sed-plugin.py; + }; + + shack-correct = buildSimpleReaktorPlugin "shack-correct" { + path = [ pkgs.gnused ]; + pattern = "^(?P<args>.*Shack.*)$$"; + script = ./scripts/shack-correct.sh; + }; + + nixos-version = buildSimpleReaktorPlugin "nixos-version" { + script = pkgs.writeScript "nixos-version" '' + #! /bin/sh + . /etc/os-release + echo "$PRETTY_NAME" + ''; + }; + stockholm-issue = buildSimpleReaktorPlugin "stockholm-issue" { + script = ./scripts/random-issue.sh; + path = with pkgs; [ git gnused lentil ]; + env = { "origin" = "http://cgit.gum/stockholm"; }; + }; + + titlebot = + let + pypkgs = pkgs.python3Packages; + titlebot_cmds = pypkgs.buildPythonPackage { + name = "titlebot_cmds"; + propagatedBuildInputs = with pypkgs; [ setuptools ]; + src = pkgs.fetchurl { + url = "https://github.com/makefu/reaktor-titlebot/archive/2.1.0.tar.gz"; + sha256 = "0wvf09wmk8b52f9j65qrw81nwrhs9pfhijwrlkzp5l7l2q8cjkp6"; + }; + }; + in buildBaseReaktorPlugin rec { + name = "titlebot"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out + ln -s ${titlebot_cmds}/* $out + ''; + config = '' + def titlebot_cmd(cmd): + from os import environ + return { 'capname': None, + 'env': { 'TITLEDB': + environ['state_dir']+'/suggestions.json' }, + 'pattern': '^\\.' + cmd + '\\s*(?:\\s+(?P<args>.*))?$$', + 'argv': [ '${titlebot_cmds}/bin/' + cmd ] } + for i in ['up','help','list','top','new']: + public_commands.insert(0,titlebot_cmd(i)) + commands.insert(0,titlebot_cmd('clear')) + ''; + }; +} diff --git a/krebs/5pkgs/Reaktor/scripts/random-emoji.sh b/krebs/5pkgs/Reaktor/scripts/random-emoji.sh new file mode 100644 index 000000000..386aa68b9 --- /dev/null +++ b/krebs/5pkgs/Reaktor/scripts/random-emoji.sh @@ -0,0 +1,6 @@ +#!/bin/sh +curl http://emojicons.com/random -s | \ + grep data-text | \ + sed -n 's/.*>\(.*\)<\/textarea>/\1/p' | \ + head -n 1 | \ + xmlstarlet unesc diff --git a/krebs/5pkgs/Reaktor/scripts/random-issue.sh b/krebs/5pkgs/Reaktor/scripts/random-issue.sh new file mode 100644 index 000000000..5c47c6156 --- /dev/null +++ b/krebs/5pkgs/Reaktor/scripts/random-issue.sh @@ -0,0 +1,20 @@ +#! /bin/sh +set -eu +# requires env: +# $state_dir +# $origin + +# in PATH: git,lentil,coreutils +subdir=`echo "$1" | tr -dc "[:alnum:]"` +name=`echo "$origin" | tr -dc "[:alnum:]"` +track="$state_dir/$name-checkout" +(if test -e "$track" ;then + cd "$track" + git fetch origin master + git reset --hard origin/master +else + git clone "$origin" "$track" +fi) >&2 + +cd "$track" +lentil "${subdir:-.}" -f csv | sed 1d | shuf | head -1 diff --git a/krebs/5pkgs/Reaktor/scripts/sed-plugin.py b/krebs/5pkgs/Reaktor/scripts/sed-plugin.py new file mode 100644 index 000000000..8103c9585 --- /dev/null +++ b/krebs/5pkgs/Reaktor/scripts/sed-plugin.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +# Usage: +# _from=krebs state_dir=. python sed-plugin.py 'dick butt' +# _from=krebs state_dir=. python sed-plugin.py 's/t/l/g' +## dick bull +import shelve +from os import environ +from os.path import join +from sys import argv +d = shelve.open(join(environ['state_dir'],'sed-plugin.shelve'),writeback=True) +usr = environ['_from'] +import re + +def is_regex(line): + myre = re.compile(r'^s/((?:\\/|[^/])+)/((?:\\/|[^/])*)/([ig]*)$') + return myre.match(line) + +line = argv[1] +m = is_regex(line) + +if m: + f,t,flagstr = m.groups() + fn = f.replace('\/','/') + tn = t.replace('\/','/') + flags = 0 + count = 1 + if flagstr: + if 'i' in flagstr: + flags = re.IGNORECASE + if 'g' in flagstr: + count = 0 + else: + flagstr = '' + last = d.get(usr,None) + if last: + #print(re.sub(fn,tn,last,count=count,flags=flags)) + from subprocess import Popen,PIPE + p = Popen(['sed','s/{}/{}/{}'.format(f,t,flagstr)],stdin=PIPE,stdout=PIPE ) + so,se = p.communicate(bytes("{}\n".format(last),"UTF-8")) + if p.returncode: + print("something went wrong when trying to process your regex: {}".format(se.decode())) + ret = so.decode() + print("\x1b[1m{}\x1b[0m meinte: {}".format(usr,ret.strip())) + if ret: + d[usr] = ret + + else: + print("no last message") +else: + d[usr] = line + +d.close() diff --git a/krebs/5pkgs/Reaktor/scripts/shack-correct.sh b/krebs/5pkgs/Reaktor/scripts/shack-correct.sh new file mode 100644 index 000000000..3b4d04f80 --- /dev/null +++ b/krebs/5pkgs/Reaktor/scripts/shack-correct.sh @@ -0,0 +1,6 @@ +#! /bin/sh +set -eu +printf "Sie meinten wohl \"" +echo -n $@ | sed 's/Shack/shack/g' +echo "\"" +echo "${_from}--" diff --git a/krebs/5pkgs/cacpanel/default.nix b/krebs/5pkgs/cacpanel/default.nix index 3e3e2e1fc..3df4dffed 100644 --- a/krebs/5pkgs/cacpanel/default.nix +++ b/krebs/5pkgs/cacpanel/default.nix @@ -2,11 +2,11 @@ python3Packages.buildPythonPackage rec { name = "cacpanel-${version}"; - version = "0.2.1"; + version = "0.2.3"; src = pkgs.fetchurl { url = "https://pypi.python.org/packages/source/c/cacpanel/cacpanel-${version}.tar.gz"; - sha256 = "1zaazg5r10kgva32zh4fhpw6l6h51ijkwpa322na0kh4x6f6aqj3"; + sha256 = "1fib7416qqv8yzrj75kxra7ccpz9abqh58b6gkaavws2fa6m3mm8"; }; propagatedBuildInputs = with python3Packages; [ diff --git a/krebs/5pkgs/default.nix b/krebs/5pkgs/default.nix index 7df7b7d3c..c4b1dafe4 100644 --- a/krebs/5pkgs/default.nix +++ b/krebs/5pkgs/default.nix @@ -26,6 +26,8 @@ subdirs // rec { inherit (subdirs) get jq; }; + ReaktorPlugins = pkgs.callPackage ./Reaktor/plugins.nix {}; + execve = name: { filename, argv, envp ? {}, destination ? "" }: writeC name { inherit destination; } '' #include <unistd.h> @@ -40,6 +42,10 @@ subdirs // rec { } ''; + test = { + infest-cac-centos7 = pkgs.callPackage ./test/infest-cac-centos7 {}; + }; + execveBin = name: cfg: execve name (cfg // { destination = "/bin/${name}"; }); writeC = name: { destination ? "" }: src: pkgs.runCommand name {} '' diff --git a/krebs/5pkgs/genid/default.nix b/krebs/5pkgs/genid/default.nix deleted file mode 100644 index c75bec317..000000000 --- a/krebs/5pkgs/genid/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ lib, pkgs, ... }: - -pkgs.writeScriptBin "genid" '' - #! /bin/sh - # usage: genid NAME - set -euf - - export PATH=${lib.makeSearchPath "bin" (with pkgs; [ - bc - coreutils - ])} - - name=$1 - hash=$(printf %s "$name" | sha1sum | cut -d\ -f1 | tr a-f A-F) - echo " - min=2^24 # bigger than nobody and nogroup, see <nixos/modules/misc/ids.nix> - # and some spare for stuff like lxd. - max=2^32 # see 2^(8*sizeof(uid_t)) - ibase=16 - ($hash + min) % max - " | bc -'' diff --git a/krebs/5pkgs/krebszones/default.nix b/krebs/5pkgs/krebszones/default.nix index f6fd672dc..9230192bd 100644 --- a/krebs/5pkgs/krebszones/default.nix +++ b/krebs/5pkgs/krebszones/default.nix @@ -1,5 +1,10 @@ { lib, pkgs,python3Packages,fetchurl, ... }: +# TODO: Prepare a diff of future and current +## ovh-zone export krebsco.de --config ~/secrets/krebs/cfg.json |sed 's/[ ]\+/ /g' | sort current +## sed 's/[ ]\+/ /g'/etc/zones/krebsco.de | sort > future +## diff future.sorted current.sorted + python3Packages.buildPythonPackage rec { name = "krebszones-${version}"; version = "0.4.4"; diff --git a/krebs/5pkgs/snapraid/default.nix b/krebs/5pkgs/snapraid/default.nix deleted file mode 100644 index 41db0f284..000000000 --- a/krebs/5pkgs/snapraid/default.nix +++ /dev/null @@ -1,33 +0,0 @@ -{stdenv, fetchurl}: -let - s = # Generated upstream information - rec { - baseName="jq"; - version="1.5"; - name="${baseName}-${version}"; - url=https://github.com/stedolan/jq/releases/download/jq-1.5/jq-1.5.tar.gz; - sha256="0g29kyz4ykasdcrb0zmbrp2jqs9kv1wz9swx849i2d1ncknbzln4"; - }; - buildInputs = [ - ]; -in -stdenv.mkDerivation { - inherit (s) name version; - inherit buildInputs; - src = fetchurl { - inherit (s) url sha256; - }; - - # jq is linked to libjq: - configureFlags = [ - "LDFLAGS=-Wl,-rpath,\\\${libdir}" - ]; - meta = { - inherit (s) version; - description = ''A lightweight and flexible command-line JSON processor''; - license = stdenv.lib.licenses.mit ; - maintainers = [stdenv.lib.maintainers.raskin]; - platforms = stdenv.lib.platforms.linux ++ stdenv.lib.platforms.darwin; - }; -} - diff --git a/krebs/5pkgs/krebs-ci/default.nix b/krebs/5pkgs/test/infest-cac-centos7/default.nix index f5b302b52..7f2e3f231 100644 --- a/krebs/5pkgs/krebs-ci/default.nix +++ b/krebs/5pkgs/test/infest-cac-centos7/default.nix @@ -1,7 +1,9 @@ { stdenv, coreutils,makeWrapper, cac, cacpanel, gnumake, gnused, jq, openssh, ... }: stdenv.mkDerivation rec { - name = "krebs-ci-0.1.0"; + name = "${shortname}-${version}"; + shortname = "infest-cac-centos7"; + version = "0.2.0"; src = ./notes; @@ -23,9 +25,9 @@ stdenv.mkDerivation rec { installPhase = '' mkdir -p $out/bin - cp ${src} $out/bin/krebs-ci - chmod +x $out/bin/krebs-ci - wrapProgram $out/bin/krebs-ci \ + cp ${src} $out/bin/${shortname} + chmod +x $out/bin/${shortname} + wrapProgram $out/bin/${shortname} \ --prefix PATH : ${path} ''; meta = with stdenv.lib; { diff --git a/krebs/5pkgs/krebs-ci/notes b/krebs/5pkgs/test/infest-cac-centos7/notes index 7e34d6a28..6bfb6906e 100755 --- a/krebs/5pkgs/krebs-ci/notes +++ b/krebs/5pkgs/test/infest-cac-centos7/notes @@ -1,12 +1,24 @@ #! /bin/sh # nix-shell -p gnumake jq openssh cac cacpanel -set -euf +set -eufx # 2 secrets are required: + krebs_cred=${krebs_cred-./cac.json} retiolum_key=${retiolum_key-./retiolum.rsa_key.priv} +clear_defer(){ + echo "${trapstr:-exit}" + trap - INT TERM EXIT KILL +} +defer(){ + if test -z "${debug:-}"; then + trapstr="$1;${trapstr:-exit}" + trap "$trapstr" INT TERM EXIT KILL + fi +} + # Sanity if test ! -r "$krebs_cred";then echo "\$krebs_cred=$krebs_cred must be readable"; exit 1 @@ -18,46 +30,73 @@ fi krebs_secrets=$(mktemp -d) sec_file=$krebs_secrets/cac_config krebs_ssh=$krebs_secrets/tempssh +export cac_resources_cache=$krebs_secrets/res_cache.json +export cac_servers_cache=$krebs_secrets/servers_cache.json +export cac_tasks_cache=$krebs_secrets/tasks_cache.json +export cac_templates_cache=$krebs_secrets/templates_cache.json # we need to receive this key from buildmaster to speed up tinc bootstrap -TRAP="rm $sec_file;rm -r $krebs_secrets" -trap "$TRAP" INT TERM EXIT +defer "trap - INT TERM EXIT" +defer "rm -r $krebs_secrets" cat > $sec_file <<EOF cac_login="$(jq -r .email $krebs_cred)" -cac_key="$(cac-cli panel --config $krebs_cred settings | jq -r .apicode)" +cac_key="$(cac-cli --config $krebs_cred panel settings | jq -r .apicode)" EOF export cac_secrets=$sec_file -cac-cli panel --config $krebs_cred update-api-ip +cac-cli --config $krebs_cred panel add-api-ip # test login: cac update cac servers -# Template 26: CentOS7 -# TODO: use cac templates to determine the real Centos7 template in case it changes -name=$( cac build cpu=1 ram=512 storage=10 os=26 2>&1\ - | jq -r .servername) +# preserve old trap +old_trapstr=$(clear_defer) +while true;do + # Template 26: CentOS7 + # TODO: use cac templates to determine the real Centos7 template in case it changes + out=$(cac build cpu=1 ram=512 storage=10 os=26 2>&1) + if name=$(echo "$out" | jq -r .servername);then + id=servername:$name + echo "got a working machine, id=$id" + else + echo "Unable to build a virtual machine, retrying in 15 seconds" >&2 + echo "Output of build program: $out" >&2 + sleep 15 + continue + fi -id=servername:$name -trap "cac delete $id;$TRAP" INT TERM EXIT -# TODO: timeout? -always_update=true cac waitstatus $id "Powered On" + clear_defer >/dev/null + defer "cac delete $id" -wait_login_cac(){ - # timeout - for t in `seq 60`;do - # now we have a working cac server - if cac ssh $1 cat /etc/redhat-release | \ - grep CentOS ;then - return 0 - fi - sleep 10 - done - return 1 -} -# die on timeout -wait_login_cac $id + # TODO: timeout? + + wait_login_cac(){ + # we wait for 30 minutes + for t in `seq 180`;do + # now we have a working cac server + if cac ssh $1 -o ConnectTimeout=10 \ + cat /etc/redhat-release | \ + grep CentOS ;then + return 0 + fi + sleep 10 + done + return 1 + } + # die on timeout + if ! wait_login_cac $id;then + echo "unable to boot a working system within time frame, retrying..." >&2 + echo "Cleaning up old image,last status: $(cac update;cac getserver $id | jq -r .status)" + eval "$(clear_defer | sed 's/;exit//')" + sleep 15 + else + echo "got a working system" >&2 + break + fi +done +clear_defer >/dev/null +defer "cac delete $id;$old_trapstr" mkdir -p shared/2configs/temp cac generatenetworking $id > \ @@ -94,7 +133,7 @@ cac powerop $id reset wait_login(){ # timeout - for t in `seq 20`;do + for t in `seq 90`;do # now we have a working cac server if ssh -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ diff --git a/krebs/Zhosts/bobby b/krebs/Zhosts/bobby new file mode 100644 index 000000000..aac6e377b --- /dev/null +++ b/krebs/Zhosts/bobby @@ -0,0 +1,11 @@ +Subnet = 10.243.111.112/32 +Subnet = 42:0:0:0:0:0:111:112/128 + +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEA+AScnIqFdzGl+iRZTNZ7r91n/r1H4GzDsrAupUvJ4mi7nDN4eP8s +uLvKtJp22RxfuF3Kf4KhHb8LHQ8bLLN/KDaNDXrCNBc69d7vvLsjoY+wfGLJNu4Y +Ad/8J4r3rdb83mTA3IHb47T/70MERPBr2gF84YiG6ZoQrPQuTk4lHxaI83SOhjny +0F0ucS/rBV6Vv9y5/756TKi1cFPSpY4X+qeWc8xWrBGJcJiiqYb8ZX2o/lkAJ5c+ +jI/VdybGFVGY9+bp4Jw5xBIo5KGuFnm8+blRmSDDl3joRneKQSx9FAu7RUwoajBu +cEbi1529NReQzIFT6Vt22ymbHftxOiuh4QIDAQAB +-----END RSA PUBLIC KEY----- diff --git a/krebs/Zhosts/kebsco b/krebs/Zhosts/kebsco new file mode 100644 index 000000000..2fd1c5f42 --- /dev/null +++ b/krebs/Zhosts/kebsco @@ -0,0 +1,11 @@ +Subnet = 10.243.212.68 +Subnet = 42:9d30:3845:c822:988b:96c5:39ab:90b7 + +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEA0dEwTZh2uzJpP9GL7YRyiLuezJqYiJ8/4Bl4IPshJnuO9IGbEcto +0cFm9uM9gxxqggfaCi96DsIQNlyqff2vDfEj3mdIu9T3tkRROByQF8y1NWX29NyH +zZEX8Ri8u4U2KdYTEzPXEFxBEl0GQX9mMtlvwzCq7V4ueCcWB1xDA+DtJjpd894z +3FOw0rIxYmfYhLAL5B3rzF74bcHFGV30f4JWq11wLBkyR6/Q5gxgZzkKYGwdZ/SN +C6gg86abKdp65/Wq5P331IbwPBal1ZhGbaAo1y7JpjpLvZytI2jboXeQuPZ8P5hU +L3zKKceAibPKrw9+y8lb+IKoYLF7I1KYIwIDAQAB +-----END RSA PUBLIC KEY----- diff --git a/krebs/default.nix b/krebs/default.nix index ad0205426..15d0e8e2e 100644 --- a/krebs/default.nix +++ b/krebs/default.nix @@ -36,6 +36,7 @@ let out = { { system ? current-host-name , target ? system }@args: let + config = get-config system; in '' #! /bin/sh # ${current-date} ${current-user-name}@${current-host-name} @@ -47,6 +48,9 @@ let out = { ${builtins.readFile ./4lib/infest/install-nix.sh} ''} + # Prepare target source via bind-mounting + + (${nixos-install args}) ${rootssh target '' @@ -98,7 +102,7 @@ let out = { #! /bin/sh # ${current-date} ${current-user-name}@${current-host-name} # krebs.nixos-install - (${populate args}) + (${populate (args // { root = "/mnt"; })}) ${rootssh target '' export PATH; PATH=/root/.nix-profile/bin:$PATH @@ -205,6 +209,7 @@ let out = { populate = { system ? current-host-name , target ? system + , root ? "" }@args: let out = '' #! /bin/sh @@ -217,6 +222,7 @@ let out = { ["dir" "git"])} ''; + config = get-config system; current-host = config.krebs.hosts.${current-host-name}; @@ -225,17 +231,18 @@ let out = { methods.dir = config: let can-push = config.host.name == current-host.name; + target-path = root + config.target-path; push-method = '' rsync \ --exclude .git \ --exclude .graveyard \ --exclude old \ --exclude tmp \ - --rsync-path='mkdir -p ${config.target-path} && rsync' \ + --rsync-path='mkdir -p ${target-path} && rsync' \ --delete-excluded \ -vrLptgoD \ ${config.path}/ \ - root@${target}:${config.target-path} + root@${target}:${target-path} ''; in if can-push then push-method else @@ -244,9 +251,10 @@ let out = { throw "No way to push ${dir} from ${current-host.name} to ${target}"; methods.git = config: - rootssh target '' - mkdir -p ${config.target-path} - cd ${config.target-path} + let target-path = root + config.target-path; + in rootssh target '' + mkdir -p ${target-path} + cd ${target-path} if ! test -e .git; then git init fi |