feat(tvix/boot): support seeding closures via nar-bridge
This updates the parameters mkBootTest can be called with. It now accepts a `path`, and then either importPathName needs to be set, or isClosure needs to be set to true. The former activates the existing functionality, tvix-store import is used to import contents as a NAR-addressed store path. The latter uploads the path as a closure (so including its references, and keeping the store paths intact) to tvix-store. We use nar-bridge, and the HTTP interface it provides to do this. As `nix copy` can't be used inside a Nix build, we use `pkgs.mkBinaryCache` to come up with the .narinfo and .nar files that would be in a binary cache, and then use a bit of GNU Parallel and bash to upload store paths ourselves. Change-Id: Icfa5c0af0c22ab5418686947aa2c060f5987b873 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11188 Autosubmit: flokli <flokli@flokli.de> Reviewed-by: Connor Brewster <cbrewster@hey.com> Tested-by: BuildkiteCI
This commit is contained in:
		
							parent
							
								
									8fb1d0ad4b
								
							
						
					
					
						commit
						997b59e452
					
				
					 1 changed files with 93 additions and 36 deletions
				
			
		| 
						 | 
					@ -8,15 +8,32 @@ let
 | 
				
			||||||
    { blobServiceAddr ? "memory://"
 | 
					    { blobServiceAddr ? "memory://"
 | 
				
			||||||
    , directoryServiceAddr ? "memory://"
 | 
					    , directoryServiceAddr ? "memory://"
 | 
				
			||||||
    , pathInfoServiceAddr ? "memory://"
 | 
					    , pathInfoServiceAddr ? "memory://"
 | 
				
			||||||
      # The path to import (via tvix-store import).
 | 
					
 | 
				
			||||||
    , importPath ? ../../docs
 | 
					
 | 
				
			||||||
    , importPathName ? "docs"
 | 
					      # The path to import.
 | 
				
			||||||
 | 
					    , path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Whether the path should be imported as a closure.
 | 
				
			||||||
 | 
					      # If false, importPathName must be specified.
 | 
				
			||||||
 | 
					    , isClosure ? false
 | 
				
			||||||
 | 
					    , importPathName ? null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }:
 | 
					    }:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      assert isClosure -> importPathName == null;
 | 
				
			||||||
 | 
					      assert (!isClosure) -> importPathName != null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      pkgs.stdenv.mkDerivation {
 | 
					      pkgs.stdenv.mkDerivation {
 | 
				
			||||||
        name = "run-vm";
 | 
					        name = "run-vm";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        nativeBuildInputs = [
 | 
					        nativeBuildInputs = [
 | 
				
			||||||
          depot.tvix.store
 | 
					          depot.tvix.store
 | 
				
			||||||
          depot.tvix.boot.runVM
 | 
					          depot.tvix.boot.runVM
 | 
				
			||||||
 | 
					        ] ++ lib.optionals isClosure [
 | 
				
			||||||
 | 
					          depot.tvix.nar-bridge
 | 
				
			||||||
 | 
					          pkgs.curl
 | 
				
			||||||
 | 
					          pkgs.parallel
 | 
				
			||||||
 | 
					          pkgs.xz.bin
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        buildCommand = ''
 | 
					        buildCommand = ''
 | 
				
			||||||
          touch $out
 | 
					          touch $out
 | 
				
			||||||
| 
						 | 
					@ -25,39 +42,79 @@ let
 | 
				
			||||||
          BLOB_SERVICE_ADDR=${blobServiceAddr} \
 | 
					          BLOB_SERVICE_ADDR=${blobServiceAddr} \
 | 
				
			||||||
            DIRECTORY_SERVICE_ADDR=${directoryServiceAddr} \
 | 
					            DIRECTORY_SERVICE_ADDR=${directoryServiceAddr} \
 | 
				
			||||||
            PATH_INFO_SERVICE_ADDR=${pathInfoServiceAddr} \
 | 
					            PATH_INFO_SERVICE_ADDR=${pathInfoServiceAddr} \
 | 
				
			||||||
          tvix-store daemon -l $PWD/tvix-store.socket &
 | 
					            tvix-store daemon -l $PWD/tvix-store.sock &
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          # Wait for the socket to be created.
 | 
					          # Wait for the socket to be created.
 | 
				
			||||||
        while [ ! -e $PWD/tvix-store.socket ]; do sleep 1; done
 | 
					          while [ ! -e $PWD/tvix-store.sock ]; do sleep 1; done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          # Export env vars so that subsequent tvix-store commands will talk to
 | 
					          # Export env vars so that subsequent tvix-store commands will talk to
 | 
				
			||||||
          # our tvix-store daemon over the unix socket.
 | 
					          # our tvix-store daemon over the unix socket.
 | 
				
			||||||
        export BLOB_SERVICE_ADDR=grpc+unix://$PWD/tvix-store.socket
 | 
					          export BLOB_SERVICE_ADDR=grpc+unix://$PWD/tvix-store.sock
 | 
				
			||||||
        export DIRECTORY_SERVICE_ADDR=grpc+unix://$PWD/tvix-store.socket
 | 
					          export DIRECTORY_SERVICE_ADDR=grpc+unix://$PWD/tvix-store.sock
 | 
				
			||||||
        export PATH_INFO_SERVICE_ADDR=grpc+unix://$PWD/tvix-store.socket
 | 
					          export PATH_INFO_SERVICE_ADDR=grpc+unix://$PWD/tvix-store.sock
 | 
				
			||||||
      '' + lib.optionalString (importPath != null) ''
 | 
					        '' + lib.optionalString (!isClosure) ''
 | 
				
			||||||
        echo "Importing ${importPath} into tvix-store with name ${importPathName}…"
 | 
					          echo "Importing ${path} into tvix-store with name ${importPathName}…"
 | 
				
			||||||
        cp -R ${importPath} ${importPathName}
 | 
					          cp -R ${path} ${importPathName}
 | 
				
			||||||
          outpath=$(tvix-store import ${importPathName})
 | 
					          outpath=$(tvix-store import ${importPathName})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          echo "imported to $outpath"
 | 
					          echo "imported to $outpath"
 | 
				
			||||||
 | 
					        '' + lib.optionalString (isClosure) ''
 | 
				
			||||||
 | 
					          echo "Starting nar-bridge…"
 | 
				
			||||||
 | 
					          nar-bridge-http --store-addr=unix://$PWD/tvix-store.sock --listen-addr=$PWD/nar-bridge.sock &
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # Wait for the socket to be created.
 | 
				
			||||||
 | 
					          while [ ! -e $PWD/nar-bridge.sock ]; do sleep 1; done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # Upload. We can't use nix copy --to http://…, as it wants access to the nix db.
 | 
				
			||||||
 | 
					          # However, we can use mkBinaryCache to assemble .narinfo and .nar.xz to upload,
 | 
				
			||||||
 | 
					          # and then drive a HTTP client ourselves.
 | 
				
			||||||
 | 
					          to_upload=${pkgs.mkBinaryCache { rootPaths = [path];}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # Upload all NAR files (with some parallelism).
 | 
				
			||||||
 | 
					          # As mkBinaryCache produces them xz-compressed, unpack them on the fly.
 | 
				
			||||||
 | 
					          # nar-bridge doesn't care about the path we upload *to*, but a
 | 
				
			||||||
 | 
					          # subsequent .narinfo upload need to refer to its contents (by narhash).
 | 
				
			||||||
 | 
					          echo -e "Uploading NARs… "
 | 
				
			||||||
 | 
					          ls -d $to_upload/nar/*.nar.xz | parallel 'xz -d < {} | curl -s -T - --unix-socket $PWD/nar-bridge.sock http://localhost:9000/nar/$(basename {} | cut -d "." -f 1).nar'
 | 
				
			||||||
 | 
					          echo "Done."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # Upload all NARInfo files.
 | 
				
			||||||
 | 
					          # FUTUREWORK: This doesn't upload them in order, and currently relies
 | 
				
			||||||
 | 
					          # on PathInfoService not doing any checking.
 | 
				
			||||||
 | 
					          # In the future, we might want to make this behaviour configurable,
 | 
				
			||||||
 | 
					          # and disable checking here, to keep the logic simple.
 | 
				
			||||||
 | 
					          ls -d $to_upload/*.narinfo | parallel 'curl -s -T - --unix-socket $PWD/nar-bridge.sock http://localhost:9000/$(basename {}) < {}'
 | 
				
			||||||
 | 
					        '' + ''
 | 
				
			||||||
          # Invoke a VM using tvix as the backing store, ensure the outpath appears in its listing.
 | 
					          # Invoke a VM using tvix as the backing store, ensure the outpath appears in its listing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          CH_CMDLINE="tvix.find" run-tvix-vm 2>&1 | tee output.txt
 | 
					          CH_CMDLINE="tvix.find" run-tvix-vm 2>&1 | tee output.txt
 | 
				
			||||||
        grep $outpath output.txt
 | 
					          grep ${path} output.txt
 | 
				
			||||||
        '';
 | 
					        '';
 | 
				
			||||||
        requiredSystemFeatures = [ "kvm" ];
 | 
					        requiredSystemFeatures = [ "kvm" ];
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
depot.nix.readTree.drvTargets {
 | 
					depot.nix.readTree.drvTargets
 | 
				
			||||||
  docs-memory = (mkBootTest { });
 | 
					{
 | 
				
			||||||
 | 
					  docs-memory = (mkBootTest {
 | 
				
			||||||
 | 
					    path = ../../docs;
 | 
				
			||||||
 | 
					    importPathName = "docs";
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
  docs-sled = (mkBootTest {
 | 
					  docs-sled = (mkBootTest {
 | 
				
			||||||
    blobServiceAddr = "sled://$PWD/blobs.sled";
 | 
					    blobServiceAddr = "sled://$PWD/blobs.sled";
 | 
				
			||||||
    directoryServiceAddr = "sled://$PWD/directories.sled";
 | 
					    directoryServiceAddr = "sled://$PWD/directories.sled";
 | 
				
			||||||
    pathInfoServiceAddr = "sled://$PWD/pathinfo.sled";
 | 
					    pathInfoServiceAddr = "sled://$PWD/pathinfo.sled";
 | 
				
			||||||
 | 
					    path = ../../docs;
 | 
				
			||||||
 | 
					    importPathName = "docs";
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  docs-objectstore-local = (mkBootTest {
 | 
					  docs-objectstore-local = (mkBootTest {
 | 
				
			||||||
    blobServiceAddr = "objectstore+file://$PWD/blobs";
 | 
					    blobServiceAddr = "objectstore+file://$PWD/blobs";
 | 
				
			||||||
 | 
					    path = ../../docs;
 | 
				
			||||||
 | 
					    importPathName = "docs";
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closure-tvix = (mkBootTest {
 | 
				
			||||||
 | 
					    blobServiceAddr = "objectstore+file://$PWD/blobs";
 | 
				
			||||||
 | 
					    path = depot.tvix.store;
 | 
				
			||||||
 | 
					    isClosure = true;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue