lxcpp: fix cgroup unit tests
[platform/core/security/vasum.git] / server / zones-manager.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak <j.olszak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Jan Olszak (j.olszak@samsung.com)
22  * @brief   Definition of the class for managing zones
23  */
24
25 #include "config.hpp"
26
27 #include "common-definitions.hpp"
28 #include "dynamic-config-scheme.hpp"
29 #include "zones-manager.hpp"
30 #include "lxc/cgroup.hpp"
31 #include "exception.hpp"
32
33 #include "utils/paths.hpp"
34 #include "logger/logger.hpp"
35 #include "config/manager.hpp"
36 #include "dbus/exception.hpp"
37 #include "utils/fs.hpp"
38 #include "utils/img.hpp"
39 #include "utils/environment.hpp"
40 #include "utils/vt.hpp"
41 #include "api/messages.hpp"
42
43 #include <boost/filesystem.hpp>
44 #include <boost/exception/diagnostic_information.hpp>
45 #include <cassert>
46 #include <string>
47 #include <climits>
48 #include <cctype>
49 #include <set>
50
51 #ifdef USE_BOOST_REGEX
52 #include <boost/regex.hpp>
53 namespace rgx = boost;
54 #else
55 #include <regex>
56 namespace rgx = std;
57 #endif
58
59 namespace vasum {
60
61
62 namespace {
63
64
65 const std::string HOST_ID = "host";
66 const std::string ENABLED_FILE_NAME = "enabled";
67
68 const rgx::regex ZONE_NAME_REGEX("~NAME~");
69 const rgx::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~");
70
71 const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100;
72
73 const std::vector<std::string> prohibitedZonesNames{
74     ENABLED_FILE_NAME,
75     "lxc-monitord.log"
76 };
77
78 template<typename T>
79 void remove(std::vector<T>& v, const T& item)
80 {
81     // erase-remove idiom, ask google for explanation
82     v.erase(std::remove(v.begin(), v.end(), item), v.end());
83 }
84
85 template<typename Iter, typename Predicate>
86 Iter circularFindNext(Iter begin, Iter end, Iter current, Predicate pred)
87 {
88     if (begin == end || current == end) {
89         return end;
90     }
91     for (Iter next = current;;) {
92         ++ next;
93         if (next == end) {
94             next = begin;
95         }
96         if (next == current) {
97             return end;
98         }
99         if (pred(*next)) {
100             return next;
101         }
102     }
103 }
104
105 Zone& get(std::vector<std::unique_ptr<Zone>>::iterator iter)
106 {
107     return **iter;
108 }
109
110 bool zoneIsRunning(const std::unique_ptr<Zone>& zone) {
111     return zone->isRunning();
112 }
113
114 bool isalnum(const std::string& str)
115 {
116     for (const auto& c : str) {
117         if (!std::isalnum(c)) {
118             return false;
119         }
120     }
121     return true;
122 }
123
124 void cleanUpUnknownsFromRoot(const boost::filesystem::path& zonesPath,
125                              const std::vector<std::string>& zoneIds,
126                              bool dryRun)
127 {
128     namespace fs =  boost::filesystem;
129     const auto end = fs::directory_iterator();
130
131     std::set<std::string> knowns(zoneIds.begin(), zoneIds.end());
132     knowns.insert(prohibitedZonesNames.begin(), prohibitedZonesNames.end());
133
134     // Remove all directories that start with '.'
135     for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) {
136         if (zoneDir->path().filename().string()[0] ==  '.') {
137             if (!dryRun) {
138                 fs::remove_all(zoneDir->path());
139                 LOGI("Remove directory entry: " << *zoneDir);
140             } else {
141                 LOGI("Remove directory entry (dry run): " << *zoneDir);
142             }
143         }
144     }
145
146     for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) {
147         const auto zoneIt = knowns.find(zoneDir->path().filename().string());
148         if (zoneIt == knowns.end()) {
149             if (!dryRun) {
150                 const std::string filename = '.' + zoneDir->path().filename().string();
151                 fs::path newName = zoneDir->path().parent_path() / filename;
152
153                 fs::rename(zoneDir->path(), newName);
154                 fs::remove_all(newName);
155                 LOGI("Remove directory entry: " << *zoneDir);
156             } else {
157                 LOGI("Remove directory entry (dry run): " << *zoneDir);
158             }
159         }
160     }
161 }
162
163 } // namespace
164
165
166 ZonesManager::ZonesManager(ipc::epoll::EventPoll& eventPoll, const std::string& configPath)
167     : mIsRunning(true)
168     , mWorker(utils::Worker::create())
169     , mDetachOnExit(false)
170     , mExclusiveIDLock(INVALID_CONNECTION_ID)
171     , mHostIPCConnection(eventPoll, this)
172 #ifdef DBUS_CONNECTION
173     , mHostDbusConnection(this)
174 #endif
175 {
176     LOGD("Instantiating ZonesManager object...");
177
178     config::loadFromJsonFile(configPath, mConfig);
179     config::loadFromKVStoreWithJsonFile(mConfig.dbPath,
180                                         configPath,
181                                         mDynamicConfig,
182                                         getVasumDbPrefix());
183
184     if (mConfig.inputConfig.enabled) {
185         LOGI("Registering input monitor [" << mConfig.inputConfig.device.c_str() << "]");
186         mSwitchingSequenceMonitor.reset(new InputMonitor(eventPoll, mConfig.inputConfig, this));
187     }
188 }
189
190 ZonesManager::~ZonesManager()
191 {
192     LOGD("Destroying ZonesManager object...");
193     stop(true);
194 }
195
196 void ZonesManager::start()
197 {
198     Lock lock(mMutex);
199
200     LOGD("Starting ZonesManager");
201
202     mIsRunning = true;
203
204     cleanUpUnknownsFromRoot(mConfig.zonesPath, mDynamicConfig.zoneIds, !mConfig.cleanUpZonesPath);
205
206 #ifdef DBUS_CONNECTION
207     using namespace std::placeholders;
208     mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules));
209     mHostDbusConnection.setProxyCallCallback(std::bind(&ZonesManager::handleProxyCall,
210                                                        this, HOST_ID, _1, _2, _3, _4, _5, _6, _7));
211 #endif //DBUS_CONNECTION
212
213     for (const auto& zoneId : mDynamicConfig.zoneIds) {
214         insertZone(zoneId, getTemplatePathForExistingZone(zoneId));
215     }
216
217     updateDefaultId();
218
219     LOGD("ZonesManager object instantiated");
220
221     if (mConfig.inputConfig.enabled) {
222         LOGI("Starting input monitor ");
223         mSwitchingSequenceMonitor->start();
224     }
225
226     // After everything's initialized start to respond to clients' requests
227     mHostIPCConnection.start();
228 }
229
230 void ZonesManager::stop(bool wait)
231 {
232     Lock lock(mMutex);
233     LOGD("Stopping ZonesManager");
234
235     if(!mIsRunning) {
236         return;
237     }
238
239     if (!mDetachOnExit) {
240         try {
241             shutdownAll();
242         } catch (ServerException&) {
243             LOGE("Failed to shutdown all of the zones");
244         }
245     }
246
247     // wait for all tasks to complete
248     mWorker.reset();
249     mHostIPCConnection.stop(wait);
250     if (mConfig.inputConfig.enabled) {
251         LOGI("Stopping input monitor ");
252         mSwitchingSequenceMonitor->stop();
253     }
254     mIsRunning = false;
255 }
256
257 bool ZonesManager::isRunning()
258 {
259     Lock lock(mMutex);
260     return mIsRunning ||  mHostIPCConnection.isRunning();
261 }
262
263 ZonesManager::Zones::iterator ZonesManager::findZone(const std::string& id)
264 {
265     return std::find_if(mZones.begin(), mZones.end(), [&id](const std::unique_ptr<Zone>& zone) {
266         return zone->getId() == id;
267     });
268 }
269
270 Zone& ZonesManager::getZone(const std::string& id)
271 {
272     auto iter = findZone(id);
273     if (iter == mZones.end()) {
274         throw InvalidZoneIdException("Zone id not found");
275     }
276     return get(iter);
277 }
278
279 void ZonesManager::saveDynamicConfig()
280 {
281     config::saveToKVStore(mConfig.dbPath, mDynamicConfig, getVasumDbPrefix());
282 }
283
284 void ZonesManager::updateDefaultId()
285 {
286     // TODO add an api to change defaultId
287     if (mZones.empty() && mDynamicConfig.defaultId.empty()) {
288         LOGT("Keep empty defaultId");
289         return;
290     }
291     if (findZone(mDynamicConfig.defaultId) != mZones.end()) {
292         LOGT("Keep " << mDynamicConfig.defaultId << " as defaultId");
293         return;
294     }
295
296     // update
297     if (mZones.empty()) {
298         mDynamicConfig.defaultId.clear();
299         LOGD("DefaultId cleared");
300     } else {
301         mDynamicConfig.defaultId = mZones.front()->getId();
302         LOGD("DefaultId changed to " << mDynamicConfig.defaultId);
303     }
304     saveDynamicConfig();
305 }
306
307 std::string ZonesManager::getTemplatePathForExistingZone(const std::string& id)
308 {
309     ZoneTemplatePathConfig config;
310     config::loadFromKVStore(mConfig.dbPath, config, getZoneDbPrefix(id));
311     return config.zoneTemplatePath;
312 }
313
314 void ZonesManager::insertZone(const std::string& zoneId, const std::string& zoneTemplatePath)
315 {
316     if (zoneId == HOST_ID) {
317         throw InvalidZoneIdException("Cannot use reserved zone ID");
318     }
319     if (findZone(zoneId) != mZones.end()) {
320         throw InvalidZoneIdException("Zone already exists");
321     }
322
323     LOGT("Creating Zone " << zoneId);
324     std::unique_ptr<Zone> zone(new Zone(zoneId,
325                                         mConfig.zonesPath,
326                                         zoneTemplatePath,
327                                         mConfig.dbPath,
328                                         mConfig.zoneTemplateDir,
329                                         mConfig.runMountPointPrefix));
330
331     mZones.push_back(std::move(zone));
332
333     // after zone is created successfully, put a file informing that zones are enabled
334     if (mZones.size() == 1) {
335         if (!utils::saveFileContent(
336                 utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME), "")) {
337             throw ZoneOperationException(ENABLED_FILE_NAME + ": cannot create.");
338         }
339     }
340 }
341
342 void ZonesManager::tryAddTask(const utils::Worker::Task& task, api::MethodResultBuilder::Pointer result, bool wait)
343 {
344     {
345         Lock lock(mExclusiveIDMutex);
346
347         if (mExclusiveIDLock != INVALID_CONNECTION_ID &&
348             mExclusiveIDLock != result->getID()) {
349             result->setError(api::ERROR_QUEUE, "Queue is locked by another client");
350             return;
351         }
352     }
353
354     if (wait) {
355         mWorker->addTaskAndWait(task);
356     } else {
357         mWorker->addTask(task);
358     }
359 }
360
361 void ZonesManager::destroyZone(const std::string& zoneId)
362 {
363     Lock lock(mMutex);
364
365     auto iter = findZone(zoneId);
366     if (iter == mZones.end()) {
367         const std::string msg = "Failed to destroy zone " + zoneId + ": no such zone";
368         LOGE(msg);
369         throw InvalidZoneIdException(msg);
370     }
371
372     get(iter).setDestroyOnExit();
373     mZones.erase(iter);
374
375     if (mZones.empty()) {
376         if (!utils::removeFile(utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME))) {
377             LOGE("Failed to remove enabled file.");
378         }
379     }
380
381     // update dynamic config
382     remove(mDynamicConfig.zoneIds, zoneId);
383     saveDynamicConfig();
384     updateDefaultId();
385
386     refocus();
387 }
388
389 void ZonesManager::focus(const std::string& zoneId)
390 {
391     Lock lock(mMutex);
392     auto iter = findZone(zoneId);
393     focusInternal(iter);
394 }
395
396 void ZonesManager::focusInternal(Zones::iterator iter)
397 {
398     // assume mutex is locked
399     if (iter == mZones.end()) {
400         if (!mActiveZoneId.empty()) {
401             if (mConfig.hostVT > 0) {
402                 LOGI("Focus to: host");
403                 utils::activateVT(mConfig.hostVT);
404             }
405             mActiveZoneId.clear();
406         }
407         return;
408     }
409
410     Zone& zoneToFocus = get(iter);
411     const std::string& idToFocus = zoneToFocus.getId();
412
413     if (idToFocus == mActiveZoneId) {
414         return;
415     }
416
417     if (!zoneToFocus.isRunning()) {
418         LOGE("Can't focus not running zone " << idToFocus);
419         assert(false);
420         return;
421     }
422
423     LOGI("Focus to: " << idToFocus);
424
425     if (!zoneToFocus.activateVT()) {
426         LOGE("Failed to activate zones VT");
427         return;
428     }
429
430     for (auto& zone : mZones) {
431         if (zone->isRunning()) {
432             std::string id = zone->getId();
433             if (id == idToFocus) {
434                 LOGD(id << ": being sent to foreground");
435                 zone->goForeground();
436             } else {
437                 LOGD(id << ": being sent to background");
438                 zone->goBackground();
439             }
440         }
441     }
442     mActiveZoneId = idToFocus;
443 }
444
445 void ZonesManager::refocus()
446 {
447     // assume mutex is locked
448
449     // check if refocus is required
450     auto oldIter = findZone(mActiveZoneId);
451     if (oldIter != mZones.end() && get(oldIter).isRunning()) {
452         return;
453     }
454
455     // try to refocus to defaultId
456     auto iter = findZone(mDynamicConfig.defaultId);
457     if (iter == mZones.end() || !get(iter).isRunning()) {
458         // focus to any running or to host if not found
459         iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning);
460     }
461     focusInternal(iter);
462 }
463
464 void ZonesManager::restoreAll()
465 {
466     LOGI("Restoring all zones");
467
468     Lock lock(mMutex);
469
470     for (auto& zone : mZones) {
471         zone->restore();
472         // FIXME wait until zone is started and stable
473         // there is problem (with lxc-start) when starting zones too fast
474         // here or in zone.cpp after start
475         std::this_thread::sleep_for(std::chrono::milliseconds(500));
476     }
477
478     refocus();
479 }
480
481 void ZonesManager::shutdownAll()
482 {
483     LOGI("Stopping all zones");
484
485     Lock lock(mMutex);
486
487     for (auto& zone : mZones) {
488         zone->stop(false);
489     }
490
491     refocus();
492 }
493
494 bool ZonesManager::isPaused(const std::string& zoneId)
495 {
496     Lock lock(mMutex);
497     return getZone(zoneId).isPaused();
498 }
499
500 bool ZonesManager::isRunning(const std::string& zoneId)
501 {
502     Lock lock(mMutex);
503     return getZone(zoneId).isRunning();
504 }
505
506 bool ZonesManager::isStopped(const std::string& zoneId)
507 {
508     Lock lock(mMutex);
509     return getZone(zoneId).isStopped();
510 }
511
512 std::string ZonesManager::getRunningForegroundZoneId()
513 {
514     Lock lock(mMutex);
515     auto iter = getRunningForegroundZoneIterator();
516     return iter == mZones.end() ? std::string() : get(iter).getId();
517 }
518
519 std::string ZonesManager::getNextToForegroundZoneId()
520 {
521     Lock lock(mMutex);
522     auto iter = getNextToForegroundZoneIterator();
523     return iter == mZones.end() ? std::string() : get(iter).getId();
524 }
525
526 ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator()
527 {
528     // assume mutex is locked
529     if (mActiveZoneId.empty()) {
530         return mZones.end();
531     }
532     auto iter = findZone(mActiveZoneId);
533     if (!get(iter).isRunning()) {
534         LOGW("Active zone " << mActiveZoneId << " is not running any more!");
535         return mZones.end();
536     }
537     return iter;
538 }
539
540 ZonesManager::Zones::iterator ZonesManager::getNextToForegroundZoneIterator()
541 {
542     // assume mutex is locked
543     auto current = findZone(mActiveZoneId);
544     if (current == mZones.end()) {
545         // find any running
546         return std::find_if(mZones.begin(), mZones.end(), zoneIsRunning);
547     } else {
548         // find next running
549         return circularFindNext(mZones.begin(), mZones.end(), current, zoneIsRunning);
550     }
551 }
552
553 void ZonesManager::switchingSequenceMonitorNotify()
554 {
555     LOGI("switchingSequenceMonitorNotify() called");
556
557     Lock lock(mMutex);
558
559     auto next = getNextToForegroundZoneIterator();
560
561     if (next != mZones.end()) {
562         focusInternal(next);
563     }
564 }
565
566
567 void ZonesManager::setZonesDetachOnExit()
568 {
569     Lock lock(mMutex);
570
571     mDetachOnExit = true;
572
573     for (auto& zone : mZones) {
574         zone->setDetachOnExit();
575     }
576 }
577
578 void ZonesManager::disconnectedCallback(const std::string& id)
579 {
580     LOGD("Client Disconnected: " << id);
581
582     {
583         Lock lock(mExclusiveIDMutex);
584
585         if (mExclusiveIDLock == id) {
586             mExclusiveIDLock = INVALID_CONNECTION_ID;
587         }
588     }
589 }
590
591 void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/,
592                                              api::MethodResultBuilder::Pointer result)
593 {
594     auto handler = [&, this] {
595         // get config of currently set zone and switch if switchToDefaultAfterTimeout is true
596         Lock lock(mMutex);
597
598         auto activeIter = findZone(mActiveZoneId);
599         auto defaultIter = findZone(mDynamicConfig.defaultId);
600
601         if (activeIter != mZones.end() &&
602             defaultIter != mZones.end() &&
603             get(activeIter).isSwitchToDefaultAfterTimeoutAllowed() &&
604             get(defaultIter).isRunning()) {
605
606             LOGI("Switching to default zone " << mDynamicConfig.defaultId);
607             focusInternal(defaultIter);
608         }
609         result->setVoid();
610     };
611
612     tryAddTask(handler, result, true);
613 }
614
615 void ZonesManager::handleCreateFileCall(const api::CreateFileIn& request,
616                                         api::MethodResultBuilder::Pointer result)
617 {
618     auto handler = [&, this] {
619         LOGI("CreateFile call");
620
621         Lock lock(mMutex);
622
623         auto srcIter = findZone(request.id);
624         if (srcIter == mZones.end()) {
625             LOGE("Zone '" << request.id << "' not found");
626             result->setError(api::ERROR_INVALID_ID, "Requested Zone was not found.");
627             return;
628         }
629         Zone& srcZone = get(srcIter);
630
631         auto retValue = std::make_shared<api::CreateFileOut>();
632         try {
633             retValue->fd = srcZone.createFile(request.path, request.flags, request.mode);
634         } catch(ZoneOperationException& e) {
635             result->setError(api::ERROR_CREATE_FILE_FAILED, "Unable to create file");
636             return;
637         }
638
639         result->set(retValue);
640     };
641
642     tryAddTask(handler, result, true);
643 }
644
645 #ifdef DBUS_CONNECTION
646 void ZonesManager::handleProxyCall(const std::string& caller,
647                                    const std::string& target,
648                                    const std::string& targetBusName,
649                                    const std::string& targetObjectPath,
650                                    const std::string& targetInterface,
651                                    const std::string& targetMethod,
652                                    GVariant* parameters,
653                                    dbus::MethodResultBuilder::Pointer result)
654 {
655     auto handler = [&, this] {
656         if (!mProxyCallPolicy->isProxyCallAllowed(caller,
657                                                   target,
658                                                   targetBusName,
659                                                   targetObjectPath,
660                                                   targetInterface,
661                                                   targetMethod)) {
662             LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName
663                  << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
664             result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden");
665             return;
666         }
667
668         LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName
669              << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
670
671         auto asyncResultCallback = [result](dbus::AsyncMethodCallResult & asyncMethodCallResult) {
672             try {
673                 GVariant* targetResult = asyncMethodCallResult.get();
674                 result->set(g_variant_new("(v)", targetResult));
675             } catch (dbus::DbusException& e) {
676                 result->setError(api::ERROR_FORWARDED, e.what());
677             }
678         };
679
680         if (target != HOST_ID) {
681             result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target");
682             return;
683         }
684
685         mHostDbusConnection.proxyCallAsync(targetBusName,
686                                            targetObjectPath,
687                                            targetInterface,
688                                            targetMethod,
689                                            parameters,
690                                            asyncResultCallback);
691     };
692
693     // This call cannot be locked by lock/unlock queue
694     mWorker->addTaskAndWait(handler);
695 }
696 #endif //DBUS_CONNECTION
697
698 void ZonesManager::handleLockQueueCall(api::MethodResultBuilder::Pointer result)
699 {
700     Lock lock(mExclusiveIDMutex);
701     std::string id = result->getID();
702
703     LOGI("Lock Queue: " << id);
704
705     if (mExclusiveIDLock == id) {
706         result->setError(api::ERROR_QUEUE, "Queue already locked");
707         return;
708     }
709
710     if (mExclusiveIDLock != INVALID_CONNECTION_ID) {
711         result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
712         return;
713     }
714
715     mExclusiveIDLock = id;
716     result->setVoid();
717 }
718
719 void ZonesManager::handleUnlockQueueCall(api::MethodResultBuilder::Pointer result)
720 {
721     Lock lock(mExclusiveIDMutex);
722     std::string id = result->getID();
723
724     LOGI("Unlock Queue: " << id);
725
726     if (mExclusiveIDLock == INVALID_CONNECTION_ID) {
727         result->setError(api::ERROR_QUEUE, "Queue not locked");
728         return;
729     }
730
731     if (mExclusiveIDLock != id) {
732         result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
733         return;
734     }
735
736     mExclusiveIDLock = INVALID_CONNECTION_ID;
737     result->setVoid();
738 }
739
740 void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result)
741 {
742     auto handler = [&, this] {
743         LOGI("GetZoneIds call");
744
745         Lock lock(mMutex);
746
747         auto zoneIds = std::make_shared<api::ZoneIds>();
748         for (const auto& zone : mZones) {
749             zoneIds->values.push_back(zone->getId());
750         }
751
752         result->set(zoneIds);
753     };
754
755     // This call cannot be locked by lock/unlock queue
756     mWorker->addTaskAndWait(handler);
757 }
758
759 void ZonesManager::handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result)
760 {
761     auto handler = [&, this] {
762         LOGI("GetActiveZoneId call");
763
764         auto zoneId = std::make_shared<api::ZoneId>();
765         zoneId->value = getRunningForegroundZoneId();
766         result->set(zoneId);
767     };
768
769     // This call cannot be locked by lock/unlock queue
770     mWorker->addTaskAndWait(handler);
771 }
772
773 void ZonesManager::handleGetZoneInfoCall(const api::ZoneId& zoneId,
774                                          api::MethodResultBuilder::Pointer result)
775 {
776     auto handler = [&, this] {
777         LOGI("GetZoneInfo call");
778
779         Lock lock(mMutex);
780
781         auto iter = findZone(zoneId.value);
782         if (iter == mZones.end()) {
783             LOGE("No zone with id=" << zoneId.value);
784             result->setError(api::ERROR_INVALID_ID, "No such zone id");
785             return;
786         }
787
788         Zone& zone = get(iter);
789         auto zoneInfo = std::make_shared<api::ZoneInfoOut>();
790
791         if (zone.isRunning()) {
792             zoneInfo->state = "RUNNING";
793         } else if (zone.isStopped()) {
794             zoneInfo->state = "STOPPED";
795         } else if (zone.isPaused()) {
796             zoneInfo->state = "FROZEN";
797         } else {
798             LOGE("Unrecognized state of zone id=" << zoneId.value);
799             result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone");
800             return;
801         }
802
803         zoneInfo->id = zone.getId();
804         zoneInfo->vt = zone.getVT();
805         zoneInfo->rootPath = zone.getRootPath();
806         result->set(zoneInfo);
807     };
808
809     // This call cannot be locked by lock/unlock queue
810     mWorker->addTaskAndWait(handler);
811 }
812
813 void ZonesManager::handleSetNetdevAttrsCall(const api::SetNetDevAttrsIn& data,
814                                             api::MethodResultBuilder::Pointer result)
815 {
816     auto handler = [&, this] {
817         LOGI("SetNetdevAttrs call");
818
819         try {
820             Lock lock(mMutex);
821
822             // TODO: Use vector<StringPair> instead of tuples
823             std::vector<std::tuple<std::string, std::string>> attrsAsTuples;
824             for(const auto& entry: data.attrs){
825                 attrsAsTuples.push_back(std::make_tuple(entry.first, entry.second));
826             }
827
828             getZone(data.id).setNetdevAttrs(data.netDev, attrsAsTuples);
829             result->setVoid();
830         } catch (const InvalidZoneIdException&) {
831             LOGE("No zone with id=" << data.id);
832             result->setError(api::ERROR_INVALID_ID, "No such zone id");
833         } catch (const std::runtime_error& ex) {
834             LOGE("Can't set attributes: " << ex.what());
835             result->setError(api::ERROR_INTERNAL, ex.what());
836         }
837     };
838
839     tryAddTask(handler, result, true);
840 }
841
842 void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data,
843                                             api::MethodResultBuilder::Pointer result)
844 {
845     auto handler = [&, this] {
846         LOGI("GetNetdevAttrs call");
847
848         try {
849             Lock lock(mMutex);
850             auto netDevAttrs = std::make_shared<api::GetNetDevAttrs>();
851             const auto attrs = getZone(data.first).getNetdevAttrs(data.second);
852
853             for (size_t i = 0; i < attrs.size(); ++i) {
854                 netDevAttrs->values.push_back({std::get<0>(attrs[i]), std::get<1>(attrs[i])});
855             }
856             result->set(netDevAttrs);
857         } catch (const InvalidZoneIdException&) {
858             LOGE("No zone with id=" << data.first);
859             result->setError(api::ERROR_INVALID_ID, "No such zone id");
860         } catch (const std::runtime_error& ex) {
861             LOGE("Can't set attributes: " << ex.what());
862             result->setError(api::ERROR_INTERNAL, ex.what());
863         }
864     };
865
866     tryAddTask(handler, result, true);
867 }
868
869 void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId,
870                                            api::MethodResultBuilder::Pointer result)
871 {
872     auto handler = [&, this] {
873         LOGI("GetNetdevList call");
874
875         try {
876             Lock lock(mMutex);
877             auto netDevList = std::make_shared<api::NetDevList>();
878             netDevList->values = getZone(zoneId.value).getNetdevList();
879             result->set(netDevList);
880         } catch (const InvalidZoneIdException&) {
881             LOGE("No zone with id=" << zoneId.value);
882             result->setError(api::ERROR_INVALID_ID, "No such zone id");
883         } catch (const std::runtime_error& ex) {
884             LOGE("Can't set attributes: " << ex.what());
885             result->setError(api::ERROR_INTERNAL, ex.what());
886         }
887     };
888
889     tryAddTask(handler, result, true);
890 }
891
892 void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& data,
893                                               api::MethodResultBuilder::Pointer result)
894 {
895     auto handler = [&, this] {
896         LOGI("CreateNetdevVeth call");
897
898         try {
899             Lock lock(mMutex);
900
901             getZone(data.id).createNetdevVeth(data.zoneDev, data.hostDev);
902             result->setVoid();
903         } catch (const InvalidZoneIdException&) {
904             LOGE("No zone with id=" << data.id);
905             result->setError(api::ERROR_INVALID_ID, "No such zone id");
906         } catch (const std::runtime_error& ex) {
907             LOGE("Can't create veth: " << ex.what());
908             result->setError(api::ERROR_INTERNAL, ex.what());
909         }
910     };
911
912     tryAddTask(handler, result, true);
913 }
914
915 void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanIn& data,
916                                                  api::MethodResultBuilder::Pointer result)
917 {
918     auto handler = [&, this] {
919         LOGI("CreateNetdevMacvlan call");
920
921         try {
922             Lock lock(mMutex);
923             getZone(data.id).createNetdevMacvlan(data.zoneDev, data.hostDev, data.mode);
924             result->setVoid();
925         } catch (const InvalidZoneIdException&) {
926             LOGE("No zone with id=" << data.id);
927             result->setError(api::ERROR_INVALID_ID, "No such zone id");
928         } catch (const std::runtime_error& ex) {
929             LOGE("Can't create macvlan: " << ex.what());
930             result->setError(api::ERROR_INTERNAL, ex.what());
931         }
932     };
933
934     tryAddTask(handler, result, true);
935 }
936
937 void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& data,
938                                               api::MethodResultBuilder::Pointer result)
939 {
940     auto handler = [&, this] {
941         LOGI("CreateNetdevPhys call");
942
943         try {
944             Lock lock(mMutex);
945
946             getZone(data.first).moveNetdev(data.second);
947             result->setVoid();
948         } catch (const InvalidZoneIdException&) {
949             LOGE("No zone with id=" << data.first);
950             result->setError(api::ERROR_INVALID_ID, "No such zone id");
951         } catch (const std::runtime_error& ex) {
952             LOGE("Can't create netdev: " << ex.what());
953             result->setError(api::ERROR_INTERNAL, ex.what());
954         }
955     };
956
957     tryAddTask(handler, result, true);
958 }
959
960 void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data,
961                                            api::MethodResultBuilder::Pointer result)
962 {
963     auto handler = [&, this] {
964         LOGI("DestroyNetdev call");
965
966         try {
967             Lock lock(mMutex);
968
969             getZone(data.first).destroyNetdev(data.second);
970             result->setVoid();
971         } catch (const InvalidZoneIdException&) {
972             LOGE("No zone with id=" << data.first);
973             result->setError(api::ERROR_INVALID_ID, "No such zone id");
974         } catch (const std::runtime_error& ex) {
975             LOGE("Can't create netdev: " << ex.what());
976             result->setError(api::ERROR_INTERNAL, ex.what());
977         }
978     };
979
980     tryAddTask(handler, result, true);
981 }
982
983 void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data,
984                                                    api::MethodResultBuilder::Pointer result)
985 {
986     auto handler = [&, this] {
987         LOGI("DelNetdevIpAddress call");
988
989         try {
990             Lock lock(mMutex);
991             getZone(data.zone).deleteNetdevIpAddress(data.netdev, data.ip);
992             result->setVoid();
993         } catch (const InvalidZoneIdException&) {
994             LOGE("No zone with id=" << data.zone);
995             result->setError(api::ERROR_INVALID_ID, "No such zone id");
996         } catch (const std::runtime_error& ex) {
997             LOGE("Can't delete address: " << ex.what());
998             result->setError(api::ERROR_INTERNAL, ex.what());
999         }
1000     };
1001
1002     tryAddTask(handler, result, true);
1003 }
1004
1005 void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data,
1006                                          api::MethodResultBuilder::Pointer result)
1007 {
1008     auto handler = [&, this] {
1009         LOGI("DeclareFile call");
1010
1011         try {
1012             Lock lock(mMutex);
1013             auto declaration = std::make_shared<api::Declaration>();
1014             declaration->value = getZone(data.zone).declareFile(data.type, data.path, data.flags, data.mode);
1015             result->set(declaration);
1016         } catch (const InvalidZoneIdException&) {
1017             LOGE("No zone with id=" << data.zone);
1018             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1019         } catch (const config::ConfigException& ex) {
1020             LOGE("Can't declare file: " << ex.what());
1021             result->setError(api::ERROR_INTERNAL, "Internal error");
1022         }
1023     };
1024
1025     tryAddTask(handler, result, true);
1026 }
1027
1028 void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data,
1029                                           api::MethodResultBuilder::Pointer result)
1030 {
1031     auto handler = [&, this] {
1032         LOGI("DeclareMount call");
1033
1034         try {
1035             Lock lock(mMutex);
1036             auto declaration = std::make_shared<api::Declaration>();
1037             declaration->value = getZone(data.zone).declareMount(data.source, data.target, data.type, data.flags, data.data);
1038             result->set(declaration);
1039         } catch (const InvalidZoneIdException&) {
1040             LOGE("No zone with id=" << data.zone);
1041             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1042         } catch (const config::ConfigException& ex) {
1043             LOGE("Can't declare mount: " << ex.what());
1044             result->setError(api::ERROR_INTERNAL, "Internal error");
1045         }
1046     };
1047
1048     tryAddTask(handler, result, true);
1049 }
1050
1051 void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data,
1052                                          api::MethodResultBuilder::Pointer result)
1053 {
1054     auto handler = [&, this] {
1055         LOGI("DeclareLink call");
1056
1057         try {
1058             Lock lock(mMutex);
1059             auto declaration = std::make_shared<api::Declaration>();
1060             declaration->value = getZone(data.zone).declareLink(data.source, data.target);
1061             result->set(declaration);
1062         } catch (const InvalidZoneIdException&) {
1063             LOGE("No zone with id=" << data.zone);
1064             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1065         } catch (const config::ConfigException& ex) {
1066             LOGE("Can't declare link: " << ex.what());
1067             result->setError(api::ERROR_INTERNAL, "Internal error");
1068         }
1069     };
1070
1071     tryAddTask(handler, result, true);
1072 }
1073
1074 void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId,
1075                                              api::MethodResultBuilder::Pointer result)
1076 {
1077     auto handler = [&, this] {
1078         LOGI("GetDeclarations call Id=" << zoneId.value);
1079
1080         try {
1081             Lock lock(mMutex);
1082             auto declarations = std::make_shared<api::Declarations>();
1083             declarations->values = getZone(zoneId.value).getDeclarations();
1084             result->set(declarations);
1085         } catch (const InvalidZoneIdException&) {
1086             LOGE("No zone with id=" << zoneId.value);
1087             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1088         } catch (const std::runtime_error& ex) {
1089             LOGE(ex.what());
1090             result->setError(api::ERROR_INTERNAL, ex.what());
1091         }
1092     };
1093
1094     tryAddTask(handler, result, true);
1095 }
1096
1097 void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& data,
1098                                                api::MethodResultBuilder::Pointer result)
1099 {
1100     auto handler = [&, this] {
1101         LOGI("RemoveDeclaration call Id=" << data.first);
1102
1103         try {
1104             Lock lock(mMutex);
1105             getZone(data.first).removeDeclaration(data.second);
1106             result->setVoid();
1107         } catch (const InvalidZoneIdException&) {
1108             LOGE("No zone with id=" << data.first);
1109             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1110         } catch (const std::runtime_error& ex) {
1111             LOGE(ex.what());
1112             result->setError(api::ERROR_INTERNAL, ex.what());
1113         }
1114     };
1115
1116     tryAddTask(handler, result, true);
1117 }
1118
1119 void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId,
1120                                            api::MethodResultBuilder::Pointer result)
1121 {
1122     auto handler = [&, this] {
1123         LOGI("SetActiveZone call; Id=" << zoneId.value );
1124
1125         Lock lock(mMutex);
1126
1127         auto iter = findZone(zoneId.value);
1128         if (iter == mZones.end()) {
1129             LOGE("No zone with id=" << zoneId.value);
1130             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1131             return;
1132         }
1133
1134         if (!get(iter).isRunning()) {
1135             LOGE("Could not activate stopped or paused zone");
1136             result->setError(api::ERROR_ZONE_NOT_RUNNING,
1137                              "Could not activate stopped or paused zone");
1138             return;
1139         }
1140
1141         focusInternal(iter);
1142         result->setVoid();
1143     };
1144
1145     tryAddTask(handler, result, true);
1146 }
1147
1148
1149 void ZonesManager::generateNewConfig(const std::string& id,
1150                                      const std::string& templatePath)
1151 {
1152     const std::string dbPrefix = getZoneDbPrefix(id);
1153     ZoneDynamicConfig dynamicConfig;
1154     config::loadFromKVStoreWithJsonFile(mConfig.dbPath, templatePath, dynamicConfig, dbPrefix);
1155
1156     // update mount point path
1157     dynamicConfig.runMountPoint = rgx::regex_replace(dynamicConfig.runMountPoint,
1158                                                        ZONE_NAME_REGEX,
1159                                                        id);
1160
1161     if (dynamicConfig.vt >= 0) {
1162         // generate first free VT number
1163         const int freeVT = getVTForNewZone();
1164         LOGD("VT number: " << freeVT);
1165         dynamicConfig.vt = freeVT;
1166
1167         if (!dynamicConfig.ipv4Gateway.empty() && !dynamicConfig.ipv4.empty()) {
1168             // generate third IP octet for network config
1169             std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT);
1170             LOGD("IP third octet: " << thirdOctetStr);
1171             dynamicConfig.ipv4Gateway = rgx::regex_replace(dynamicConfig.ipv4Gateway,
1172                                                              ZONE_IP_THIRD_OCTET_REGEX,
1173                                                              thirdOctetStr);
1174             dynamicConfig.ipv4 = rgx::regex_replace(dynamicConfig.ipv4,
1175                                                       ZONE_IP_THIRD_OCTET_REGEX,
1176                                                       thirdOctetStr);
1177         }
1178     }
1179
1180     // save dynamic config
1181     config::saveToKVStore(mConfig.dbPath, dynamicConfig, dbPrefix);
1182
1183     // save zone template path
1184     ZoneTemplatePathConfig templatePathConfig;
1185     templatePathConfig.zoneTemplatePath = templatePath;
1186     config::saveToKVStore(mConfig.dbPath, templatePathConfig, dbPrefix);
1187
1188 }
1189
1190 int ZonesManager::getVTForNewZone()
1191 {
1192     if (mConfig.availableVTs.empty()) {
1193         return -1;
1194     }
1195     std::set<int> candidates(mConfig.availableVTs.begin(), mConfig.availableVTs.end());
1196     // exclude all used
1197     for (auto& zone : mZones) {
1198         candidates.erase(zone->getVT());
1199     }
1200     if (candidates.empty()) {
1201         const std::string msg = "No free VT for zone";
1202         LOGE(msg);
1203         throw ZoneOperationException(msg);
1204     }
1205     // return the smallest
1206     return *candidates.begin();
1207 }
1208
1209 void ZonesManager::createZone(const std::string& id,
1210                               const std::string& templateName)
1211 {
1212     if (id.empty() || !isalnum(id)) {
1213         const std::string msg = "Failed to add zone - invalid name.";
1214         LOGE(msg);
1215         throw InvalidZoneIdException(msg);
1216     }
1217
1218     if (find(prohibitedZonesNames.begin(), prohibitedZonesNames.end(), id) != prohibitedZonesNames.end()) {
1219         const std::string msg = "Cannot create " + id + " zone - name is not allowed!";
1220         LOGE(msg);
1221         throw InvalidZoneIdException(msg);
1222     }
1223
1224     LOGI("Creating zone " << id);
1225
1226     Lock lock(mMutex);
1227
1228     // TODO: This solution is temporary. It utilizes direct access to config files when creating new
1229     // zones. Update this handler when config database will appear.
1230     namespace fs = boost::filesystem;
1231
1232     // check if zone does not exist
1233     if (findZone(id) != mZones.end()) {
1234         const std::string msg = "Cannot create " + id + " zone - already exists!";
1235         LOGE(msg);
1236         throw InvalidZoneIdException(msg);
1237     }
1238
1239     if (fs::exists(fs::path(mConfig.zonesPath) / id)) {
1240         const std::string msg = "Cannot create " + id + " zone - file system already exists!";
1241         LOGE(msg);
1242         throw InvalidZoneIdException(msg);
1243     }
1244
1245     const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/");
1246
1247     // copy zone image if config contains path to image
1248     LOGT("Image path: " << mConfig.zoneImagePath);
1249     if (!mConfig.zoneImagePath.empty()) {
1250         auto copyImageContentsWrapper = std::bind(&utils::copyImageContents,
1251                                                   mConfig.zoneImagePath,
1252                                                   zonePathStr);
1253
1254         if (!utils::launchAsRoot(copyImageContentsWrapper)) {
1255             const std::string msg = "Failed to copy zone image.";
1256             LOGE(msg);
1257             throw ZoneOperationException(msg);
1258         }
1259     }
1260
1261     auto removeAllWrapper = [](const std::string & path) -> bool {
1262         try {
1263             LOGD("Removing copied data");
1264             fs::remove_all(fs::path(path));
1265         } catch (const std::exception& e) {
1266             LOGW("Failed to remove data: " << boost::diagnostic_information(e));
1267         }
1268         return true;
1269     };
1270
1271     std::string zoneTemplatePath = utils::createFilePath(mConfig.zoneTemplateDir,
1272                                                          templateName + ".conf");
1273
1274     try {
1275         LOGI("Generating config from " << zoneTemplatePath);
1276         generateNewConfig(id, zoneTemplatePath);
1277     } catch (std::runtime_error& e) {
1278         LOGE("Generate config failed: " << e.what());
1279         utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
1280         throw;
1281     }
1282
1283     LOGT("Creating new zone");
1284     try {
1285         insertZone(id, zoneTemplatePath);
1286     } catch (std::runtime_error& e) {
1287         LOGE("Creating new zone failed: " << e.what());
1288         utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
1289         throw;
1290     }
1291
1292     mDynamicConfig.zoneIds.push_back(id);
1293     saveDynamicConfig();
1294     updateDefaultId();
1295 }
1296
1297 void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data,
1298                                         api::MethodResultBuilder::Pointer result)
1299 {
1300     auto creator = [&, this] {
1301         try {
1302             createZone(data.first, data.second);
1303             result->setVoid();
1304         } catch (const InvalidZoneIdException& e) {
1305             result->setError(api::ERROR_INVALID_ID, e.what());
1306         } catch (const std::exception& e) {
1307             result->setError(api::ERROR_INTERNAL, e.what());
1308         }
1309     };
1310
1311     tryAddTask(creator, result, true);
1312 }
1313
1314 void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId,
1315                                          api::MethodResultBuilder::Pointer result)
1316 {
1317     auto destroyer = [=] {
1318         try {
1319             LOGI("Destroying zone " << zoneId.value);
1320             destroyZone(zoneId.value);
1321         } catch (const InvalidZoneIdException&) {
1322             LOGE("Failed to destroy zone - no such zone id: " << zoneId.value);
1323             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1324         } catch (const std::runtime_error& e) {
1325             LOGE("Error during zone destruction: " << e.what());
1326             result->setError(api::ERROR_INTERNAL, "Failed to destroy zone");
1327             return;
1328         }
1329         result->setVoid();
1330     };
1331
1332     tryAddTask(destroyer, result, false);
1333 }
1334
1335 void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId,
1336                                           api::MethodResultBuilder::Pointer result)
1337 {
1338     auto shutdown = [=] {
1339         LOGI("ShutdownZone call; Id=" << zoneId.value);
1340
1341         try {
1342             LOGT("Shutdown zone " << zoneId.value);
1343
1344             Lock lock(mMutex);
1345             auto iter = findZone(zoneId.value);
1346             if (iter == mZones.end()) {
1347                 LOGE("Failed to shutdown zone - no such zone id: " << zoneId.value);
1348                 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1349                 return;
1350             }
1351             get(iter).stop(true);
1352             refocus();
1353             result->setVoid();
1354         } catch (ZoneOperationException& e) {
1355             LOGE("Error during zone shutdown: " << e.what());
1356             result->setError(api::ERROR_INTERNAL, "Failed to shutdown zone");
1357             return;
1358         }
1359     };
1360
1361     tryAddTask(shutdown, result, false);
1362 }
1363
1364 void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId,
1365                                        api::MethodResultBuilder::Pointer result)
1366 {
1367     auto startAsync = [=] {
1368         LOGI("StartZone call; Id=" << zoneId.value);
1369
1370         try {
1371             LOGT("Start zone " << zoneId.value);
1372
1373             Lock lock(mMutex);
1374             auto iter = findZone(zoneId.value);
1375             if (iter == mZones.end()) {
1376                 LOGE("Failed to start zone - no such zone id: " << zoneId.value);
1377                 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1378                 return;
1379             }
1380             get(iter).start();
1381             focusInternal(iter);
1382             result->setVoid();
1383         } catch (const std::exception& e) {
1384             LOGE(zoneId.value << ": failed to start: " << e.what());
1385             result->setError(api::ERROR_INTERNAL, "Failed to start zone");
1386         }
1387     };
1388     tryAddTask(startAsync, result, false);
1389 }
1390
1391 void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId,
1392                                       api::MethodResultBuilder::Pointer result)
1393 {
1394     auto handler = [&, this] {
1395         LOGI("LockZone call; Id=" << zoneId.value );
1396
1397         Lock lock(mMutex);
1398
1399         auto iter = findZone(zoneId.value);
1400         if (iter == mZones.end()) {
1401             LOGE("Failed to lock zone - no such zone id: " << zoneId.value);
1402             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1403             return;
1404         }
1405
1406         Zone& zone = get(iter);
1407         if (!zone.isRunning()) {
1408             LOGE("Zone id=" << zoneId.value << " is not running.");
1409             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1410             return;
1411         }
1412
1413         LOGT("Lock zone");
1414         try {
1415             zone.goBackground();// make sure it will be in background after unlock
1416             zone.suspend();
1417             refocus();
1418         } catch (ZoneOperationException& e) {
1419             LOGE(e.what());
1420             result->setError(api::ERROR_INTERNAL, e.what());
1421             return;
1422         }
1423
1424         result->setVoid();
1425     };
1426
1427     tryAddTask(handler, result, true);
1428 }
1429
1430 void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId,
1431                                         api::MethodResultBuilder::Pointer result)
1432 {
1433     auto handler = [&, this] {
1434         LOGI("UnlockZone call; Id=" << zoneId.value );
1435
1436         Lock lock(mMutex);
1437
1438         auto iter = findZone(zoneId.value);
1439         if (iter == mZones.end()) {
1440             LOGE("Failed to unlock zone - no such zone id: " << zoneId.value);
1441             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1442             return;
1443         }
1444
1445         Zone& zone = get(iter);
1446         if (!zone.isPaused()) {
1447             LOGE("Zone id=" << zoneId.value << " is not paused.");
1448             result->setError(api::ERROR_INVALID_STATE, "Zone is not paused");
1449             return;
1450         }
1451
1452         LOGT("Unlock zone");
1453         try {
1454             zone.resume();
1455         } catch (ZoneOperationException& e) {
1456             LOGE(e.what());
1457             result->setError(api::ERROR_INTERNAL, e.what());
1458             return;
1459         }
1460
1461         result->setVoid();
1462     };
1463
1464     tryAddTask(handler, result, true);
1465 }
1466
1467 void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data,
1468                                          api::MethodResultBuilder::Pointer result)
1469 {
1470     auto handler = [&, this] {
1471         LOGI("GrantDevice call; id=" << data.id << "; dev=" << data.device);
1472
1473         Lock lock(mMutex);
1474
1475         auto iter = findZone(data.id);
1476         if (iter == mZones.end()) {
1477             LOGE("Failed to grant device - no such zone id: " << data.id);
1478             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1479             return;
1480         }
1481
1482         Zone& zone = get(iter);
1483         if (!zone.isRunning() && !zone.isPaused()) {
1484             LOGE("Zone id=" << data.id << " is not running");
1485             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1486             return;
1487         }
1488
1489         std::string devicePath = "/dev/" + data.device;
1490
1491         if (!lxc::isDevice(devicePath)) {
1492             LOGE("Failed to grant device - cannot acces device: " << data.device);
1493             result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1494             return;
1495         }
1496
1497         // assume device node is created inside zone
1498         if (!lxc::setDeviceAccess(data.id, devicePath, true, data.flags)) {
1499             LOGE("Failed to grant device: " << data.device << " for zone: " << data.id);
1500             result->setError(api::ERROR_INTERNAL, "Cannot grant device");
1501             return;
1502         }
1503
1504         result->setVoid();
1505     };
1506
1507     tryAddTask(handler, result, true);
1508 }
1509
1510 void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data,
1511                                           api::MethodResultBuilder::Pointer result)
1512 {
1513     auto handler = [&, this] {
1514         LOGI("RevokeDevice call; id=" << data.first << "; dev=" << data.second);
1515
1516         Lock lock(mMutex);
1517
1518         auto iter = findZone(data.first);
1519         if (iter == mZones.end()) {
1520             LOGE("Failed to revoke device - no such zone id: " << data.first);
1521             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1522             return;
1523         }
1524
1525         Zone& zone = get(iter);
1526         if (!zone.isRunning() && !zone.isPaused()) {
1527             LOGE("Zone id=" << data.first << " is not running");
1528             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1529             return;
1530         }
1531         std::string devicePath = "/dev/" + data.second;
1532
1533         if (!lxc::isDevice(devicePath)) {
1534             LOGE("Failed to revoke device - cannot acces device: " << data.second);
1535             result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1536             return;
1537         }
1538
1539         if (!lxc::setDeviceAccess(data.first, devicePath, false, 0)) {
1540             LOGE("Failed to revoke device: " << data.second << " for zone: " << data.first);
1541             result->setError(api::ERROR_INTERNAL, "Cannot revoke device");
1542             return;
1543         }
1544
1545         result->setVoid();
1546     };
1547
1548     tryAddTask(handler, result, true);
1549 }
1550
1551 void ZonesManager::handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result)
1552 {
1553     auto handler = [&, this] {
1554         LOGI("CleanUpZonesRoot call");
1555         try {
1556             std::vector<std::string> zonesIds;
1557             Lock lock(mMutex);
1558             for (const auto& zone : mZones) {
1559                 zonesIds.push_back(zone->getId());
1560             }
1561             cleanUpUnknownsFromRoot(mConfig.zonesPath, zonesIds, false);
1562         } catch (const std::exception& e) {
1563             result->setError(api::ERROR_INTERNAL, e.what());
1564         }
1565         result->setVoid();
1566     };
1567
1568     tryAddTask(handler, result, true);
1569 }
1570
1571 } // namespace vasum