// 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()); } }
// This test verifies that sandbox path volume allows two containers // nested under the same parent container to share data. // TODO(jieyu): Parameterize this test to test both linux and posix // launcher and filesystem isolator. TEST_F(VolumeSandboxPathIsolatorTest, SharedVolume) { slave::Flags flags = CreateSlaveFlags(); flags.isolation = "volume/sandbox_path"; Fetcher fetcher; Try<MesosContainerizer*> create = MesosContainerizer::create( flags, true, &fetcher); ASSERT_SOME(create); Owned<MesosContainerizer> containerizer(create.get()); SlaveState state; state.id = SlaveID(); AWAIT_READY(containerizer->recover(state)); ContainerID containerId; containerId.set_value(UUID::random().toString()); ExecutorInfo executor = createExecutorInfo("executor", "sleep 99", "cpus:1"); Try<string> directory = environment->mkdtemp(); ASSERT_SOME(directory); Future<bool> launch = containerizer->launch( containerId, None(), executor, directory.get(), None(), state.id, map<string, string>(), true); // TODO(benh): Ever want to check not-checkpointing? AWAIT_ASSERT_TRUE(launch); ContainerID nestedContainerId1; nestedContainerId1.mutable_parent()->CopyFrom(containerId); nestedContainerId1.set_value(UUID::random().toString()); ContainerInfo containerInfo; containerInfo.set_type(ContainerInfo::MESOS); Volume* volume = containerInfo.add_volumes(); volume->set_mode(Volume::RW); volume->set_container_path("parent"); Volume::Source* source = volume->mutable_source(); source->set_type(Volume::Source::SANDBOX_PATH); Volume::Source::SandboxPath* sandboxPath = source->mutable_sandbox_path(); sandboxPath->set_type(Volume::Source::SandboxPath::PARENT); sandboxPath->set_path("shared"); launch = containerizer->launch( nestedContainerId1, createCommandInfo("touch parent/file; sleep 1000"), containerInfo, None(), state.id); AWAIT_ASSERT_TRUE(launch); ContainerID nestedContainerId2; nestedContainerId2.mutable_parent()->CopyFrom(containerId); nestedContainerId2.set_value(UUID::random().toString()); launch = containerizer->launch( nestedContainerId2, createCommandInfo( "while true; do if [ -f parent/file ]; then exit 0; fi; done"), containerInfo, None(), state.id); AWAIT_ASSERT_TRUE(launch); Future<Option<ContainerTermination>> wait = containerizer->wait(nestedContainerId2); AWAIT_READY(wait); ASSERT_SOME(wait.get()); ASSERT_TRUE(wait.get()->has_status()); EXPECT_WEXITSTATUS_EQ(0, wait.get()->status()); wait = containerizer->wait(containerId); containerizer->destroy(containerId); AWAIT_READY(wait); ASSERT_SOME(wait.get()); ASSERT_TRUE(wait.get()->has_status()); EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status()); }
void LowSpeedLink::Handler(int status) { /* Matt: Just for testing! */ char buff[100]; /* Matt: Ensure the file descriptor for the low speed device is valid. * If lsfd = 0, then it isn't valid. Return from the handler. */ if(fd == 0) return; /* Matt: Read all avaiable characters on the tty device. */ int ret = read(fd, buff, 64); for(int i = 0; i < ret; i+=1) { /*--------------------------------------------------------------------*/ /* Matt: This section is just for testing. */ if(buff[i] == 'x') exit(1); /* Matt: This is a rough example of steps which need to be taken when a * complete command packet has been recieved. */ else if(buff[i] == 'c') { /* Matt: The "pretend" command. */ uchar id = 0x55; // command id uchar len = 0x01; // length of the command data uchar data[1] = {0xAA}; // command data /* Matt: Each of these three steps MUST be carried out for each * command packet recieved. * * 1.) Create a new commmand info structure in which each piece of * the command will be packed. * NOTE: createCommandInfo makes a DEEP COPY of the command data * 2.) Push the pointer to the command info structure into the * command queue. * 3.) Increment the data availability semaphore. */ CommandInfo *info = createCommandInfo(id, len, data); // step 1 cmdQueue.push(info); // step 2 sem_post(&execHalt); // step 3 } /* Matt: This is a rough example of steps which need to be taken when a * complete file transfer packet has been recieved. */ else if(buff[i] == 'f') { /* Matt: The "pretend" command. */ uchar sess = 0x55; // session id uchar len = 0x01; // length of the file transfer data uchar data[1] = {0xAA}; // file transfer data uchar block = 0x03; // block id /* Matt: Each of these three steps MUST be carried out for each * file transfer packet recieved. * * 1.) Create a new file transfer info structure in which each piece * of the file transfer will be packed. * NOTE: createFileTransInfo makes a DEEP COPY of the file * transfer data * 2.) Push the pointer to the file transfer info structure into the * file queue. * 3.) Increment the data availability semaphore. */ FileTransInfo *info = createFileTransInfo(sess, len, // step 1 data, block); fileQueue.push(info); // step 2 sem_post(&execHalt); // step 3 } /* Matt: End of the testing section. */ /*--------------------------------------------------------------------*/ } }
TEST(AgentCallValidationTest, LaunchNestedContainerSession) { // Missing `launch_nested_container_session`. agent::Call call; call.set_type(agent::Call::LAUNCH_NESTED_CONTAINER_SESSION); Option<Error> error = validation::agent::call::validate(call); EXPECT_SOME(error); // `container_id` is not valid. ContainerID badContainerId; badContainerId.set_value("no spaces allowed"); agent::Call::LaunchNestedContainerSession* launch = call.mutable_launch_nested_container_session(); launch->mutable_container_id()->CopyFrom(badContainerId); error = validation::agent::call::validate(call); EXPECT_SOME(error); // Valid `container_id` but missing `container_id.parent`. ContainerID containerId; containerId.set_value(UUID::random().toString()); launch->mutable_container_id()->CopyFrom(containerId); error = validation::agent::call::validate(call); EXPECT_SOME(error); // Valid `container_id.parent` but invalid `command.environment`. Set // an invalid environment variable to check that the common validation // code for the command's environment is being executed. ContainerID parentContainerId; parentContainerId.set_value(UUID::random().toString()); launch->mutable_container_id()->mutable_parent()->CopyFrom(parentContainerId); launch->mutable_command()->CopyFrom(createCommandInfo("exit 0")); Environment::Variable* variable = launch ->mutable_command() ->mutable_environment() ->mutable_variables() ->Add(); variable->set_name("ENV_VAR_KEY"); variable->set_type(mesos::Environment::Variable::VALUE); error = validation::agent::call::validate(call); EXPECT_SOME(error); EXPECT_EQ( "'launch_nested_container_session.command' is invalid: Environment " "variable 'ENV_VAR_KEY' of type 'VALUE' must have a value set", error->message); // Test the valid case. variable->set_value("env_var_value"); error = validation::agent::call::validate(call); EXPECT_NONE(error); // Any number of parents is valid. ContainerID grandparentContainerId; grandparentContainerId.set_value(UUID::random().toString()); launch->mutable_container_id()->mutable_parent()->mutable_parent()->CopyFrom( grandparentContainerId); error = validation::agent::call::validate(call); EXPECT_NONE(error); }