···11+# We provide three paths to get the credentials into the builder's
22+# environment:
33+#
44+# 1. Via impureEnvVars. This method is difficult for multi-user Nix
55+# installations (but works very well for single-user Nix
66+# installations!) because it requires setting the environment
77+# variables on the nix-daemon which is either complicated or unsafe
88+# (i.e: configuring via Nix means the secrets will be persisted
99+# into the store)
1010+#
1111+# 2. If the DOCKER_CREDENTIALS key with a path to a credentials file
1212+# is added to the NIX_PATH (usually via the '-I ' argument to most
1313+# Nix tools) then an attempt will be made to read credentials from
1414+# it. The semantics are simple, the file should contain two lines
1515+# for the username and password based authentication:
1616+#
1717+# $ cat ./credentials-file.txt
1818+# DOCKER_USER=myusername
1919+# DOCKER_PASS=mypassword
2020+#
2121+# ... and a single line for the token based authentication:
2222+#
2323+# $ cat ./credentials-file.txt
2424+# DOCKER_TOKEN=mytoken
2525+#
2626+# 3. A credential file at /etc/nix-docker-credentials.txt with the
2727+# same format as the file described in #2 can also be used to
2828+# communicate credentials to the builder. This is necessary for
2929+# situations (like Hydra) where you cannot customize the NIX_PATH
3030+# given to the nix-build invocation to provide it with the
3131+# DOCKER_CREDENTIALS path
3232+let
3333+ pathParts =
3434+ (builtins.filter
3535+ ({path, prefix}: "DOCKER_CREDENTIALS" == prefix)
3636+ builtins.nixPath);
3737+in
3838+ if (pathParts != []) then (builtins.head pathParts).path else ""
···11+source "${stdenv}/setup"
22+header "exporting ${repository}/${imageName} (tag: ${tag}) into ${out}"
33+mkdir -p "${out}"
44+55+cat <<EOF > "${out}/compositeImage.sh"
66+#! ${bash}/bin/bash
77+#
88+# Create a tar archive of a docker image's layers, docker image config
99+# json, manifest.json, and repositories json; this streams directly to
1010+# stdout and is intended to be used in concert with docker load, i.e:
1111+#
1212+# ${out}/compositeImage.sh | docker load
1313+1414+# The first character follow the 's' command for sed becomes the
1515+# delimiter sed will use; this makes the transformation regex easy to
1616+# read. We feed tar a file listing the files we want in the archive,
1717+# because the paths are absolute and docker load wants them flattened in
1818+# the archive, we need to transform all of the paths going in by
1919+# stripping everything *including* the last solidus so that we end up
2020+# with the basename of the path.
2121+${gnutar}/bin/tar \
2222+ --transform='s=.*/==' \
2323+ --transform="s=.*-manifest.json=manifest.json=" \
2424+ --transform="s=.*-repositories=repositories=" \
2525+ -c "${manifest}" "${repositories}" -T "${imageFileStorePaths}"
2626+EOF
2727+chmod +x "${out}/compositeImage.sh"
2828+stopNest
···11+{ stdenv, lib, haskellPackages, writeText, gawk }:
22+let
33+ awk = "${gawk}/bin/awk";
44+ dockerCredentialsFile = import ./credentials.nix;
55+ stripScheme =
66+ builtins.replaceStrings [ "https://" "http://" ] [ "" "" ];
77+in
88+{ fetcher
99+, name
1010+ , registry ? "https://registry-1.docker.io/v2/"
1111+ , repository ? "library"
1212+ , imageName
1313+ , sha256
1414+ , tag ? ""
1515+ , layerDigest ? ""
1616+}:
1717+1818+# There must be no slashes in the repository or container names since
1919+# we use these to make the output derivation name for the nix store
2020+# path
2121+assert null == lib.findFirst (c: "/"==c) null (lib.stringToCharacters repository);
2222+assert null == lib.findFirst (c: "/"==c) null (lib.stringToCharacters imageName);
2323+2424+# Only allow hocker-config and hocker-layer as fetchers for now
2525+assert (builtins.elem fetcher ["hocker-config" "hocker-layer"]);
2626+2727+# If layerDigest is non-empty then it must not have a 'sha256:' prefix!
2828+assert
2929+ (if layerDigest != ""
3030+ then !lib.hasPrefix "sha256:" layerDigest
3131+ else true);
3232+3333+let
3434+ layerDigestFlag =
3535+ lib.optionalString (layerDigest != "") "--layer ${layerDigest}";
3636+in
3737+stdenv.mkDerivation {
3838+ inherit name;
3939+ builder = writeText "${fetcher}-builder.sh" ''
4040+ source "$stdenv/setup"
4141+ header "${fetcher} exporting to $out"
4242+4343+ declare -A creds
4444+4545+ # This is a hack for Hydra since we have no way of adding values
4646+ # to the NIX_PATH for Hydra jobsets!!
4747+ staticCredentialsFile="/etc/nix-docker-credentials.txt"
4848+ if [ ! -f "$dockerCredentialsFile" -a -f "$staticCredentialsFile" ]; then
4949+ echo "credentials file not set, falling back on static credentials file at: $staticCredentialsFile"
5050+ dockerCredentialsFile=$staticCredentialsFile
5151+ fi
5252+5353+ if [ -f "$dockerCredentialsFile" ]; then
5454+ header "using credentials from $dockerCredentialsFile"
5555+5656+ CREDSFILE=$(cat "$dockerCredentialsFile")
5757+ creds[token]=$(${awk} -F'=' '/DOCKER_TOKEN/ {print $2}' <<< "$CREDSFILE" | head -n1)
5858+5959+ # Prefer DOCKER_TOKEN over the username and password
6060+ # authentication method
6161+ if [ -z "''${creds[token]}" ]; then
6262+ creds[user]=$(${awk} -F'=' '/DOCKER_USER/ {print $2}' <<< "$CREDSFILE" | head -n1)
6363+ creds[pass]=$(${awk} -F'=' '/DOCKER_PASS/ {print $2}' <<< "$CREDSFILE" | head -n1)
6464+ fi
6565+ fi
6666+6767+ # These variables will be filled in first by the impureEnvVars, if
6868+ # those variables are empty then they will default to the
6969+ # credentials that may have been read in from the 'DOCKER_CREDENTIALS'
7070+ DOCKER_USER="''${DOCKER_USER:-''${creds[user]}}"
7171+ DOCKER_PASS="''${DOCKER_PASS:-''${creds[pass]}}"
7272+ DOCKER_TOKEN="''${DOCKER_TOKEN:-''${creds[token]}}"
7373+7474+ ${fetcher} --out="$out" \
7575+ ''${registry:+--registry "$registry"} \
7676+ ''${DOCKER_USER:+--username "$DOCKER_USER"} \
7777+ ''${DOCKER_PASS:+--password "$DOCKER_PASS"} \
7878+ ''${DOCKER_TOKEN:+--token "$DOCKER_TOKEN"} \
7979+ ${layerDigestFlag} \
8080+ "${repository}/${imageName}" \
8181+ "${tag}"
8282+8383+ stopNest
8484+ '';
8585+8686+ buildInputs = [ haskellPackages.hocker ];
8787+8888+ outputHashAlgo = "sha256";
8989+ outputHashMode = "flat";
9090+ outputHash = sha256;
9191+9292+ preferLocalBuild = true;
9393+9494+ impureEnvVars = [ "DOCKER_USER" "DOCKER_PASS" "DOCKER_TOKEN" ];
9595+9696+ inherit registry dockerCredentialsFile;
9797+}