const int RECONNECT_RETRIES = 15;
const int RECONNECT_DELAY = 1 * 1000;
+const std::string STATE_STOPPED = "stopped";
+const std::string STATE_RUNNING = "running";
+const std::string STATE_PAUSED = "paused";
+
} // namespace
Zone::Zone(const utils::Worker::Pointer& worker,
const std::string& lxcTemplatePrefix,
const std::string& baseRunMountPointPath)
: mWorker(worker)
+ , mDbPath(dbPath)
{
const std::string dbPrefix = getZoneDbPrefix(zoneId);
config::loadFromKVStoreWithJsonFile(dbPath, zoneTemplatePath, mConfig, dbPrefix);
return mConfig.privilege;
}
+void Zone::saveDynamicConfig()
+{
+ config::saveToKVStore(mDbPath, mDynamicConfig, getZoneDbPrefix(getId()));
+}
+
+void Zone::updateRequestedState(const std::string& state)
+{
+ // assume mutex is locked
+ if (state != mDynamicConfig.requestedState) {
+ LOGT("Set requested state of " << getId() << " to " << state);
+ mDynamicConfig.requestedState = state;
+ saveDynamicConfig();
+ }
+}
+
+void Zone::restore()
+{
+ std::string requestedState;
+ {
+ Lock lock(mReconnectMutex);
+ requestedState = mDynamicConfig.requestedState;
+ LOGT("Requested state of " << getId() << ": " << requestedState);
+ }
+
+ if (requestedState == STATE_RUNNING) {
+ start();
+ } else if (requestedState == STATE_STOPPED) {
+ } else if (requestedState == STATE_PAUSED) {
+ start();
+ suspend();
+ } else {
+ LOGE("Invalid requested state: " << requestedState);
+ assert(0 && "invalid requested state");
+ }
+}
+
void Zone::start()
{
Lock lock(mReconnectMutex);
+ updateRequestedState(STATE_RUNNING);
mProvision->start();
if (mConfig.enableDbusIntegration) {
mConnectionTransport.reset(new ZoneConnectionTransport(mRunMountPoint));
// refocus in ZonesManager will adjust cpu quota after all
}
-void Zone::stop()
+void Zone::stop(bool saveState)
{
Lock lock(mReconnectMutex);
+ if (saveState) {
+ updateRequestedState(STATE_STOPPED);
+ }
if (mAdmin->isRunning()) {
// boost stopping
goForeground();
int Zone::getVT() const
{
+ Lock lock(mReconnectMutex);
return mDynamicConfig.vt;
}
{
Lock lock(mReconnectMutex);
mAdmin->suspend();
+ updateRequestedState(STATE_PAUSED);
}
void Zone::resume()
{
Lock lock(mReconnectMutex);
mAdmin->resume();
+ updateRequestedState(STATE_RUNNING);
}
bool Zone::isPaused()
}
LOGE(getId() << ": Reconnecting to the DBUS has failed, stopping the zone");
- stop();
+ stop(false);
}
void Zone::setNotifyActiveZoneCallback(const NotifyActiveZoneCallback& callback)
if (!mDetachOnExit) {
try {
- stopAll();
+ shutdownAll();
} catch (ServerException&) {
- LOGE("Failed to stop all of the zones");
+ LOGE("Failed to shutdown all of the zones");
}
}
// wait for all tasks to complete
focusInternal(iter);
}
-void ZonesManager::startAll()
+void ZonesManager::restoreAll()
{
- LOGI("Starting all zones");
+ LOGI("Restoring all zones");
Lock lock(mMutex);
for (auto& zone : mZones) {
- zone->start();
+ zone->restore();
}
refocus();
}
-void ZonesManager::stopAll()
+void ZonesManager::shutdownAll()
{
LOGI("Stopping all zones");
Lock lock(mMutex);
for (auto& zone : mZones) {
- zone->stop();
+ zone->stop(false);
}
refocus();
bool ZonesManager::isPaused(const std::string& zoneId)
{
Lock lock(mMutex);
-
- auto iter = findZone(zoneId);
- if (iter == mZones.end()) {
- LOGE("No such zone id: " << zoneId);
- throw InvalidZoneIdException("No such zone");
- }
-
- return get(iter).isPaused();
+ return getZone(zoneId).isPaused();
}
bool ZonesManager::isRunning(const std::string& zoneId)
{
Lock lock(mMutex);
+ return getZone(zoneId).isRunning();
+}
- auto iter = findZone(zoneId);
- if (iter == mZones.end()) {
- LOGE("No such zone id: " << zoneId);
- throw InvalidZoneIdException("No such zone");
- }
- return get(iter).isRunning();
+bool ZonesManager::isStopped(const std::string& zoneId)
+{
+ Lock lock(mMutex);
+ return getZone(zoneId).isStopped();
}
std::string ZonesManager::getRunningForegroundZoneId()
result->setError(api::ERROR_INVALID_ID, "No such zone id");
return;
}
- get(iter).stop();
+ get(iter).stop(true);
refocus();
result->setVoid();
} catch (ZoneOperationException& e) {
cm.createZone("zone1", SIMPLE_TEMPLATE);
cm.createZone("zone2", SIMPLE_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1");
- cm.stopAll();
+ cm.shutdownAll();
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "");
}
ZonesManager cm(TEST_CONFIG_PATH);
cm.createZone("zone1", SIMPLE_TEMPLATE);
cm.createZone("zone2", SIMPLE_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1");
cm.setZonesDetachOnExit();
}
{
ZonesManager cm(TEST_CONFIG_PATH);
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "zone1");
}
}
cm.createZone("zone1", SIMPLE_TEMPLATE);
cm.createZone("zone2", SIMPLE_TEMPLATE);
cm.createZone("zone3", SIMPLE_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK(cm.getRunningForegroundZoneId() == "zone1");
cm.focus("zone2");
cm.createZone("zone1", DBUS_TEMPLATE);
cm.createZone("zone2", DBUS_TEMPLATE);
cm.createZone("zone3", DBUS_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
Latch signalReceivedLatch;
std::map<int, std::vector<std::string>> signalReceivedSourcesMap;
cm.createZone("zone1", DBUS_TEMPLATE);
cm.createZone("zone2", DBUS_TEMPLATE);
cm.createZone("zone3", DBUS_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
std::vector<std::unique_ptr<DbusAccessory>> clients;
for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) {
cm.createZone("zone1", DBUS_TEMPLATE);
cm.createZone("zone2", DBUS_TEMPLATE);
cm.createZone("zone3", DBUS_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
Latch notificationLatch;
std::string notificationSource;
cm.createZone("zone1", DBUS_TEMPLATE);
cm.createZone("zone2", DBUS_TEMPLATE);
cm.createZone("zone3", DBUS_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
std::vector<std::unique_ptr<DbusAccessory>> clients;
for (int i = 1; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) {
cm.createZone("zone1", DBUS_TEMPLATE);
cm.createZone("zone2", DBUS_TEMPLATE);
cm.createZone("zone3", DBUS_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
std::map<int, std::unique_ptr<DbusAccessory>> dbuses;
for (int i = 0; i <= TEST_DBUS_CONNECTION_ZONES_COUNT; ++i) {
cm.createZone("zone3", DBUS_TEMPLATE);
BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses());
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK(EXPECTED_DBUSES_ALL == host.callMethodGetZoneDbuses());
- cm.stopAll();
+ cm.shutdownAll();
BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses());
}
cm.createZone("zone3", SIMPLE_TEMPLATE);
BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses());
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses());
- cm.stopAll();
+ cm.shutdownAll();
BOOST_CHECK(EXPECTED_DBUSES_NONE == host.callMethodGetZoneDbuses());
}
BOOST_CHECK(signalLatch.empty());
BOOST_CHECK(collectedDbuses.empty());
- cm.startAll();
+ cm.restoreAll();
BOOST_REQUIRE(signalLatch.waitForN(TEST_DBUS_CONNECTION_ZONES_COUNT, EVENT_TIMEOUT));
BOOST_CHECK(signalLatch.empty());
cm.createZone("zone1", SIMPLE_TEMPLATE);
cm.createZone("zone2", SIMPLE_TEMPLATE);
cm.createZone("zone3", SIMPLE_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
DbusAccessory dbus(DbusAccessory::HOST_ID);
BOOST_CHECK(dbus.callMethodGetActiveZoneId() == zoneId);
}
- cm.stopAll();
+ cm.shutdownAll();
BOOST_CHECK(dbus.callMethodGetActiveZoneId() == "");
}
cm.createZone("zone1", SIMPLE_TEMPLATE);
cm.createZone("zone2", SIMPLE_TEMPLATE);
cm.createZone("zone3", SIMPLE_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
DbusAccessory dbus(DbusAccessory::HOST_ID);
DbusException,
WhatEquals("No such zone id"));
- cm.stopAll();
+ cm.shutdownAll();
BOOST_REQUIRE_EXCEPTION(dbus.callMethodSetActiveZone("zone1"),
DbusException,
WhatEquals("Could not activate stopped or paused zone"));
const std::string zone3 = "test3";
ZonesManager cm(TEST_CONFIG_PATH);
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "");
dbus.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback);
BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
- cm.startAll();
+ cm.restoreAll();
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1);
cm.focus(zone3);
auto getZoneIds = []() -> std::vector<std::string> {
ZonesManager cm(TEST_CONFIG_PATH);
- cm.startAll();
+ cm.restoreAll();
DbusAccessory dbus(DbusAccessory::HOST_ID);
return dbus.callMethodGetZoneIds();
BOOST_CHECK(getZoneIds().empty());
}
+BOOST_AUTO_TEST_CASE(ZoneStatePersistenceTest)
+{
+ const std::string zone1 = "zone1";
+ const std::string zone2 = "zone2";
+ const std::string zone3 = "zone3";
+ const std::string zone4 = "zone4";
+ const std::string zone5 = "zone5";
+
+ Latch callDone;
+ auto resultCallback = [&]() {
+ callDone.set();
+ };
+
+ // firts run
+ {
+ ZonesManager cm(TEST_CONFIG_PATH);
+ DbusAccessory dbus(DbusAccessory::HOST_ID);
+
+ // zone1 - created
+ dbus.callAsyncMethodCreateZone(zone1, SIMPLE_TEMPLATE, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+
+ // zone2 - started
+ dbus.callAsyncMethodCreateZone(zone2, SIMPLE_TEMPLATE, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodStartZone(zone2, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ BOOST_CHECK(cm.isRunning(zone2));
+
+ // zone3 - started then paused
+ dbus.callAsyncMethodCreateZone(zone3, SIMPLE_TEMPLATE, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodStartZone(zone3, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callMethodLockZone(zone3);
+ BOOST_CHECK(cm.isPaused(zone3));
+
+ // zone4 - started then stopped
+ dbus.callAsyncMethodCreateZone(zone4, SIMPLE_TEMPLATE, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodStartZone(zone4, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodShutdownZone(zone4, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ BOOST_CHECK(cm.isStopped(zone4));
+
+ // zone5 - started then stopped then started
+ dbus.callAsyncMethodCreateZone(zone5, SIMPLE_TEMPLATE, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodStartZone(zone5, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodShutdownZone(zone5, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ dbus.callAsyncMethodStartZone(zone5, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+ BOOST_CHECK(cm.isRunning(zone5));
+ }
+
+ // second run
+ {
+ ZonesManager cm(TEST_CONFIG_PATH);
+ cm.restoreAll();
+
+ BOOST_CHECK(cm.isRunning(zone1)); // because the default json value
+ BOOST_CHECK(cm.isRunning(zone2));
+ BOOST_CHECK(cm.isPaused(zone3));
+ BOOST_CHECK(cm.isStopped(zone4));
+ BOOST_CHECK(cm.isRunning(zone5));
+ }
+}
+
BOOST_AUTO_TEST_CASE(StartShutdownZoneTest)
{
const std::string zone1 = "zone1";
cm.createZone("zone1", DBUS_TEMPLATE);
cm.createZone("zone2", DBUS_TEMPLATE);
cm.createZone("zone3", DBUS_TEMPLATE);
- cm.startAll();
+ cm.restoreAll();
DbusAccessory dbus(DbusAccessory::HOST_ID);
DbusException,
WhatEquals("No such zone id"));
- cm.stopAll();
+ cm.shutdownAll();
BOOST_REQUIRE_EXCEPTION(dbus.callMethodLockZone("zone1"),
DbusException,
WhatEquals("Zone is not running"));