Commit 0ec13cdb authored by WxNzEMof's avatar WxNzEMof
Browse files

streamLayeredImage: Allow customizing ownership

This opens the way towards building images where Nix can be used as an
unprivileged user (in single-user mode).
parent fcea2b62
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -907,6 +907,11 @@ rec {
    , # Time of creation of the image. Passing "now" will make the
      # created date be the time of building.
      created ? "1970-01-01T00:00:01Z"
    , # Credentials for file ownership.
      uid ? 0
    , gid ? 0
    , uname ? "root"
    , gname ? "root"
    , # Optional bash script to run on the files prior to fixturizing the layer.
      extraCommands ? ""
    , # Optional bash script to run inside fakeroot environment.
@@ -1007,7 +1012,7 @@ rec {

        conf = runCommand "${baseName}-conf.json"
          {
            inherit fromImage maxLayers created;
            inherit fromImage maxLayers created uid gid uname gname;
            imageName = lib.toLower name;
            preferLocalBuild = true;
            passthru.imageTag =
@@ -1086,14 +1091,22 @@ rec {
              "store_layers": $store_layers[0],
              "customisation_layer", $customisation_layer,
              "repo_tag": $repo_tag,
              "created": $created
              "created": $created,
              "uid": $uid,
              "gid": $gid,
              "uname": $uname,
              "gname": $gname
            }
            ' --arg store_dir "${storeDir}" \
              --argjson from_image ${if fromImage == null then "null" else "'\"${fromImage}\"'"} \
              --slurpfile store_layers store_layers.json \
              --arg customisation_layer ${customisationLayer} \
              --arg repo_tag "$imageName:$imageTag" \
              --arg created "$created" |
              --arg created "$created" \
              --arg uid "$uid" \
              --arg gid "$gid" \
              --arg uname "$uname" \
              --arg gname "$gname" |
            tee $out
        '';

+16 −9
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@ image as an uncompressed tarball to stdout:
  the fields with the same name on the image spec [2].
* "created" can be "now".
* "created" is also used as mtime for files added to the image.
* "uid", "gid", "uname", "gname" is the file ownership, for example,
  0, 0, "root", "root".
* "store_layers" is a list of layers in ascending order, where each
  layer is the list of store paths to include in that layer.

@@ -45,7 +47,7 @@ from datetime import datetime, timezone
from collections import namedtuple


def archive_paths_to(obj, paths, mtime):
def archive_paths_to(obj, paths, mtime, uid, gid, uname, gname):
    """
    Writes the given store paths as a tar file to the given stream.

@@ -61,10 +63,10 @@ def archive_paths_to(obj, paths, mtime):

    def apply_filters(ti):
        ti.mtime = mtime
        ti.uid = 0
        ti.gid = 0
        ti.uname = "root"
        ti.gname = "root"
        ti.uid = uid
        ti.gid = gid
        ti.uname = uname
        ti.gname = gname
        return ti

    def nix_root(ti):
@@ -208,7 +210,7 @@ def overlay_base_config(from_image, final_config):
    return final_config


def add_layer_dir(tar, paths, store_dir, mtime):
def add_layer_dir(tar, paths, store_dir, mtime, uid, gid, uname, gname):
    """
    Appends given store paths to a TarFile object as a new layer.

@@ -231,7 +233,7 @@ def add_layer_dir(tar, paths, store_dir, mtime):
    archive_paths_to(
        extract_checksum,
        paths,
        mtime=mtime,
        mtime, uid, gid, uname, gname
    )
    (checksum, size) = extract_checksum.extract()

@@ -247,7 +249,7 @@ def add_layer_dir(tar, paths, store_dir, mtime):
            archive_paths_to(
                write,
                paths,
                mtime=mtime,
                mtime, uid, gid, uname, gname
            )
            write.close()

@@ -324,6 +326,10 @@ def main():
      else datetime.fromisoformat(conf["created"])
    )
    mtime = int(created.timestamp())
    uid = int(conf["uid"])
    gid = int(conf["gid"])
    uname = conf["uname"]
    gname = conf["gname"]
    store_dir = conf["store_dir"]

    from_image = load_from_image(conf["from_image"])
@@ -336,7 +342,8 @@ def main():
        for num, store_layer in enumerate(conf["store_layers"], start=start):
            print("Creating layer", num, "from paths:", store_layer,
                  file=sys.stderr)
            info = add_layer_dir(tar, store_layer, store_dir, mtime=mtime)
            info = add_layer_dir(tar, store_layer, store_dir,
                                 mtime, uid, gid, uname, gname)
            layers.append(info)

        print("Creating layer", len(layers) + 1, "with customisation...",