Exemplo n.º 1
0
TEST_F(SharedFilesystemIsolatorTest, ROOT_AbsoluteVolume)
{
    slave::Flags flags = CreateSlaveFlags();
    flags.isolation = "filesystem/shared";

    Try<Isolator*> isolator = SharedFilesystemIsolatorProcess::create(flags);
    CHECK_SOME(isolator);

    Try<Launcher*> launcher = LinuxLauncher::create(flags);
    CHECK_SOME(launcher);

    // We'll mount the absolute test work directory as /var/tmp in the
    // container.
    const string hostPath = flags.work_dir;
    const string containerPath = "/var/tmp";

    ContainerInfo containerInfo;
    containerInfo.set_type(ContainerInfo::MESOS);
    containerInfo.add_volumes()->CopyFrom(
        CREATE_VOLUME(containerPath, hostPath, Volume::RW));

    ExecutorInfo executorInfo;
    executorInfo.mutable_container()->CopyFrom(containerInfo);

    ContainerID containerId;
    containerId.set_value(UUID::random().toString());

    Future<Option<CommandInfo> > prepare =
        isolator.get()->prepare(containerId, executorInfo, flags.work_dir, None());
    AWAIT_READY(prepare);
    ASSERT_SOME(prepare.get());

    // Test the volume mounting by touching a file in the container's
    // /tmp, which should then be in flags.work_dir.
    const string filename = UUID::random().toString();
    ASSERT_FALSE(os::exists(path::join(containerPath, filename)));

    vector<string> args;
    args.push_back("/bin/sh");
    args.push_back("-x");
    args.push_back("-c");
    args.push_back(prepare.get().get().value() +
                   " && touch " +
                   path::join(containerPath, filename));

    Try<pid_t> pid = launcher.get()->fork(
                         containerId,
                         "/bin/sh",
                         args,
                         Subprocess::FD(STDIN_FILENO),
                         Subprocess::FD(STDOUT_FILENO),
                         Subprocess::FD(STDERR_FILENO),
                         None(),
                         None(),
                         None());
    ASSERT_SOME(pid);

    // Set up the reaper to wait on the forked child.
    Future<Option<int> > status = process::reap(pid.get());

    AWAIT_READY(status);
    EXPECT_SOME_EQ(0, status.get());

    // Check the file was created in flags.work_dir.
    EXPECT_TRUE(os::exists(path::join(hostPath, filename)));

    // Check it didn't get created in the host's view of containerPath.
    EXPECT_FALSE(os::exists(path::join(containerPath, filename)));

    delete launcher.get();
    delete isolator.get();
}
// This test verifies that the image specified in the volume will be
// properly provisioned and mounted into the container if container
// root filesystem is not specified.
TEST_P(VolumeImageIsolatorTest, ROOT_ImageInVolumeWithoutRootFilesystem)
{
  string registry = path::join(sandbox.get(), "registry");
  AWAIT_READY(DockerArchive::create(registry, "test_image"));

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "filesystem/linux,volume/image,docker/runtime";
  flags.docker_registry = registry;
  flags.docker_store_dir = path::join(sandbox.get(), "store");
  flags.image_providers = "docker";

  Fetcher fetcher(flags);

  Try<MesosContainerizer*> create =
    MesosContainerizer::create(flags, true, &fetcher);

  ASSERT_SOME(create);

  Owned<Containerizer> containerizer(create.get());

  ContainerID containerId;
  containerId.set_value(id::UUID::random().toString());

  ContainerInfo container = createContainerInfo(
      None(),
      {createVolumeFromDockerImage("rootfs", "test_image", Volume::RW)});

  CommandInfo command = createCommandInfo("test -d rootfs/bin");

  ExecutorInfo executor = createExecutorInfo(
      "test_executor",
      nesting ? createCommandInfo("sleep 1000") : command);

  if (!nesting) {
    executor.mutable_container()->CopyFrom(container);
  }

  string directory = path::join(flags.work_dir, "sandbox");
  ASSERT_SOME(os::mkdir(directory));

  Future<Containerizer::LaunchResult> launch = containerizer->launch(
      containerId,
      createContainerConfig(None(), executor, directory),
      map<string, string>(),
      None());

  AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch);

  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);

  if (nesting) {
    ContainerID nestedContainerId;
    nestedContainerId.mutable_parent()->CopyFrom(containerId);
    nestedContainerId.set_value(id::UUID::random().toString());

    launch = containerizer->launch(
        nestedContainerId,
        createContainerConfig(command, container),
        map<string, string>(),
        None());

    AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch);

    wait = containerizer->wait(nestedContainerId);
  }

  AWAIT_READY(wait);
  ASSERT_SOME(wait.get());
  ASSERT_TRUE(wait->get().has_status());
  EXPECT_WEXITSTATUS_EQ(0, wait->get().status());

  if (nesting) {
    Future<Option<ContainerTermination>> termination =
      containerizer->destroy(containerId);

    AWAIT_READY(termination);
    ASSERT_SOME(termination.get());
    ASSERT_TRUE(termination->get().has_status());
    EXPECT_WTERMSIG_EQ(SIGKILL, termination.get()->status());
  }
}
Exemplo n.º 3
0
// Test that a container can create a private view of a system
// directory (/var/tmp). Check that a file written by a process inside
// the container doesn't appear on the host filesystem but does appear
// under the container's work directory.
TEST_F(SharedFilesystemIsolatorTest, ROOT_RelativeVolume)
{
    slave::Flags flags = CreateSlaveFlags();
    flags.isolation = "filesystem/shared";

    Try<Isolator*> isolator = SharedFilesystemIsolatorProcess::create(flags);
    CHECK_SOME(isolator);

    Try<Launcher*> launcher = LinuxLauncher::create(flags);
    CHECK_SOME(launcher);

    // Use /var/tmp so we don't mask the work directory (under /tmp).
    const string containerPath = "/var/tmp";
    ASSERT_TRUE(os::isdir(containerPath));

    // Use a host path relative to the container work directory.
    const string hostPath = strings::remove(containerPath, "/", strings::PREFIX);

    ContainerInfo containerInfo;
    containerInfo.set_type(ContainerInfo::MESOS);
    containerInfo.add_volumes()->CopyFrom(
        CREATE_VOLUME(containerPath, hostPath, Volume::RW));

    ExecutorInfo executorInfo;
    executorInfo.mutable_container()->CopyFrom(containerInfo);

    ContainerID containerId;
    containerId.set_value(UUID::random().toString());

    Future<Option<CommandInfo> > prepare =
        isolator.get()->prepare(containerId, executorInfo, flags.work_dir, None());
    AWAIT_READY(prepare);
    ASSERT_SOME(prepare.get());

    // The test will touch a file in container path.
    const string file = path::join(containerPath, UUID::random().toString());
    ASSERT_FALSE(os::exists(file));

    // Manually run the isolator's preparation command first, then touch
    // the file.
    vector<string> args;
    args.push_back("/bin/sh");
    args.push_back("-x");
    args.push_back("-c");
    args.push_back(prepare.get().get().value() + " && touch " + file);

    Try<pid_t> pid = launcher.get()->fork(
                         containerId,
                         "/bin/sh",
                         args,
                         Subprocess::FD(STDIN_FILENO),
                         Subprocess::FD(STDOUT_FILENO),
                         Subprocess::FD(STDERR_FILENO),
                         None(),
                         None(),
                         None());
    ASSERT_SOME(pid);

    // Set up the reaper to wait on the forked child.
    Future<Option<int> > status = process::reap(pid.get());

    AWAIT_READY(status);
    EXPECT_SOME_EQ(0, status.get());

    // Check the correct hierarchy was created under the container work
    // directory.
    string dir = "/";
    foreach (const string& subdir, strings::tokenize(containerPath, "/")) {
        dir = path::join(dir, subdir);

        struct stat hostStat;
        EXPECT_EQ(0, ::stat(dir.c_str(), &hostStat));

        struct stat containerStat;
        EXPECT_EQ(0,
                  ::stat(path::join(flags.work_dir, dir).c_str(), &containerStat));

        EXPECT_EQ(hostStat.st_mode, containerStat.st_mode);
        EXPECT_EQ(hostStat.st_uid, containerStat.st_uid);
        EXPECT_EQ(hostStat.st_gid, containerStat.st_gid);
    }

    // Check it did *not* create a file in the host namespace.
    EXPECT_FALSE(os::exists(file));

    // Check it did create the file under the container's work directory
    // on the host.
    EXPECT_TRUE(os::exists(path::join(flags.work_dir, file)));

    delete launcher.get();
    delete isolator.get();
}
// This test verifies that if a persistent volume and SANDBOX_PATH
// volume are both specified and the 'path' of the SANDBOX_PATH volume
// is the same relative path as the persistent volume's container
// path, the persistent volume will not be neglect and is mounted
// correctly. This is a regression test for MESOS-7770.
TEST_F(LinuxFilesystemIsolatorTest,
       ROOT_PersistentVolumeAndHostVolumeWithRootFilesystem)
{
  string registry = path::join(sandbox.get(), "registry");
  AWAIT_READY(DockerArchive::create(registry, "test_image"));

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "filesystem/linux,docker/runtime";
  flags.docker_registry = registry;
  flags.docker_store_dir = path::join(sandbox.get(), "store");
  flags.image_providers = "docker";

  Fetcher fetcher(flags);

  Try<MesosContainerizer*> create =
    MesosContainerizer::create(flags, true, &fetcher);

  ASSERT_SOME(create);

  Owned<Containerizer> containerizer(create.get());

  ContainerID containerId;
  containerId.set_value(id::UUID::random().toString());

  // Write to an absolute path in the container's mount namespace to
  // verify mounts of the SANDBOX_PATH volume and the persistent
  // volume are done in the proper order.
  ExecutorInfo executor = createExecutorInfo(
      "test_executor",
      "echo abc > /absolute_path/file");

  executor.add_resources()->CopyFrom(createPersistentVolume(
      Megabytes(32),
      "test_role",
      "persistent_volume_id",
      "volume"));

  executor.mutable_container()->CopyFrom(createContainerInfo(
      "test_image",
      {createVolumeSandboxPath("/absolute_path", "volume", Volume::RW)}));

  // Create a persistent volume.
  string volume = slave::paths::getPersistentVolumePath(
      flags.work_dir,
      "test_role",
      "persistent_volume_id");

  ASSERT_SOME(os::mkdir(volume));

  string directory = path::join(flags.work_dir, "sandbox");
  ASSERT_SOME(os::mkdir(directory));

  Future<Containerizer::LaunchResult> launch = containerizer->launch(
      containerId,
      createContainerConfig(None(), executor, directory),
      map<string, string>(),
      None());

  AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch);

  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);

  AWAIT_READY(wait);
  ASSERT_SOME(wait.get());
  ASSERT_TRUE(wait->get().has_status());
  EXPECT_WEXITSTATUS_EQ(0, wait->get().status());

  EXPECT_SOME_EQ("abc\n", os::read(path::join(volume, "file")));
}