summaryrefslogtreecommitdiffstats
path: root/pkgs/build-support/fetchdocker/generic-fetcher.nix
blob: 9d435231934ec86b01a2496a6c466e7395d834f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
{
  stdenv,
  lib,
  haskellPackages,
  writeText,
  gawk,
}:
let
  awk = "${gawk}/bin/awk";
  dockerCredentialsFile = import ./credentials.nix { inherit lib; };
in
{
  fetcher,
  name,
  registry ? "https://registry-1.docker.io/v2/",
  repository ? "library",
  imageName,
  sha256,
  tag ? "",
  layerDigest ? "",
}:

# There must be no slashes in the repository or container names since
# we use these to make the output derivation name for the nix store
# path
assert null == lib.findFirst (c: "/" == c) null (lib.stringToCharacters repository);
assert null == lib.findFirst (c: "/" == c) null (lib.stringToCharacters imageName);

# Only allow hocker-config and hocker-layer as fetchers for now
assert (
  builtins.elem fetcher [
    "hocker-config"
    "hocker-layer"
  ]
);

# If layerDigest is non-empty then it must not have a 'sha256:' prefix!
assert (if layerDigest != "" then !lib.hasPrefix "sha256:" layerDigest else true);

let
  layerDigestFlag = lib.optionalString (layerDigest != "") "--layer ${layerDigest}";
in
stdenv.mkDerivation {
  inherit name;
  builder = writeText "${fetcher}-builder.sh" ''
    echo "${fetcher} exporting to $out"

    declare -A creds

    # This is a hack for Hydra since we have no way of adding values
    # to the NIX_PATH for Hydra jobsets!!
    staticCredentialsFile="/etc/nix-docker-credentials.txt"
    if [ ! -f "$dockerCredentialsFile" -a -f "$staticCredentialsFile" ]; then
      echo "credentials file not set, falling back on static credentials file at: $staticCredentialsFile"
      dockerCredentialsFile=$staticCredentialsFile
    fi

    if [ -f "$dockerCredentialsFile" ]; then
      echo "using credentials from $dockerCredentialsFile"

      CREDSFILE=$(cat "$dockerCredentialsFile")
      creds[token]=$(${awk} -F'=' '/DOCKER_TOKEN/ {print $2}' <<< "$CREDSFILE" | head -n1)

      # Prefer DOCKER_TOKEN over the username and password
      # authentication method
      if [ -z "''${creds[token]}" ]; then
        creds[user]=$(${awk} -F'=' '/DOCKER_USER/  {print $2}' <<< "$CREDSFILE" | head -n1)
        creds[pass]=$(${awk} -F'=' '/DOCKER_PASS/  {print $2}' <<< "$CREDSFILE" | head -n1)
      fi
    fi

    # These variables will be filled in first by the impureEnvVars, if
    # those variables are empty then they will default to the
    # credentials that may have been read in from the 'DOCKER_CREDENTIALS'
    DOCKER_USER="''${DOCKER_USER:-''${creds[user]}}"
    DOCKER_PASS="''${DOCKER_PASS:-''${creds[pass]}}"
    DOCKER_TOKEN="''${DOCKER_TOKEN:-''${creds[token]}}"

    ${fetcher} --out="$out" \
      ''${registry:+--registry "$registry"} \
      ''${DOCKER_USER:+--username "$DOCKER_USER"} \
      ''${DOCKER_PASS:+--password "$DOCKER_PASS"} \
      ''${DOCKER_TOKEN:+--token "$DOCKER_TOKEN"} \
      ${layerDigestFlag} \
      "${repository}/${imageName}" \
      "${tag}"
  '';

  buildInputs = [ haskellPackages.hocker ];

  outputHashAlgo = "sha256";
  outputHashMode = "flat";
  outputHash = sha256;

  preferLocalBuild = true;

  impureEnvVars = [
    "DOCKER_USER"
    "DOCKER_PASS"
    "DOCKER_TOKEN"
  ];

  inherit registry dockerCredentialsFile;
}