d8858ab12425df1b80832a665bc755e8c49242c2
[platform/core/security/vasum.git] / server / containers-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 containers
23  */
24
25 #include "config.hpp"
26
27 #include "host-dbus-definitions.hpp"
28 #include "common-dbus-definitions.hpp"
29 #include "container-dbus-definitions.hpp"
30 #include "containers-manager.hpp"
31 #include "container-admin.hpp"
32 #include "exception.hpp"
33
34 #include "utils/paths.hpp"
35 #include "logger/logger.hpp"
36 #include "config/manager.hpp"
37 #include "dbus/exception.hpp"
38 #include "utils/fs.hpp"
39 #include "utils/img.hpp"
40
41 #include <boost/filesystem.hpp>
42 #include <boost/regex.hpp>
43 #include <boost/uuid/uuid.hpp>
44 #include <boost/uuid/uuid_io.hpp>
45 #include <boost/uuid/uuid_generators.hpp>
46 #include <boost/exception/diagnostic_information.hpp>
47 #include <cassert>
48 #include <string>
49 #include <climits>
50
51
52 namespace security_containers {
53
54
55 namespace {
56
57 bool regexMatchVector(const std::string& str, const std::vector<boost::regex>& v)
58 {
59     for (const boost::regex& toMatch: v) {
60         if (boost::regex_match(str, toMatch)) {
61             return true;
62         }
63     }
64
65     return false;
66 }
67
68 const std::string HOST_ID = "host";
69 const std::string CONTAINER_TEMPLATE_CONFIG_PATH = "template.conf";
70 const std::string CONTAINER_TEMPLATE_LIBVIRT_CONFIG_PATH = "template.xml";
71 const std::string CONTAINER_TEMPLATE_LIBVIRT_NETWORK_PATH = "template-network.xml";
72 const std::string CONTAINER_TEMPLATE_LIBVIRT_NETWORK_FILTER_PATH = "template-nwfilter.xml";
73
74 const boost::regex CONTAINER_NAME_REGEX("~NAME~");
75 const boost::regex CONTAINER_UUID_REGEX("~UUID~");
76 const boost::regex CONTAINER_IP_THIRD_OCTET_REGEX("~IP~");
77
78 const unsigned int CONTAINER_IP_BASE_THIRD_OCTET = 100;
79
80 } // namespace
81
82 ContainersManager::ContainersManager(const std::string& managerConfigPath): mDetachOnExit(false)
83 {
84     LOGD("Instantiating ContainersManager object...");
85
86     mConfigPath = managerConfigPath;
87     config::loadFromFile(mConfigPath, mConfig);
88
89     mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules));
90
91     using namespace std::placeholders;
92     mHostConnection.setProxyCallCallback(bind(&ContainersManager::handleProxyCall,
93                                               this, HOST_ID, _1, _2, _3, _4, _5, _6, _7));
94
95     mHostConnection.setGetContainerDbusesCallback(bind(
96                 &ContainersManager::handleGetContainerDbuses, this, _1));
97
98     mHostConnection.setGetContainerIdsCallback(bind(&ContainersManager::handleGetContainerIdsCall,
99                                                     this, _1));
100
101     mHostConnection.setGetActiveContainerIdCallback(bind(&ContainersManager::handleGetActiveContainerIdCall,
102                                                          this, _1));
103
104     mHostConnection.setSetActiveContainerCallback(bind(&ContainersManager::handleSetActiveContainerCall,
105                                                        this, _1, _2));
106
107     mHostConnection.setAddContainerCallback(bind(&ContainersManager::handleAddContainerCall,
108                                                            this, _1, _2));
109
110     for (auto& containerConfig : mConfig.containerConfigs) {
111         addContainer(containerConfig);
112     }
113
114     // check if default container exists, throw ContainerOperationException if not found
115     if (mContainers.find(mConfig.defaultId) == mContainers.end()) {
116         LOGE("Provided default container ID " << mConfig.defaultId << " is invalid.");
117         throw ContainerOperationException("Provided default container ID " + mConfig.defaultId +
118                                           " is invalid.");
119     }
120
121     LOGD("ContainersManager object instantiated");
122
123     if (mConfig.inputConfig.enabled) {
124         LOGI("Registering input monitor [" << mConfig.inputConfig.device.c_str() << "]");
125         mSwitchingSequenceMonitor.reset(
126                 new InputMonitor(mConfig.inputConfig,
127                                  std::bind(&ContainersManager::switchingSequenceMonitorNotify,
128                                            this)));
129     }
130
131
132 }
133
134 ContainersManager::~ContainersManager()
135 {
136     LOGD("Destroying ContainersManager object...");
137
138     if (!mDetachOnExit) {
139         try {
140             stopAll();
141         } catch (ServerException&) {
142             LOGE("Failed to stop all of the containers");
143         }
144     }
145
146     LOGD("ContainersManager object destroyed");
147 }
148
149 void ContainersManager::addContainer(const std::string& containerConfig)
150 {
151     std::string baseConfigPath = utils::dirName(mConfigPath);
152     std::string containerConfigPath = utils::getAbsolutePath(containerConfig, baseConfigPath);
153
154     LOGT("Creating Container " << containerConfigPath);
155     std::unique_ptr<Container> c(new Container(containerConfigPath,
156                                                mConfig.runMountPointPrefix));
157     const std::string id = c->getId();
158     if (id == HOST_ID) {
159         throw ContainerOperationException("Cannot use reserved container ID");
160     }
161
162     using namespace std::placeholders;
163     c->setNotifyActiveContainerCallback(bind(&ContainersManager::notifyActiveContainerHandler,
164                                              this, id, _1, _2));
165
166     c->setDisplayOffCallback(bind(&ContainersManager::displayOffHandler,
167                                   this, id));
168
169     c->setFileMoveRequestCallback(bind(&ContainersManager::handleContainerMoveFileRequest,
170                                             this, id, _1, _2, _3));
171
172     c->setProxyCallCallback(bind(&ContainersManager::handleProxyCall,
173                                  this, id, _1, _2, _3, _4, _5, _6, _7));
174
175     c->setDbusStateChangedCallback(bind(&ContainersManager::handleDbusStateChanged,
176                                         this, id, _1));
177
178     mContainers.insert(ContainerMap::value_type(id, std::move(c)));
179 }
180
181 void ContainersManager::focus(const std::string& containerId)
182 {
183     /* try to access the object first to throw immediately if it doesn't exist */
184     ContainerMap::mapped_type& foregroundContainer = mContainers.at(containerId);
185
186     if (!foregroundContainer->activateVT()) {
187         LOGE("Failed to activate containers VT. Aborting focus.");
188         return;
189     }
190
191     for (auto& container : mContainers) {
192         LOGD(container.second->getId() << ": being sent to background");
193         container.second->goBackground();
194     }
195     mConfig.foregroundId = foregroundContainer->getId();
196     LOGD(mConfig.foregroundId << ": being sent to foreground");
197     foregroundContainer->goForeground();
198 }
199
200 void ContainersManager::startAll()
201 {
202     LOGI("Starting all containers");
203
204     bool isForegroundFound = false;
205
206     for (auto& container : mContainers) {
207         container.second->start();
208
209         if (container.first == mConfig.foregroundId) {
210             isForegroundFound = true;
211             LOGI(container.second->getId() << ": set as the foreground container");
212             container.second->goForeground();
213         }
214     }
215
216     if (!isForegroundFound) {
217         auto foregroundIterator = std::min_element(mContainers.begin(), mContainers.end(),
218                                                    [](ContainerMap::value_type &c1, ContainerMap::value_type &c2) {
219                                                        return c1.second->getPrivilege() < c2.second->getPrivilege();
220                                                    });
221
222         mConfig.foregroundId = foregroundIterator->second->getId();
223         LOGI(mConfig.foregroundId << ": no foreground container configured, setting one with highest priority");
224         foregroundIterator->second->goForeground();
225     }
226 }
227
228 void ContainersManager::stopAll()
229 {
230     LOGI("Stopping all containers");
231
232     for (auto& container : mContainers) {
233         container.second->stop();
234     }
235 }
236
237 std::string ContainersManager::getRunningForegroundContainerId()
238 {
239     for (auto& container : mContainers) {
240         if (container.first == mConfig.foregroundId &&
241             container.second->isRunning()) {
242             return container.first;
243         }
244     }
245     return std::string();
246 }
247
248 std::string ContainersManager::getNextToForegroundContainerId()
249 {
250     // handles case where there is no next container
251     if (mContainers.size() < 2) {
252         return std::string();
253     }
254
255     for (auto it = mContainers.begin(); it != mContainers.end(); ++it) {
256         if (it->first == mConfig.foregroundId &&
257             it->second->isRunning()) {
258             auto nextIt = std::next(it);
259             if (nextIt != mContainers.end()) {
260                 return nextIt->first;
261             }
262         }
263     }
264     return mContainers.begin()->first;
265 }
266
267 void ContainersManager::switchingSequenceMonitorNotify()
268 {
269     LOGI("switchingSequenceMonitorNotify() called");
270
271     auto nextContainerId = getNextToForegroundContainerId();
272     focus(nextContainerId);
273 }
274
275
276 void ContainersManager::setContainersDetachOnExit()
277 {
278     mDetachOnExit = true;
279
280     for (auto& container : mContainers) {
281         container.second->setDetachOnExit();
282     }
283 }
284
285 void ContainersManager::notifyActiveContainerHandler(const std::string& caller,
286                                                      const std::string& application,
287                                                      const std::string& message)
288 {
289     LOGI("notifyActiveContainerHandler(" << caller << ", " << application << ", " << message
290          << ") called");
291     try {
292         const std::string activeContainer = getRunningForegroundContainerId();
293         if (!activeContainer.empty() && caller != activeContainer) {
294             mContainers[activeContainer]->sendNotification(caller, application, message);
295         }
296     } catch(const SecurityContainersException&) {
297         LOGE("Notification from " << caller << " hasn't been sent");
298     }
299 }
300
301 void ContainersManager::displayOffHandler(const std::string& /*caller*/)
302 {
303     // get config of currently set container and switch if switchToDefaultAfterTimeout is true
304     const std::string activeContainerName = getRunningForegroundContainerId();
305     const auto& activeContainer = mContainers.find(activeContainerName);
306
307     if (activeContainer != mContainers.end() &&
308         activeContainer->second->isSwitchToDefaultAfterTimeoutAllowed()) {
309         LOGI("Switching to default container " << mConfig.defaultId);
310         focus(mConfig.defaultId);
311     }
312 }
313
314 void ContainersManager::handleContainerMoveFileRequest(const std::string& srcContainerId,
315                                                        const std::string& dstContainerId,
316                                                        const std::string& path,
317                                                        dbus::MethodResultBuilder::Pointer result)
318 {
319     // TODO: this implementation is only a placeholder.
320     // There are too many unanswered questions and security concerns:
321     // 1. What about mount namespace, host might not see the source/destination
322     //    file. The file might be a different file from a host perspective.
323     // 2. Copy vs move (speed and security concerns over already opened FDs)
324     // 3. Access to source and destination files - DAC, uid/gig
325     // 4. Access to source and destintation files - MAC, smack
326     // 5. Destination file uid/gid assignment
327     // 6. Destination file smack label assignment
328     // 7. Verifiability of the source path
329
330     // NOTE: other possible implementations include:
331     // 1. Sending file descriptors opened directly in each container through DBUS
332     //    using something like g_dbus_message_set_unix_fd_list()
333     // 2. SCS forking and calling setns(MNT) in each container and opening files
334     //    by itself, then passing FDs to the main process
335     // Now when the main process has obtained FDs (by either of those methods)
336     // it can do the copying by itself.
337
338     LOGI("File move requested\n"
339          << "src: " << srcContainerId << "\n"
340          << "dst: " << dstContainerId << "\n"
341          << "path: " << path);
342
343     ContainerMap::const_iterator srcIter = mContainers.find(srcContainerId);
344     if (srcIter == mContainers.end()) {
345         LOGE("Source container '" << srcContainerId << "' not found");
346         return;
347     }
348     Container& srcContainer = *srcIter->second;
349
350     ContainerMap::const_iterator dstIter = mContainers.find(dstContainerId);
351     if (dstIter == mContainers.end()) {
352         LOGE("Destination container '" << dstContainerId << "' not found");
353         result->set(g_variant_new("(s)", api::container::FILE_MOVE_DESTINATION_NOT_FOUND.c_str()));
354         return;
355     }
356     Container& dstContanier = *dstIter->second;
357
358     if (srcContainerId == dstContainerId) {
359         LOGE("Cannot send a file to yourself");
360         result->set(g_variant_new("(s)", api::container::FILE_MOVE_WRONG_DESTINATION.c_str()));
361         return;
362     }
363
364     if (!regexMatchVector(path, srcContainer.getPermittedToSend())) {
365         LOGE("Source container has no permissions to send the file: " << path);
366         result->set(g_variant_new("(s)", api::container::FILE_MOVE_NO_PERMISSIONS_SEND.c_str()));
367         return;
368     }
369
370     if (!regexMatchVector(path, dstContanier.getPermittedToRecv())) {
371         LOGE("Destination container has no permissions to receive the file: " << path);
372         result->set(g_variant_new("(s)", api::container::FILE_MOVE_NO_PERMISSIONS_RECEIVE.c_str()));
373         return;
374     }
375
376     namespace fs = boost::filesystem;
377     std::string srcPath = fs::absolute(srcContainerId, mConfig.containersPath).string() + path;
378     std::string dstPath = fs::absolute(dstContainerId, mConfig.containersPath).string() + path;
379
380     if (!utils::moveFile(srcPath, dstPath)) {
381         LOGE("Failed to move the file: " << path);
382         result->set(g_variant_new("(s)", api::container::FILE_MOVE_FAILED.c_str()));
383     } else {
384         result->set(g_variant_new("(s)", api::container::FILE_MOVE_SUCCEEDED.c_str()));
385         try {
386             dstContanier.sendNotification(srcContainerId, path, api::container::FILE_MOVE_SUCCEEDED);
387         } catch (ServerException&) {
388             LOGE("Notification to '" << dstContainerId << "' has not been sent");
389         }
390     }
391 }
392
393 void ContainersManager::handleProxyCall(const std::string& caller,
394                                         const std::string& target,
395                                         const std::string& targetBusName,
396                                         const std::string& targetObjectPath,
397                                         const std::string& targetInterface,
398                                         const std::string& targetMethod,
399                                         GVariant* parameters,
400                                         dbus::MethodResultBuilder::Pointer result)
401 {
402     if (!mProxyCallPolicy->isProxyCallAllowed(caller,
403                                               target,
404                                               targetBusName,
405                                               targetObjectPath,
406                                               targetInterface,
407                                               targetMethod)) {
408         LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName
409                 << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
410         result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden");
411         return;
412     }
413
414     LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName
415             << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
416
417     auto asyncResultCallback = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
418         try {
419             GVariant* targetResult = asyncMethodCallResult.get();
420             result->set(g_variant_new("(v)", targetResult));
421         } catch (dbus::DbusException& e) {
422             result->setError(api::ERROR_FORWARDED, e.what());
423         }
424     };
425
426     if (target == HOST_ID) {
427         mHostConnection.proxyCallAsync(targetBusName,
428                                        targetObjectPath,
429                                        targetInterface,
430                                        targetMethod,
431                                        parameters,
432                                        asyncResultCallback);
433         return;
434     }
435
436     ContainerMap::const_iterator targetIter = mContainers.find(target);
437     if (targetIter == mContainers.end()) {
438         LOGE("Target container '" << target << "' not found");
439         result->setError(api::ERROR_UNKNOWN_ID, "Unknown proxy call target");
440         return;
441     }
442
443     Container& targetContainer = *targetIter->second;
444     targetContainer.proxyCallAsync(targetBusName,
445                                    targetObjectPath,
446                                    targetInterface,
447                                    targetMethod,
448                                    parameters,
449                                    asyncResultCallback);
450 }
451
452 void ContainersManager::handleGetContainerDbuses(dbus::MethodResultBuilder::Pointer result)
453 {
454     std::vector<GVariant*> entries;
455     for (auto& container : mContainers) {
456         GVariant* containerId = g_variant_new_string(container.first.c_str());
457         GVariant* dbusAddress = g_variant_new_string(container.second->getDbusAddress().c_str());
458         GVariant* entry = g_variant_new_dict_entry(containerId, dbusAddress);
459         entries.push_back(entry);
460     }
461     GVariant* dict = g_variant_new_array(G_VARIANT_TYPE("{ss}"), entries.data(), entries.size());
462     result->set(g_variant_new("(*)", dict));
463 }
464
465 void ContainersManager::handleDbusStateChanged(const std::string& containerId,
466                                                const std::string& dbusAddress)
467 {
468     mHostConnection.signalContainerDbusState(containerId, dbusAddress);
469 }
470
471 void ContainersManager::handleGetContainerIdsCall(dbus::MethodResultBuilder::Pointer result)
472 {
473     std::vector<GVariant*> containerIds;
474     for(auto& container: mContainers){
475         containerIds.push_back(g_variant_new_string(container.first.c_str()));
476     }
477
478     GVariant* array = g_variant_new_array(G_VARIANT_TYPE("s"),
479                                           containerIds.data(),
480                                           containerIds.size());
481     result->set(g_variant_new("(*)", array));
482 }
483
484 void ContainersManager::handleGetActiveContainerIdCall(dbus::MethodResultBuilder::Pointer result)
485 {
486     LOGI("GetActiveContainerId call");
487     if (mContainers[mConfig.foregroundId]->isRunning()){
488         result->set(g_variant_new("(s)", mConfig.foregroundId.c_str()));
489     } else {
490         result->set(g_variant_new("(s)", ""));
491     }
492 }
493
494 void ContainersManager::handleSetActiveContainerCall(const std::string& id,
495                                                      dbus::MethodResultBuilder::Pointer result)
496 {
497     LOGI("SetActiveContainer call; Id=" << id );
498     auto container = mContainers.find(id);
499     if (container == mContainers.end()){
500         LOGE("No container with id=" << id );
501         result->setError(api::ERROR_UNKNOWN_ID, "No such container id");
502         return;
503     }
504
505     if (container->second->isStopped()){
506         LOGE("Could not activate a stopped container");
507         result->setError(api::host::ERROR_CONTAINER_STOPPED,
508                          "Could not activate a stopped container");
509         return;
510     }
511
512     focus(id);
513     result->setVoid();
514 }
515
516
517 void ContainersManager::generateNewConfig(const std::string& id,
518                                           const std::string& templatePath,
519                                           const std::string& resultPath)
520 {
521     namespace fs = boost::filesystem;
522
523     std::string resultFileDir = utils::dirName(resultPath);
524     if (!fs::exists(resultFileDir)) {
525         if (!utils::createEmptyDir(resultFileDir)) {
526             LOGE("Unable to create directory for new config.");
527             throw ContainerOperationException("Unable to create directory for new config.");
528         }
529     }
530
531     fs::path resultFile(resultPath);
532     if (fs::exists(resultFile)) {
533         LOGT(resultPath << " already exists, removing");
534         fs::remove(resultFile);
535     }
536
537     std::string config;
538     if (!utils::readFileContent(templatePath, config)) {
539         LOGE("Failed to read template config file.");
540         throw ContainerOperationException("Failed to read template config file.");
541     }
542
543     std::string resultConfig = boost::regex_replace(config, CONTAINER_NAME_REGEX, id);
544
545     boost::uuids::uuid u = boost::uuids::random_generator()();
546     std::string uuidStr = to_string(u);
547     LOGD("uuid: " << uuidStr);
548     resultConfig = boost::regex_replace(resultConfig, CONTAINER_UUID_REGEX, uuidStr);
549
550     // generate third IP octet for network config
551     std::string thirdOctetStr = std::to_string(CONTAINER_IP_BASE_THIRD_OCTET + mContainers.size() + 1);
552     LOGD("ip_third_octet: " << thirdOctetStr);
553     resultConfig = boost::regex_replace(resultConfig, CONTAINER_IP_THIRD_OCTET_REGEX, thirdOctetStr);
554
555     if (!utils::saveFileContent(resultPath, resultConfig)) {
556         LOGE("Faield to save new config file.");
557         throw ContainerOperationException("Failed to save new config file.");
558     }
559
560     // restrict new config file so that only owner (security-containers) can write it
561     fs::permissions(resultPath, fs::perms::owner_all |
562                                 fs::perms::group_read |
563                                 fs::perms::others_read);
564 }
565
566 void ContainersManager::handleAddContainerCall(const std::string& id,
567                                                dbus::MethodResultBuilder::Pointer result)
568 {
569     LOGI("Adding container " << id);
570
571     // TODO: This solution is temporary. It utilizes direct access to config files when creating new
572     // containers. Update this handler when config database will appear.
573     namespace fs = boost::filesystem;
574
575     boost::system::error_code ec;
576     const std::string containerPathStr = utils::createFilePath(mConfig.containersPath, "/", id, "/");
577
578     // check if container does not exist
579     if (mContainers.find(id) != mContainers.end()) {
580         LOGE("Cannot create " << id << " container - already exists!");
581         result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
582                          "Cannot create " + id + " container - already exists!");
583         return;
584     }
585
586     // copy container image if config contains path to image
587     LOGT("image path: " << mConfig.containerImagePath);
588     if (!mConfig.containerImagePath.empty()) {
589         if (!utils::copyImageContents(mConfig.containerImagePath, containerPathStr)) {
590             LOGE("Failed to copy container image.");
591             result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
592                             "Failed to copy container image.");
593             return;
594         }
595     }
596
597     // generate paths to new configuration files
598     std::string baseDir = utils::dirName(mConfigPath);
599     std::string configDir = utils::getAbsolutePath(mConfig.containerNewConfigPrefix, baseDir);
600     std::string templateDir = utils::getAbsolutePath(mConfig.containerTemplatePath, baseDir);
601
602     std::string configPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_CONFIG_PATH);
603     std::string newConfigPath = utils::createFilePath(configDir, "/containers/", id + ".conf");
604     std::string libvirtConfigPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_LIBVIRT_CONFIG_PATH);
605     std::string newLibvirtConfigPath = utils::createFilePath(configDir, "/libvirt-config/", id + ".xml");
606     std::string libvirtNetworkPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_LIBVIRT_NETWORK_PATH);
607     std::string newLibvirtNetworkPath = utils::createFilePath(configDir, "/libvirt-config/", id + "-network.xml");
608     std::string libvirtNetworkFilterPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_LIBVIRT_NETWORK_FILTER_PATH);
609     std::string newLibvirtNetworkFilterPath = utils::createFilePath(configDir, "/libvirt-config/", id + "-nwfilter.xml");
610
611     auto removeAllWrapper = [](const std::string& path) {
612         try {
613             LOGD("Removing copied data");
614             fs::remove_all(fs::path(path));
615         } catch(const boost::exception& e) {
616             LOGW("Failed to remove data: " << boost::diagnostic_information(e));
617         }
618     };
619
620     try {
621         LOGI("Generating config from " << configPath << " to " << newConfigPath);
622         generateNewConfig(id, configPath, newConfigPath);
623
624         LOGI("Generating config from " << libvirtConfigPath << " to " << newLibvirtConfigPath);
625         generateNewConfig(id, libvirtConfigPath, newLibvirtConfigPath);
626
627         LOGI("Generating config from " << libvirtNetworkPath << " to " << newLibvirtNetworkPath);
628         generateNewConfig(id, libvirtNetworkPath, newLibvirtNetworkPath);
629
630         LOGI("Generating config from " << libvirtNetworkFilterPath << " to " << newLibvirtNetworkFilterPath);
631         generateNewConfig(id, libvirtNetworkFilterPath, newLibvirtNetworkFilterPath);
632     } catch (SecurityContainersException& e) {
633         LOGE(e.what());
634         removeAllWrapper(containerPathStr);
635         result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what());
636         return;
637     }
638
639     LOGT("Adding new container");
640     try {
641         addContainer(newConfigPath);
642     } catch (SecurityContainersException& e) {
643         LOGE(e.what());
644         removeAllWrapper(containerPathStr);
645         result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what());
646         return;
647     }
648
649     auto resultCallback = [result, containerPathStr, removeAllWrapper](bool succeeded) {
650         if (succeeded) {
651             result->setVoid();
652         } else {
653             LOGE("Failed to start container.");
654             removeAllWrapper(containerPathStr);
655             result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
656                              "Failed to start container.");
657         }
658     };
659     mContainers[id]->startAsync(resultCallback);
660 }
661
662 } // namespace security_containers