Move shutdown timeout to Zone config
[platform/core/security/vasum.git] / server / zone-admin.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   Implementation of class for administrating one zone
23  */
24
25 #include "config.hpp"
26
27 #include "zone-admin.hpp"
28 #include "exception.hpp"
29 #include "netdev.hpp"
30
31 #include "logger/logger.hpp"
32 #include "utils/paths.hpp"
33 #include "utils/c-array.hpp"
34 #include "lxc/cgroup.hpp"
35
36 #include <cassert>
37 #include <climits>
38 #include <thread>
39 #include <chrono>
40
41
42 namespace vasum {
43
44 const std::uint64_t DEFAULT_CPU_SHARES = 1024;
45 const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000;
46
47 ZoneAdmin::ZoneAdmin(const std::string& zoneId,
48                      const std::string& zonesPath,
49                      const std::string& lxcTemplatePrefix,
50                      const ZoneConfig& config,
51                      const ZoneDynamicConfig& dynamicConfig)
52     : mConfig(config),
53       mDynamicConfig(dynamicConfig),
54       mZone(zonesPath, zoneId),
55       mId(zoneId),
56       mDetachOnExit(false),
57       mDestroyOnExit(false)
58 {
59     LOGD(mId << ": Instantiating ZoneAdmin object");
60
61     if (!mZone.isDefined()) {
62
63         const std::string lxcTemplate = utils::getAbsolutePath(config.lxcTemplate,
64                                                                lxcTemplatePrefix);
65         LOGI(mId << ": Creating zone from template: " << lxcTemplate);
66         utils::CStringArrayBuilder args;
67         if (!dynamicConfig.ipv4Gateway.empty()) {
68             args.add("--ipv4-gateway");
69             args.add(dynamicConfig.ipv4Gateway.c_str());
70         }
71         if (!dynamicConfig.ipv4.empty()) {
72             args.add("--ipv4");
73             args.add(dynamicConfig.ipv4.c_str());
74         }
75         const std::string vt = std::to_string(dynamicConfig.vt);
76         if (dynamicConfig.vt > 0) {
77             args.add("--vt");
78             args.add(vt.c_str());
79         }
80         if (!mZone.create(lxcTemplate, args.c_array())) {
81             throw ZoneOperationException("Could not create zone");
82         }
83     }
84 }
85
86
87 ZoneAdmin::~ZoneAdmin()
88 {
89     LOGD(mId << ": Destroying ZoneAdmin object...");
90
91     if (mDestroyOnExit) {
92         if (!mZone.stop()) {
93             LOGE(mId << ": Failed to stop the zone");
94         }
95         if (!mZone.destroy()) {
96             LOGE(mId << ": Failed to destroy the zone");
97         }
98     }
99
100     if (!mDetachOnExit) {
101         // Try to forcefully stop
102         if (!mZone.stop()) {
103             LOGE(mId << ": Failed to stop the zone");
104         }
105     }
106
107     LOGD(mId << ": ZoneAdmin object destroyed");
108 }
109
110
111 const std::string& ZoneAdmin::getId() const
112 {
113     return mId;
114 }
115
116
117 void ZoneAdmin::start()
118 {
119     LOGD(mId << ": Starting...");
120     if (isRunning()) {
121         LOGD(mId << ": Already running - nothing to do...");
122         return;
123     }
124
125     utils::CStringArrayBuilder args;
126     for (const std::string& arg : mConfig.initWithArgs) {
127         args.add(arg.c_str());
128     }
129     if (args.empty()) {
130         args.add("/sbin/init");
131     }
132
133     if (!mZone.start(args.c_array())) {
134         throw ZoneOperationException("Could not start zone");
135     }
136
137     // Wait until the full platform launch with graphical stack.
138     // VT should be activated by a graphical stack.
139     // If we do it with 'zoneToFocus.activateVT' before starting the graphical stack,
140     // graphical stack initialization failed and we finally switch to the black screen.
141     // Skip waiting when graphical stack is not running (unit tests).
142     if (mDynamicConfig.vt > 0) {
143         // TODO, timeout is a temporary solution
144         std::this_thread::sleep_for(std::chrono::milliseconds(4000));
145     }
146
147     LOGD(mId << ": Started");
148 }
149
150
151 void ZoneAdmin::stop()
152 {
153     LOGD(mId << ": Stopping procedure started...");
154     if (isStopped()) {
155         LOGD(mId << ": Already crashed/down/off - nothing to do");
156         return;
157     }
158
159     if (!mZone.shutdown(mConfig.shutdownTimeout)) {
160         // force stop
161         if (!mZone.stop()) {
162             throw ZoneOperationException("Could not stop zone");
163         }
164     }
165
166     LOGD(mId << ": Stopping procedure ended");
167 }
168
169
170 void ZoneAdmin::destroy()
171 {
172     LOGD(mId << ": Destroying procedure started...");
173
174     if (!mZone.destroy()) {
175         throw ZoneOperationException("Could not destroy zone");
176     }
177
178     LOGD(mId << ": Destroying procedure ended");
179 }
180
181
182 bool ZoneAdmin::isRunning()
183 {
184     return mZone.getState() == lxc::LxcZone::State::RUNNING;
185 }
186
187
188 bool ZoneAdmin::isStopped()
189 {
190     return mZone.getState() == lxc::LxcZone::State::STOPPED;
191 }
192
193
194 void ZoneAdmin::suspend()
195 {
196     LOGD(mId << ": Pausing...");
197     if (!mZone.freeze()) {
198         throw ZoneOperationException("Could not pause zone");
199     }
200     LOGD(mId << ": Paused");
201 }
202
203
204 void ZoneAdmin::resume()
205 {
206     LOGD(mId << ": Resuming...");
207     if (!mZone.unfreeze()) {
208         throw ZoneOperationException("Could not resume zone");
209     }
210     LOGD(mId << ": Resumed");
211 }
212
213
214 bool ZoneAdmin::isPaused()
215 {
216     return mZone.getState() == lxc::LxcZone::State::FROZEN;
217 }
218
219
220 void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched)
221 {
222     assert(isRunning());
223
224     switch (sched) {
225     case SchedulerLevel::FOREGROUND:
226         LOGD(mId << ": Setting SchedulerLevel::FOREGROUND");
227         setSchedulerParams(DEFAULT_CPU_SHARES,
228                            DEFAULT_VCPU_PERIOD_MS,
229                            mConfig.cpuQuotaForeground);
230         break;
231     case SchedulerLevel::BACKGROUND:
232         LOGD(mId << ": Setting SchedulerLevel::BACKGROUND");
233         setSchedulerParams(DEFAULT_CPU_SHARES,
234                            DEFAULT_VCPU_PERIOD_MS,
235                            mConfig.cpuQuotaBackground);
236         break;
237     default:
238         assert(0 && "Unknown sched parameter value");
239     }
240 }
241
242
243 void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares,
244                                    std::uint64_t vcpuPeriod,
245                                    std::int64_t vcpuQuota)
246 {
247     assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000);
248     assert(vcpuQuota == -1 ||
249            (vcpuQuota >= 1000 && vcpuQuota <= static_cast<std::int64_t>(ULLONG_MAX / 1000)));
250
251     if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) ||
252         !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) ||
253         !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) {
254
255         LOGE(mId << ": Error while setting the zone's scheduler params");
256         throw ZoneOperationException("Could not set scheduler params");
257     }
258 }
259
260 void ZoneAdmin::setDetachOnExit()
261 {
262     mDetachOnExit = true;
263 }
264
265 void ZoneAdmin::setDestroyOnExit()
266 {
267     mDestroyOnExit = true;
268 }
269
270 std::int64_t ZoneAdmin::getSchedulerQuota()
271 {
272     std::string ret;
273     if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) {
274         LOGE(mId << ": Error while getting the zone's scheduler quota param");
275         throw ZoneOperationException("Could not get scheduler quota param");
276     }
277     return std::stoll(ret);
278 }
279
280 void ZoneAdmin::createNetdevVeth(const std::string& zoneDev,
281                                  const std::string& hostDev)
282 {
283     netdev::createVeth(mZone.getInitPid(), zoneDev, hostDev);
284 }
285
286 void ZoneAdmin::createNetdevMacvlan(const std::string& zoneDev,
287                                     const std::string& hostDev,
288                                     const uint32_t& mode)
289 {
290     netdev::createMacvlan(mZone.getInitPid(), zoneDev, hostDev, static_cast<macvlan_mode>(mode));
291 }
292
293 void ZoneAdmin::moveNetdev(const std::string& devId)
294 {
295     netdev::movePhys(mZone.getInitPid(), devId);
296 }
297
298 void ZoneAdmin::destroyNetdev(const std::string& devId)
299 {
300     netdev::destroyNetdev(devId, mZone.getInitPid());
301 }
302
303 void ZoneAdmin::setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs)
304 {
305     netdev::setAttrs(mZone.getInitPid(), netdev, attrs);
306 }
307
308 ZoneAdmin::NetdevAttrs ZoneAdmin::getNetdevAttrs(const std::string& netdev)
309 {
310     return netdev::getAttrs(mZone.getInitPid(), netdev);
311 }
312
313 std::vector<std::string> ZoneAdmin::getNetdevList()
314 {
315     return netdev::listNetdev(mZone.getInitPid());
316 }
317
318 void ZoneAdmin::deleteNetdevIpAddress(const std::string& netdev, const std::string& ip)
319 {
320     netdev::deleteIpAddress(mZone.getInitPid(), netdev, ip);
321 }
322
323 } // namespace vasum