You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2017/12/14 05:03:20 UTC
[5/7] mesos git commit: Add a unit test for pre-existing volume
support in SLRP.
Add a unit test for pre-existing volume support in SLRP.
Review: https://reviews.apache.org/r/64584/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4d895545
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4d895545
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4d895545
Branch: refs/heads/master
Commit: 4d895545891e09da063c4e845621557f75b4f6b3
Parents: 673b421
Author: Chun-Hung Hsiao <ch...@mesosphere.io>
Authored: Wed Dec 13 20:47:07 2017 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Dec 13 20:47:07 2017 -0800
----------------------------------------------------------------------
.../storage_local_resource_provider_tests.cpp | 239 ++++++++++++++++---
1 file changed, 207 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/4d895545/src/tests/storage_local_resource_provider_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/storage_local_resource_provider_tests.cpp b/src/tests/storage_local_resource_provider_tests.cpp
index 20f4f76..1d6ce8e 100644
--- a/src/tests/storage_local_resource_provider_tests.cpp
+++ b/src/tests/storage_local_resource_provider_tests.cpp
@@ -83,7 +83,8 @@ public:
"value": "%s",
"arguments": [
"%s",
- "--available_capacity=4GB",
+ "--available_capacity=2GB",
+ "--volumes=volume1:1GB;volume2:1GB",
"--work_dir=%s"
]
}
@@ -109,10 +110,10 @@ protected:
};
-// This test verifies that a framework can create then destroy a volume
-// from the resources provided by a storage local resource provider that
-// uses the test CSI plugin.
-TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
+// This test verifies that a framework can create then destroy a new
+// volume from the storage pool of a storage local resource provider
+// that uses the test CSI plugin.
+TEST_F(StorageLocalResourceProviderTest, ROOT_NewVolume)
{
Try<Owned<cluster::Master>> master = StartMaster();
ASSERT_SOME(master);
@@ -173,10 +174,15 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
Sequence offers;
- auto isSourceType = [](
- const Resource& r, const Resource::DiskInfo::Source::Type& type) {
+ // We are only interested in storage pools and volume created from
+ // them, which have a "default" profile.
+ auto hasSourceType = [](
+ const Resource& r,
+ const Resource::DiskInfo::Source::Type& type) {
return r.has_disk() &&
r.disk().has_source() &&
+ r.disk().source().has_profile() &&
+ r.disk().source().profile() == "default" &&
r.disk().source().type() == type;
};
@@ -185,17 +191,17 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
.WillRepeatedly(DeclineOffers());
EXPECT_CALL(sched, resourceOffers(&driver, OffersHaveAnyResource(
- std::bind(isSourceType, lambda::_1, Resource::DiskInfo::Source::RAW))))
+ std::bind(hasSourceType, lambda::_1, Resource::DiskInfo::Source::RAW))))
.InSequence(offers)
.WillOnce(FutureArg<1>(&rawDiskOffers));
EXPECT_CALL(sched, resourceOffers(&driver, OffersHaveAnyResource(
- std::bind(isSourceType, lambda::_1, Resource::DiskInfo::Source::MOUNT))))
+ std::bind(hasSourceType, lambda::_1, Resource::DiskInfo::Source::MOUNT))))
.InSequence(offers)
.WillOnce(FutureArg<1>(&volumeCreatedOffers));
EXPECT_CALL(sched, resourceOffers(&driver, OffersHaveAnyResource(
- std::bind(isSourceType, lambda::_1, Resource::DiskInfo::Source::RAW))))
+ std::bind(hasSourceType, lambda::_1, Resource::DiskInfo::Source::RAW))))
.InSequence(offers)
.WillOnce(FutureArg<1>(&volumeDestroyedOffers));
@@ -207,9 +213,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
Option<Resource> source;
foreach (const Resource& resource, rawDiskOffers->at(0).resources()) {
- if (resource.has_disk() &&
- resource.disk().has_source() &&
- resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+ if (hasSourceType(resource, Resource::DiskInfo::Source::RAW)) {
source = resource;
break;
}
@@ -229,9 +233,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
Option<Resource> volume;
foreach (const Resource& resource, volumeCreatedOffers->at(0).resources()) {
- if (resource.has_disk() &&
- resource.disk().has_source() &&
- resource.disk().source().type() == Resource::DiskInfo::Source::MOUNT) {
+ if (hasSourceType(resource, Resource::DiskInfo::Source::MOUNT)) {
volume = resource;
break;
}
@@ -269,9 +271,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
Option<Resource> destroyed;
foreach (const Resource& resource, volumeDestroyedOffers->at(0).resources()) {
- if (resource.has_disk() &&
- resource.disk().has_source() &&
- resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+ if (hasSourceType(resource, Resource::DiskInfo::Source::RAW)) {
destroyed = resource;
break;
}
@@ -288,9 +288,9 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_CreateVolumeAndDestroyVolume)
// This test verifies that a framework can launch a task using a created
-// volume provided by a storage local resource provider that uses the
-// test CSI plugin, then destroy the volume while it is published.
-TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
+// volume from a storage local resource provider that uses the test CSI
+// plugin, then destroy the volume while it is published.
+TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchTask)
{
Try<Owned<cluster::Master>> master = StartMaster();
ASSERT_SOME(master);
@@ -356,10 +356,15 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
Sequence offers;
- auto isSourceType = [](
- const Resource& r, const Resource::DiskInfo::Source::Type& type) {
+ // We are only interested in storage pools and volume created from
+ // them, which have a "default" profile.
+ auto hasSourceType = [](
+ const Resource& r,
+ const Resource::DiskInfo::Source::Type& type) {
return r.has_disk() &&
r.disk().has_source() &&
+ r.disk().source().has_profile() &&
+ r.disk().source().profile() == "default" &&
r.disk().source().type() == type;
};
@@ -368,7 +373,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
.WillRepeatedly(DeclineOffers());
EXPECT_CALL(sched, resourceOffers(&driver, OffersHaveAnyResource(
- std::bind(isSourceType, lambda::_1, Resource::DiskInfo::Source::RAW))))
+ std::bind(hasSourceType, lambda::_1, Resource::DiskInfo::Source::RAW))))
.InSequence(offers)
.WillOnce(FutureArg<1>(&rawDiskOffers));
@@ -380,9 +385,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
Option<Resource> source;
foreach (const Resource& resource, rawDiskOffers->at(0).resources()) {
- if (resource.has_disk() &&
- resource.disk().has_source() &&
- resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+ if (hasSourceType(resource, Resource::DiskInfo::Source::RAW)) {
source = resource;
break;
}
@@ -392,7 +395,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
// Create a volume.
EXPECT_CALL(sched, resourceOffers(&driver, OffersHaveAnyResource(
- std::bind(isSourceType, lambda::_1, Resource::DiskInfo::Source::MOUNT))))
+ std::bind(hasSourceType, lambda::_1, Resource::DiskInfo::Source::MOUNT))))
.InSequence(offers)
.WillOnce(FutureArg<1>(&volumeCreatedOffers));
@@ -407,9 +410,7 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
Option<Resource> volume;
foreach (const Resource& resource, volumeCreatedOffers->at(0).resources()) {
- if (resource.has_disk() &&
- resource.disk().has_source() &&
- resource.disk().source().type() == Resource::DiskInfo::Source::MOUNT) {
+ if (hasSourceType(resource, Resource::DiskInfo::Source::MOUNT)) {
volume = resource;
break;
}
@@ -501,6 +502,180 @@ TEST_F(StorageLocalResourceProviderTest, ROOT_LaunchAndDestroyVolume)
EXPECT_FALSE(os::exists(volumePath.get()));
}
+
+// This test verifies that a framework can convert pre-existing volumes
+// from a storage local resource provider that uses the test CSI plugin
+// into mount or block volumes.
+TEST_F(StorageLocalResourceProviderTest, ROOT_PreExistingVolume)
+{
+ Try<Owned<cluster::Master>> master = StartMaster();
+ ASSERT_SOME(master);
+
+ Owned<MasterDetector> detector = master.get()->createDetector();
+
+ slave::Flags flags = CreateSlaveFlags();
+ flags.isolation = "filesystem/linux";
+
+ // Disable HTTP authentication to simplify resource provider interactions.
+ flags.authenticate_http_readwrite = false;
+
+ // Set the resource provider capability and other required capabilities.
+ constexpr SlaveInfo::Capability::Type capabilities[] = {
+ SlaveInfo::Capability::MULTI_ROLE,
+ SlaveInfo::Capability::HIERARCHICAL_ROLE,
+ SlaveInfo::Capability::RESERVATION_REFINEMENT,
+ SlaveInfo::Capability::RESOURCE_PROVIDER
+ };
+
+ flags.agent_features = SlaveCapabilities();
+ foreach (SlaveInfo::Capability::Type type, capabilities) {
+ flags.agent_features->add_capabilities()->set_type(type);
+ }
+
+ flags.resource_provider_config_dir = resourceProviderConfigDir;
+
+ Future<SlaveRegisteredMessage> slaveRegisteredMessage =
+ FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
+
+ Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
+ ASSERT_SOME(slave);
+
+ AWAIT_READY(slaveRegisteredMessage);
+
+ // Register a framework to exercise offer operations.
+ FrameworkInfo framework = DEFAULT_FRAMEWORK_INFO;
+ framework.set_roles(0, "storage");
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, framework, master.get()->pid, DEFAULT_CREDENTIAL);
+
+ // We use the filter explicitly here so that the resources will not
+ // be filtered for 5 seconds (the default).
+ Filters filters;
+ filters.set_refuse_seconds(0);
+
+ EXPECT_CALL(sched, registered(&driver, _, _));
+
+ // The framework is expected to see the following offers in sequence:
+ // 1. One containing two RAW disk resources for pre-existing volumes
+ // before `CREATE_VOLUME` and `CREATE_BLOCK`.
+ // 2. One containing a MOUNT and a BLOCK disk resources after
+ // `CREATE_VOLUME` and `CREATE_BLOCK`.
+ // 3. One containing two RAW disk resources for pre-existing volumes
+ // resource after `DSTROY_VOLUME` and `DESTROY_BLOCK`.
+ Future<vector<Offer>> rawDisksOffers;
+ Future<vector<Offer>> disksConvertedOffers;
+ Future<vector<Offer>> disksRevertedOffers;
+
+ // We are only interested in pre-existing volumes, which have IDs but
+ // no profile.
+ auto isPreExistingVolume = [](const Resource& r) {
+ return r.has_disk() &&
+ r.disk().has_source() &&
+ r.disk().source().has_id() &&
+ !r.disk().source().has_profile();
+ };
+
+ // Decline offers that contain only the agent's default resources.
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillRepeatedly(DeclineOffers());
+
+ EXPECT_CALL(sched, resourceOffers(&driver, OffersHaveAnyResource(
+ isPreExistingVolume)))
+ .WillOnce(FutureArg<1>(&rawDisksOffers))
+ .WillOnce(FutureArg<1>(&disksConvertedOffers))
+ .WillOnce(FutureArg<1>(&disksRevertedOffers));
+
+ driver.start();
+
+ AWAIT_READY(rawDisksOffers);
+ ASSERT_FALSE(rawDisksOffers->empty());
+
+ vector<Resource> sources;
+
+ foreach (const Resource& resource, rawDisksOffers->at(0).resources()) {
+ if (isPreExistingVolume(resource) &&
+ resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+ sources.push_back(resource);
+ }
+ }
+
+ ASSERT_EQ(2, sources.size());
+
+ // Create a volume and a block.
+ driver.acceptOffers(
+ {rawDisksOffers->at(0).id()},
+ {CREATE_VOLUME(sources.at(0), Resource::DiskInfo::Source::MOUNT),
+ CREATE_BLOCK(sources.at(1))},
+ filters);
+
+ AWAIT_READY(disksConvertedOffers);
+ ASSERT_FALSE(disksConvertedOffers->empty());
+
+ Option<Resource> volume;
+ Option<Resource> block;
+
+ foreach (const Resource& resource, disksConvertedOffers->at(0).resources()) {
+ if (isPreExistingVolume(resource)) {
+ if (resource.disk().source().type() ==
+ Resource::DiskInfo::Source::MOUNT) {
+ volume = resource;
+ } else if (resource.disk().source().type() ==
+ Resource::DiskInfo::Source::BLOCK) {
+ block = resource;
+ }
+ }
+ }
+
+ ASSERT_SOME(volume);
+ ASSERT_TRUE(volume->disk().source().has_mount());
+ ASSERT_TRUE(volume->disk().source().mount().has_root());
+ EXPECT_FALSE(path::absolute(volume->disk().source().mount().root()));
+
+ ASSERT_SOME(block);
+
+ // Destroy the created volume.
+ driver.acceptOffers(
+ {disksConvertedOffers->at(0).id()},
+ {DESTROY_VOLUME(volume.get()),
+ DESTROY_BLOCK(block.get())},
+ filters);
+
+ AWAIT_READY(disksRevertedOffers);
+ ASSERT_FALSE(disksRevertedOffers->empty());
+
+ vector<Resource> destroyed;
+
+ foreach (const Resource& resource, disksRevertedOffers->at(0).resources()) {
+ if (isPreExistingVolume(resource) &&
+ resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+ destroyed.push_back(resource);
+ }
+ }
+
+ ASSERT_EQ(2, destroyed.size());
+
+ foreach (const Resource& resource, destroyed) {
+ ASSERT_FALSE(resource.disk().source().has_mount());
+ ASSERT_TRUE(resource.disk().source().has_metadata());
+
+ // Check if the volume is not deleted by the test CSI plugin.
+ Option<string> volumePath;
+
+ foreach (const Label& label, resource.disk().source().metadata().labels()) {
+ if (label.key() == "path") {
+ volumePath = label.value();
+ break;
+ }
+ }
+
+ ASSERT_SOME(volumePath);
+ EXPECT_TRUE(os::exists(volumePath.get()));
+ }
+}
+
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {