diff options
-rw-r--r-- | nixos/modules/services/misc/mesos-master.nix | 21 | ||||
-rw-r--r-- | nixos/modules/services/misc/mesos-slave.nix | 98 | ||||
-rw-r--r-- | nixos/tests/mesos.nix | 97 | ||||
-rw-r--r-- | nixos/tests/mesos_test.py | 72 | ||||
-rw-r--r-- | pkgs/applications/networking/cluster/mesos/default.nix | 94 | ||||
-rw-r--r-- | pkgs/applications/networking/cluster/mesos/maven_repo.patch | 13 | ||||
-rw-r--r-- | pkgs/applications/networking/cluster/mesos/nixos.patch | 444 | ||||
-rw-r--r-- | pkgs/applications/networking/cluster/mesos/rb36610.patch | 7 | ||||
-rw-r--r-- | pkgs/applications/networking/cluster/mesos/rb51324.patch | 71 | ||||
-rw-r--r-- | pkgs/applications/networking/cluster/mesos/rb51325.patch | 157 | ||||
-rw-r--r-- | pkgs/development/interpreters/python/build-python-package-setuptools.nix | 2 | ||||
-rw-r--r-- | pkgs/development/libraries/protobuf/generic.nix | 22 | ||||
-rw-r--r-- | pkgs/top-level/python-packages.nix | 23 |
13 files changed, 749 insertions, 372 deletions
diff --git a/nixos/modules/services/misc/mesos-master.nix b/nixos/modules/services/misc/mesos-master.nix index 99583ebeebd5..0523c6549ed6 100644 --- a/nixos/modules/services/misc/mesos-master.nix +++ b/nixos/modules/services/misc/mesos-master.nix @@ -16,12 +16,30 @@ in { type = types.bool; }; + ip = mkOption { + description = "IP address to listen on."; + default = "0.0.0.0"; + type = types.str; + }; + port = mkOption { description = "Mesos Master port"; default = 5050; type = types.int; }; + advertiseIp = mkOption { + description = "IP address advertised to reach this master."; + default = null; + type = types.nullOr types.str; + }; + + advertisePort = mkOption { + description = "Port advertised to reach this Mesos master."; + default = null; + type = types.nullOr types.int; + }; + zk = mkOption { description = '' ZooKeeper URL (used for leader election amongst masters). @@ -84,7 +102,10 @@ in { serviceConfig = { ExecStart = '' ${pkgs.mesos}/bin/mesos-master \ + --ip=${cfg.ip} \ --port=${toString cfg.port} \ + ${optionalString (cfg.advertiseIp != null) "--advertise_ip=${cfg.advertiseIp}"} \ + ${optionalString (cfg.advertisePort != null) "--advertise_port=${toString cfg.advertisePort}"} \ ${if cfg.quorum == 0 then "--registry=in_memory" else "--zk=${cfg.zk} --registry=replicated_log --quorum=${toString cfg.quorum}"} \ diff --git a/nixos/modules/services/misc/mesos-slave.nix b/nixos/modules/services/misc/mesos-slave.nix index 9ddecb6fe30c..47be10274d3b 100644 --- a/nixos/modules/services/misc/mesos-slave.nix +++ b/nixos/modules/services/misc/mesos-slave.nix @@ -12,7 +12,23 @@ let attribsArg = optionalString (cfg.attributes != {}) "--attributes=${mkAttributes cfg.attributes}"; - containerizers = [ "mesos" ] ++ (optional cfg.withDocker "docker"); + containerizersArg = concatStringsSep "," ( + lib.unique ( + cfg.containerizers ++ (optional cfg.withDocker "docker") + ) + ); + + imageProvidersArg = concatStringsSep "," ( + lib.unique ( + cfg.imageProviders ++ (optional cfg.withDocker "docker") + ) + ); + + isolationArg = concatStringsSep "," ( + lib.unique ( + cfg.isolation ++ (optionals cfg.withDocker [ "filesystem/linux" "docker/runtime"]) + ) + ); in { @@ -27,7 +43,7 @@ in { ip = mkOption { description = "IP address to listen on."; default = "0.0.0.0"; - type = types.string; + type = types.str; }; port = mkOption { @@ -36,6 +52,53 @@ in { type = types.int; }; + advertiseIp = mkOption { + description = "IP address advertised to reach this agent."; + default = null; + type = types.nullOr types.str; + }; + + advertisePort = mkOption { + description = "Port advertised to reach this agent."; + default = null; + type = types.nullOr types.int; + }; + + containerizers = mkOption { + description = '' + List of containerizer implementations to compose in order to provide + containerization. Available options are mesos and docker. + The order the containerizers are specified is the order they are tried. + ''; + default = [ "mesos" ]; + type = types.listOf types.str; + }; + + imageProviders = mkOption { + description = "List of supported image providers, e.g., APPC,DOCKER."; + default = [ ]; + type = types.listOf types.str; + }; + + imageProvisionerBackend = mkOption { + description = '' + Strategy for provisioning container rootfs from images, + e.g., aufs, bind, copy, overlay. + ''; + default = "copy"; + type = types.str; + }; + + isolation = mkOption { + description = '' + Isolation mechanisms to use, e.g., posix/cpu,posix/mem, or + cgroups/cpu,cgroups/mem, or network/port_mapping, or `gpu/nvidia` for nvidia + specific gpu isolation. + ''; + default = [ "posix/cpu" "posix/mem" ]; + type = types.listOf types.str; + }; + master = mkOption { description = '' May be one of: @@ -57,6 +120,16 @@ in { type = types.bool; }; + dockerRegistry = mkOption { + description = '' + The default url for pulling Docker images. + It could either be a Docker registry server url, + or a local path in which Docker image archives are stored. + ''; + default = null; + type = types.nullOr (types.either types.str types.path); + }; + workDir = mkOption { description = "The Mesos work directory."; default = "/var/lib/mesos/slave"; @@ -96,28 +169,45 @@ in { host = "aabc123"; os = "nixos"; }; }; + + executorEnvironmentVariables = mkOption { + description = '' + The environment variables that should be passed to the executor, and thus subsequently task(s). + ''; + default = { + PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; + }; + type = types.attrsOf types.str; + }; }; }; - config = mkIf cfg.enable { systemd.services.mesos-slave = { description = "Mesos Slave"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - environment.MESOS_CONTAINERIZERS = concatStringsSep "," containerizers; + path = [ pkgs.stdenv.shellPackage ]; serviceConfig = { ExecStart = '' ${pkgs.mesos}/bin/mesos-slave \ + --containerizers=${containerizersArg} \ + --image_providers=${imageProvidersArg} \ + --image_provisioner_backend=${cfg.imageProvisionerBackend} \ + --isolation=${isolationArg} \ --ip=${cfg.ip} \ --port=${toString cfg.port} \ + ${optionalString (cfg.advertiseIp != null) "--advertise_ip=${cfg.advertiseIp}"} \ + ${optionalString (cfg.advertisePort != null) "--advertise_port=${toString cfg.advertisePort}"} \ --master=${cfg.master} \ --work_dir=${cfg.workDir} \ --logging_level=${cfg.logLevel} \ ${attribsArg} \ ${optionalString cfg.withHadoop "--hadoop-home=${pkgs.hadoop}"} \ ${optionalString cfg.withDocker "--docker=${pkgs.docker}/libexec/docker/docker"} \ + ${optionalString (cfg.dockerRegistry != null) "--docker_registry=${cfg.dockerRegistry}"} \ + --executor_environment_variables=${lib.escapeShellArg (builtins.toJSON cfg.executorEnvironmentVariables)} \ ${toString cfg.extraCmdLineOptions} ''; PermissionsStartOnly = true; diff --git a/nixos/tests/mesos.nix b/nixos/tests/mesos.nix index 3610603aeba2..6e9af126f032 100644 --- a/nixos/tests/mesos.nix +++ b/nixos/tests/mesos.nix @@ -1,32 +1,91 @@ -import ./make-test.nix ({ pkgs, ...} : { - name = "simple"; +import ./make-test.nix ({ pkgs, ...} : rec { + name = "mesos"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ offline ]; + maintainers = [ offline kamilchm cstrahan ]; }; - machine = { config, pkgs, ... }: { - services.zookeeper.enable = true; - virtualisation.docker.enable = true; - services.mesos = { - slave = { - enable = true; - master = "zk://localhost:2181/mesos"; - attributes = { - tag1 = "foo"; - tag2 = "bar"; - }; + nodes = { + master = { config, pkgs, ... }: { + networking.firewall.enable = false; + services.zookeeper.enable = true; + services.mesos.master = { + enable = true; + zk = "zk://master:2181/mesos"; }; - master = { - enable = true; - zk = "zk://localhost:2181/mesos"; + }; + + slave = { config, pkgs, ... }: { + networking.firewall.enable = false; + networking.nat.enable = true; + virtualisation.docker.enable = true; + services.mesos = { + slave = { + enable = true; + master = "master:5050"; + dockerRegistry = registry; + executorEnvironmentVariables = { + PATH = "/run/current-system/sw/bin"; + }; + }; }; }; }; + simpleDocker = pkgs.dockerTools.buildImage { + name = "echo"; + contents = [ pkgs.stdenv.shellPackage pkgs.coreutils ]; + config = { + Env = [ + # When shell=true, mesos invokes "sh -c '<cmd>'", so make sure "sh" is + # on the PATH. + "PATH=${pkgs.stdenv.shellPackage}/bin:${pkgs.coreutils}/bin" + ]; + Entrypoint = [ "echo" ]; + }; + }; + + registry = pkgs.runCommand "registry" { } '' + mkdir -p $out + cp ${simpleDocker} $out/echo:latest.tar + ''; + + testFramework = pkgs.pythonPackages.buildPythonPackage { + name = "mesos-tests"; + propagatedBuildInputs = [ pkgs.mesos ]; + catchConflicts = false; + src = ./mesos_test.py; + phases = [ "installPhase" "fixupPhase" ]; + installPhase = '' + mkdir $out + cp $src $out/mesos_test.py + chmod +x $out/mesos_test.py + + echo "done" > test.result + tar czf $out/test.tar.gz test.result + ''; + }; + testScript = '' startAll; - $machine->waitForUnit("mesos-master.service"); - $machine->waitForUnit("mesos-slave.service"); + $master->waitForUnit("mesos-master.service"); + $slave->waitForUnit("mesos-slave.service"); + + $master->waitForOpenPort(5050); + $slave->waitForOpenPort(5051); + + # is slave registred? + $master->waitUntilSucceeds("curl -s --fail http://master:5050/master/slaves". + " | grep -q \"\\\"hostname\\\":\\\"slave\\\"\""); + + # try to run docker image + $master->succeed("${pkgs.mesos}/bin/mesos-execute --master=master:5050". + " --resources=\"cpus:0.1;mem:32\" --name=simple-docker". + " --containerizer=mesos --docker_image=echo:latest". + " --shell=true --command=\"echo done\" | grep -q TASK_FINISHED"); + + # simple command with .tar.gz uri + $master->succeed("${testFramework}/mesos_test.py master ". + "${testFramework}/test.tar.gz"); ''; }) diff --git a/nixos/tests/mesos_test.py b/nixos/tests/mesos_test.py new file mode 100644 index 000000000000..be8bb32e49a7 --- /dev/null +++ b/nixos/tests/mesos_test.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +import uuid +import time +import subprocess +import os + +import sys + +from mesos.interface import Scheduler +from mesos.native import MesosSchedulerDriver +from mesos.interface import mesos_pb2 + +def log(msg): + process = subprocess.Popen("systemd-cat", stdin=subprocess.PIPE) + (out,err) = process.communicate(msg) + +class NixosTestScheduler(Scheduler): + def __init__(self): + self.master_ip = sys.argv[1] + self.download_uri = sys.argv[2] + + def resourceOffers(self, driver, offers): + log("XXX got resource offer") + + offer = offers[0] + task = self.new_task(offer) + uri = task.command.uris.add() + uri.value = self.download_uri + task.command.value = "cat test.result" + driver.launchTasks(offer.id, [task]) + + def statusUpdate(self, driver, update): + log("XXX status update") + if update.state == mesos_pb2.TASK_FAILED: + log("XXX test task failed with message: " + update.message) + driver.stop() + sys.exit(1) + elif update.state == mesos_pb2.TASK_FINISHED: + driver.stop() + sys.exit(0) + + def new_task(self, offer): + task = mesos_pb2.TaskInfo() + id = uuid.uuid4() + task.task_id.value = str(id) + task.slave_id.value = offer.slave_id.value + task.name = "task {}".format(str(id)) + + cpus = task.resources.add() + cpus.name = "cpus" + cpus.type = mesos_pb2.Value.SCALAR + cpus.scalar.value = 0.1 + + mem = task.resources.add() + mem.name = "mem" + mem.type = mesos_pb2.Value.SCALAR + mem.scalar.value = 32 + + return task + +if __name__ == '__main__': + log("XXX framework started") + + framework = mesos_pb2.FrameworkInfo() + framework.user = "root" + framework.name = "nixos-test-framework" + driver = MesosSchedulerDriver( + NixosTestScheduler(), + framework, + sys.argv[1] + ":5050" + ) + driver.run() diff --git a/pkgs/applications/networking/cluster/mesos/default.nix b/pkgs/applications/networking/cluster/mesos/default.nix index 8857e6ba4e35..818848f6a7f1 100644 --- a/pkgs/applications/networking/cluster/mesos/default.nix +++ b/pkgs/applications/networking/cluster/mesos/default.nix @@ -2,16 +2,27 @@ , automake115x, libtool, unzip, gnutar, jdk, maven, python, wrapPython , setuptools, boto, pythonProtobuf, apr, subversion, gzip, systemd , leveldb, glog, perf, utillinux, libnl, iproute, openssl, libevent -, ethtool, coreutils +, ethtool, coreutils, which, iptables , bash }: let mavenRepo = import ./mesos-deps.nix { inherit stdenv curl; }; soext = if stdenv.system == "x86_64-darwin" then "dylib" else "so"; + # `tar -z` requires gzip on $PATH, so wrap tar. + # At some point, we should try to patch mesos so we add gzip to the PATH when + # tar is invoked. I think that only needs to be done here: + # src/common/command_utils.cpp + # https://github.com/NixOS/nixpkgs/issues/13783 + tarWithGzip = lib.overrideDerivation gnutar (oldAttrs: { + buildInputs = (oldAttrs.buildInputs or []) ++ [ makeWrapper ]; + postInstall = (oldAttrs.postInstall or "") + '' + wrapProgram $out/bin/tar --prefix PATH ":" "${gzip}/bin" + ''; + }); in stdenv.mkDerivation rec { - version = "1.0.1"; + version = "1.1.0"; name = "mesos-${version}"; enableParallelBuilding = true; @@ -19,17 +30,14 @@ in stdenv.mkDerivation rec { src = fetchurl { url = "mirror://apache/mesos/${version}/${name}.tar.gz"; - sha256 = "1hdh2wh11ck98ycfrxfzgivgk2pjl3638vkyw14xj7faj9qxjlz0"; + sha256 = "1hdjd4syyp88l0bnh88bhzvn9466ad2ysfp9pq3kwj3qzwg5jv8g"; }; patches = [ # https://reviews.apache.org/r/36610/ + # TODO: is this still needed? ./rb36610.patch - # https://issues.apache.org/jira/browse/MESOS-6013 - ./rb51324.patch - ./rb51325.patch - # see https://github.com/cstrahan/mesos/tree/nixos-${version} ./nixos.patch ]; @@ -46,33 +54,55 @@ in stdenv.mkDerivation rec { pythonProtobuf ]; + # note that we *must* statically link libprotobuf. + # if we dynamically link the lib, we get these errors: + # https://github.com/NixOS/nixpkgs/pull/19064#issuecomment-255082684 preConfigure = '' - substituteInPlace 3rdparty/stout/include/stout/os/posix/fork.hpp \ - --subst-var-by sh ${bash}/bin/bash + substituteInPlace 3rdparty/stout/include/stout/os/posix/chown.hpp \ + --subst-var-by chown ${coreutils}/bin/chown + + substituteInPlace 3rdparty/stout/Makefile.am \ + --replace "-lprotobuf" \ + "${pythonProtobuf.protobuf.lib}/lib/libprotobuf.a" - substituteInPlace 3rdparty/stout/include/stout/os/posix/shell.hpp \ + substituteInPlace 3rdparty/stout/include/stout/os/posix/fork.hpp \ --subst-var-by sh ${bash}/bin/bash - substituteInPlace src/Makefile.am \ - --subst-var-by mavenRepo ${mavenRepo} + substituteInPlace 3rdparty/stout/include/stout/posix/os.hpp \ + --subst-var-by tar ${tarWithGzip}/bin/tar substituteInPlace src/cli/mesos-scp \ --subst-var-by scp ${openssh}/bin/scp + substituteInPlace src/common/command_utils.cpp \ + --subst-var-by curl ${curl}/bin/curl \ + --subst-var-by gzip ${gzip}/bin/gzip \ + --subst-var-by sha512sum ${coreutils}/bin/sha512sum \ + --subst-var-by tar ${tarWithGzip}/bin/tar + substituteInPlace src/launcher/fetcher.cpp \ + --subst-var-by cp ${coreutils}/bin/cp \ --subst-var-by gzip ${gzip}/bin/gzip \ - --subst-var-by tar ${gnutar}/bin/tar \ + --subst-var-by tar ${tarWithGzip}/bin/tar \ --subst-var-by unzip ${unzip}/bin/unzip substituteInPlace src/python/cli/src/mesos/cli.py \ --subst-var-by mesos-resolve $out/bin/mesos-resolve + substituteInPlace src/python/native_common/ext_modules.py.in \ + --replace "-lprotobuf" \ + "${pythonProtobuf.protobuf.lib}/lib/libprotobuf.a" + + substituteInPlace src/slave/containerizer/mesos/isolators/gpu/volume.cpp \ + --subst-var-by cp ${coreutils}/bin/cp \ + --subst-var-by which ${which}/bin/which + substituteInPlace src/slave/containerizer/mesos/isolators/posix/disk.cpp \ - --subst-var-by du ${coreutils}/bin/du \ - --subst-var-by cp ${coreutils}/bin/cp + --subst-var-by du ${coreutils}/bin/du substituteInPlace src/slave/containerizer/mesos/provisioner/backends/copy.cpp \ - --subst-var-by cp ${coreutils}/bin/cp + --subst-var-by cp ${coreutils}/bin/cp \ + --subst-var-by rm ${coreutils}/bin/rm substituteInPlace src/uri/fetchers/copy.cpp \ --subst-var-by cp ${coreutils}/bin/cp @@ -83,23 +113,48 @@ in stdenv.mkDerivation rec { substituteInPlace src/uri/fetchers/docker.cpp \ --subst-var-by curl ${curl}/bin/curl + substituteInPlace src/Makefile.am \ + --subst-var-by mavenRepo ${mavenRepo} \ + --replace "-lprotobuf" \ + "${pythonProtobuf.protobuf.lib}/lib/libprotobuf.a" + '' + lib.optionalString stdenv.isLinux '' substituteInPlace src/linux/perf.cpp \ --subst-var-by perf ${perf}/bin/perf + substituteInPlace src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp \ + --subst-var-by mount ${utillinux}/bin/mount + + substituteInPlace src/slave/containerizer/mesos/isolators/filesystem/linux.cpp \ + --subst-var-by mount ${utillinux}/bin/mount + substituteInPlace src/slave/containerizer/mesos/isolators/filesystem/shared.cpp \ --subst-var-by mount ${utillinux}/bin/mount + substituteInPlace src/slave/containerizer/mesos/isolators/gpu/isolator.cpp \ + --subst-var-by mount ${utillinux}/bin/mount + substituteInPlace src/slave/containerizer/mesos/isolators/namespaces/pid.cpp \ --subst-var-by mount ${utillinux}/bin/mount + substituteInPlace src/slave/containerizer/mesos/isolators/network/cni/cni.cpp \ + --subst-var-by mount ${utillinux}/bin/mount + + substituteInPlace src/slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.cpp \ + --subst-var-by iptables ${iptables}/bin/iptables + substituteInPlace src/slave/containerizer/mesos/isolators/network/port_mapping.cpp \ - --subst-var-by tc ${iproute}/bin/tc \ + --subst-var-by ethtool ${ethtool}/sbin/ethtool \ --subst-var-by ip ${iproute}/bin/ip \ --subst-var-by mount ${utillinux}/bin/mount \ - --subst-var-by sh ${stdenv.shell} \ - --subst-var-by ethtool ${ethtool}/sbin/ethtool + --subst-var-by tc ${iproute}/bin/tc + + substituteInPlace src/slave/containerizer/mesos/isolators/volume/image.cpp \ + --subst-var-by mount ${utillinux}/bin/mount + + substituteInPlace src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp \ + --subst-var-by mount ${utillinux}/bin/mount ''; configureFlags = [ @@ -108,7 +163,6 @@ in stdenv.mkDerivation rec { "--with-svn=${subversion.dev}" "--with-leveldb=${leveldb}" "--with-glog=${glog}" - "--with-glog=${glog}" "--enable-optimize" "--disable-python-dependency-install" "--enable-ssl" diff --git a/pkgs/applications/networking/cluster/mesos/maven_repo.patch b/pkgs/applications/networking/cluster/mesos/maven_repo.patch deleted file mode 100644 index 9ee12976fde1..000000000000 --- a/pkgs/applications/networking/cluster/mesos/maven_repo.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/Makefile.am b/src/Makefile.am -index ae2740a..1df91a7 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -1310,7 +1310,7 @@ if HAS_JAVA - - $(MESOS_JAR): $(MESOS_JAR_SOURCE) $(MESOS_JAR_GENERATED) java/mesos.pom - @echo "Building mesos-$(PACKAGE_VERSION).jar ..." -- @cd $(abs_top_builddir)/src/java && $(MVN) -f mesos.pom clean package -+ @cd $(abs_top_builddir)/src/java && $(MVN) -f mesos.pom -Dmaven.repo.local=@mavenRepo@ clean package - - # Convenience library for JNI bindings. - # TODO(Charles Reiss): We really should be building the Java library diff --git a/pkgs/applications/networking/cluster/mesos/nixos.patch b/pkgs/applications/networking/cluster/mesos/nixos.patch index 032357e452db..78e374b8d6bc 100644 --- a/pkgs/applications/networking/cluster/mesos/nixos.patch +++ b/pkgs/applications/networking/cluster/mesos/nixos.patch @@ -1,5 +1,18 @@ +diff --git a/3rdparty/stout/include/stout/os/posix/chown.hpp b/3rdparty/stout/include/stout/os/posix/chown.hpp +index c82e2e574..15d332107 100644 +--- a/3rdparty/stout/include/stout/os/posix/chown.hpp ++++ b/3rdparty/stout/include/stout/os/posix/chown.hpp +@@ -34,7 +34,7 @@ inline Try<Nothing> chown( + // TODO(bmahler): Consider walking the file tree instead. We would need + // to be careful to not miss dotfiles. + std::string command = +- "chown -R " + stringify(uid) + ':' + stringify(gid) + " '" + path + "'"; ++ "@chown@ -R " + stringify(uid) + ':' + stringify(gid) + " '" + path + "'"; + + int status = os::system(command); + if (status != 0) { diff --git a/3rdparty/stout/include/stout/os/posix/fork.hpp b/3rdparty/stout/include/stout/os/posix/fork.hpp -index a29967d..290b98b 100644 +index a29967dcb..290b98b50 100644 --- a/3rdparty/stout/include/stout/os/posix/fork.hpp +++ b/3rdparty/stout/include/stout/os/posix/fork.hpp @@ -369,7 +369,7 @@ private: @@ -11,48 +24,97 @@ index a29967d..290b98b 100644 EXIT(EXIT_FAILURE) << "Failed to execute '" << command << "': " << os::strerror(errno); } else if (wait.isSome()) { -diff --git a/3rdparty/stout/include/stout/os/posix/shell.hpp b/3rdparty/stout/include/stout/os/posix/shell.hpp -index 1d73ae5..9bf89b5 100644 ---- a/3rdparty/stout/include/stout/os/posix/shell.hpp -+++ b/3rdparty/stout/include/stout/os/posix/shell.hpp -@@ -37,7 +37,7 @@ namespace Shell { - // received by the callee, usually the command name and `arg1` is the - // second command argument received by the callee. - --constexpr const char* name = "sh"; -+constexpr const char* name = "@sh@"; - constexpr const char* arg0 = "sh"; - constexpr const char* arg1 = "-c"; +diff --git a/3rdparty/stout/include/stout/posix/os.hpp b/3rdparty/stout/include/stout/posix/os.hpp +index c37e64db6..d3d87b7f0 100644 +--- a/3rdparty/stout/include/stout/posix/os.hpp ++++ b/3rdparty/stout/include/stout/posix/os.hpp +@@ -375,7 +375,7 @@ inline Option<std::string> getenv(const std::string& key) + inline Try<Nothing> tar(const std::string& path, const std::string& archive) + { + Try<std::string> tarOut = +- os::shell("tar %s %s %s", "-czf", archive.c_str(), path.c_str()); ++ os::shell("@tar@ %s %s %s", "-czf", archive.c_str(), path.c_str()); + if (tarOut.isError()) { + return Error("Failed to archive " + path + ": " + tarOut.error()); diff --git a/src/Makefile.am b/src/Makefile.am -index 28dd151..36fc6ec 100644 +index 3bcc0f2df..e5cbc57e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am -@@ -1528,7 +1528,8 @@ if HAS_JAVA +@@ -1545,7 +1545,7 @@ if HAS_JAVA $(MESOS_JAR): $(MESOS_JAR_SOURCE) $(MESOS_JAR_GENERATED) java/mesos.pom @echo "Building mesos-$(PACKAGE_VERSION).jar ..." - @cd $(abs_top_builddir)/src/java && $(MVN) -B -f mesos.pom clean package + @cd $(abs_top_builddir)/src/java && $(MVN) -B -f mesos.pom -Dmaven.repo.local=@mavenRepo@ clean package -+ # Convenience library for JNI bindings. # TODO(Charles Reiss): We really should be building the Java library diff --git a/src/cli/mesos-scp b/src/cli/mesos-scp -index a71ab07..feed8c4 100755 +index a71ab0708..1043d1b3c 100755 --- a/src/cli/mesos-scp +++ b/src/cli/mesos-scp -@@ -19,7 +19,7 @@ if sys.version_info < (2,6,0): +@@ -19,7 +19,8 @@ if sys.version_info < (2,6,0): def scp(host, src, dst): - cmd = 'scp -pr %s %s' % (src, host + ':' + dst) + cmd = '@scp@ -pr %s %s' % (src, host + ':' + dst) ++ try: process = subprocess.Popen( cmd, +diff --git a/src/common/command_utils.cpp b/src/common/command_utils.cpp +index 09e805140..90bf65896 100644 +--- a/src/common/command_utils.cpp ++++ b/src/common/command_utils.cpp +@@ -140,7 +140,7 @@ Future<Nothing> tar( + + argv.emplace_back(input); + +- return launch("tar", argv) ++ return launch("@tar@", argv) + .then([]() { return Nothing(); }); + } + +@@ -162,7 +162,7 @@ Future<Nothing> untar( + argv.emplace_back(directory.get()); + } + +- return launch("tar", argv) ++ return launch("@tar@", argv) + .then([]() { return Nothing(); }); + } + +@@ -170,7 +170,7 @@ Future<Nothing> untar( + Future<string> sha512(const Path& input) + { + #ifdef __linux__ +- const string cmd = "sha512sum"; ++ const string cmd = "@sha512sum@"; + vector<string> argv = { + cmd, + input // Input file to compute shasum. +@@ -206,7 +206,7 @@ Future<Nothing> gzip(const Path& input) + input + }; + +- return launch("gzip", argv) ++ return launch("@gzip@", argv) + .then([]() { return Nothing(); }); + } + +@@ -219,7 +219,7 @@ Future<Nothing> decompress(const Path& input) + input + }; + +- return launch("gzip", argv) ++ return launch("@gzip@", argv) + .then([]() { return Nothing(); }); + } + diff --git a/src/launcher/fetcher.cpp b/src/launcher/fetcher.cpp -index 4456c28..e22c8fc 100644 +index 4456c2813..e22c8fc03 100644 --- a/src/launcher/fetcher.cpp +++ b/src/launcher/fetcher.cpp @@ -68,13 +68,13 @@ static Try<bool> extract( @@ -82,11 +144,11 @@ index 4456c28..e22c8fc 100644 LOG(INFO) << "Copying resource with command:" << command; diff --git a/src/linux/perf.cpp b/src/linux/perf.cpp -index ea823b3..170f54d 100644 +index aa31982eb..8b5331b17 100644 --- a/src/linux/perf.cpp +++ b/src/linux/perf.cpp -@@ -125,7 +125,7 @@ private: - // NOTE: The watchdog process places perf in its own process group +@@ -127,7 +127,7 @@ private: + // NOTE: The supervisor childhook places perf in its own process group // and will kill the perf process when the parent dies. Try<Subprocess> _perf = subprocess( - "perf", @@ -104,37 +166,51 @@ index ea823b3..170f54d 100644 command << " --event " << event; } diff --git a/src/linux/systemd.cpp b/src/linux/systemd.cpp -index 619aa27..c1cbfe4 100644 +index 6318f48fc..394d88d47 100644 --- a/src/linux/systemd.cpp +++ b/src/linux/systemd.cpp -@@ -196,12 +196,19 @@ bool exists() +@@ -196,13 +196,21 @@ bool exists() // This is static as the init system should not change while we are running. static const bool exists = []() -> bool { // (1) Test whether `/sbin/init` links to systemd. - const Result<string> realpath = os::realpath("/sbin/init"); - if (realpath.isError() || realpath.isNone()) { - LOG(WARNING) << "Failed to test /sbin/init for systemd environment: " -- << realpath.error(); +- << (realpath.isError() ? realpath.error() +- : "does not exist"); - - return false; -+ // cstrahan: first assume we're on NixOS, then try non-NixOS ++ // cstrahan(nixos): first assume we're on NixOS, then try non-NixOS + Result<string> realpath = os::realpath("/run/current-system/systemd/lib/systemd/systemd"); + Result<string> realpathNixOS = realpath; + if (realpathNixOS.isError() || realpathNixOS.isNone()) { + Result<string> realpathNonNixOS = realpath = os::realpath("/sbin/init"); + if (realpathNonNixOS.isError() || realpathNonNixOS.isNone()) { + LOG(WARNING) << "Failed to test /run/current-system/systemd/lib/systemd/systemd for systemd environment: " -+ << realpathNixOS.error(); ++ << (realpathNixOS.isError() ? realpathNixOS.error() ++ : "does not exist"); + LOG(WARNING) << "Failed to test /sbin/init for systemd environment: " -+ << realpathNonNixOS.error(); ++ << (realpathNonNixOS.isError() ? realpathNonNixOS.error() ++ : "does not exist"); + + return false; + } } CHECK_SOME(realpath); +@@ -278,6 +286,10 @@ Path hierarchy() + + Try<Nothing> daemonReload() + { ++ // cstrahan(nixos): should we patch these `systemctl`s? ++ // probably don't want to hard-code a particular systemd store path here, ++ // but if we use /run/current-system/sw/bin/systemctl, ++ // we won't be able to support non-NixOS distros. + Try<string> daemonReload = os::shell("systemctl daemon-reload"); + if (daemonReload.isError()) { + return Error("Failed to reload systemd daemon: " + daemonReload.error()); diff --git a/src/python/cli/src/mesos/cli.py b/src/python/cli/src/mesos/cli.py -index f342992..354abf4 100644 +index f342992e0..354abf443 100644 --- a/src/python/cli/src/mesos/cli.py +++ b/src/python/cli/src/mesos/cli.py @@ -40,7 +40,7 @@ def resolve(master): @@ -146,11 +222,70 @@ index f342992..354abf4 100644 stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, +diff --git a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp +index af9f3736b..f8554d414 100644 +--- a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp ++++ b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp +@@ -499,7 +499,7 @@ Future<Option<ContainerLaunchInfo>> DockerVolumeIsolatorProcess::_prepare( + // unsafe arbitrary commands). + CommandInfo* command = launchInfo.add_pre_exec_commands(); + command->set_shell(false); +- command->set_value("mount"); ++ command->set_value("@mount@"); + command->add_arguments("mount"); + command->add_arguments("-n"); + command->add_arguments("--rbind"); +diff --git a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp +index df16b8fee..4a17475bd 100644 +--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp ++++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp +@@ -159,9 +159,9 @@ Try<Isolator*> LinuxFilesystemIsolatorProcess::create(const Flags& flags) + // here because 'create' will only be invoked during + // initialization. + Try<string> mount = os::shell( +- "mount --bind %s %s && " +- "mount --make-private %s && " +- "mount --make-shared %s", ++ "@mount@ --bind %s %s && " ++ "@mount@ --make-private %s && " ++ "@mount@ --make-shared %s", + workDir->c_str(), + workDir->c_str(), + workDir->c_str(), +@@ -180,8 +180,8 @@ Try<Isolator*> LinuxFilesystemIsolatorProcess::create(const Flags& flags) + LOG(INFO) << "Making '" << workDir.get() << "' a shared mount"; + + Try<string> mount = os::shell( +- "mount --make-private %s && " +- "mount --make-shared %s", ++ "@mount@ --make-private %s && " ++ "@mount@ --make-shared %s", + workDir->c_str(), + workDir->c_str()); + +@@ -404,7 +404,7 @@ Try<vector<CommandInfo>> LinuxFilesystemIsolatorProcess::getPreExecCommands( + + CommandInfo command; + command.set_shell(false); +- command.set_value("mount"); ++ command.set_value("@mount@"); + command.add_arguments("mount"); + command.add_arguments |