blob: 8987899e4f51178e871eb9056462f547424e96b2 [file] [log] [blame]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +01001# Copyright 2014-2015 ARM Limited
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15# pylint: disable=attribute-defined-outside-init
16import logging
17from collections import namedtuple
18
19from devlib.module import Module
20from devlib.exception import TargetError
21from devlib.utils.misc import list_to_ranges, isiterable
22from devlib.utils.types import boolean
23
24
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000025class Controller(object):
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010026
Patrick Bellasib569a562016-11-29 10:39:28 +000027 def __init__(self, kind, hid, clist):
28 """
29 Initialize a controller given the hierarchy it belongs to.
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010030
Patrick Bellasib569a562016-11-29 10:39:28 +000031 :param kind: the name of the controller
32 :type kind: str
33
34 :param hid: the Hierarchy ID this controller is mounted on
35 :type hid: int
36
37 :param clist: the list of controller mounted in the same hierarchy
38 :type clist: list(str)
39 """
40 self.mount_name = 'devlib_cgh{}'.format(hid)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000041 self.kind = kind
Patrick Bellasib569a562016-11-29 10:39:28 +000042 self.hid = hid
43 self.clist = clist
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000044 self.target = None
Patrick Bellasi15f9c032016-04-26 15:23:56 +010045 self._noprefix = False
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000046
Patrick Bellasib569a562016-11-29 10:39:28 +000047 self.logger = logging.getLogger('CGroup.'+self.kind)
48 self.logger.debug('Initialized [%s, %d, %s]',
49 self.kind, self.hid, self.clist)
50
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010051 self.mount_point = None
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000052 self._cgroups = {}
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010053
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000054 def mount(self, target, mount_root):
55
56 mounted = target.list_file_systems()
57 if self.mount_name in [e.device for e in mounted]:
58 # Identify mount point if controller is already in use
59 self.mount_point = [
60 fs.mount_point
61 for fs in mounted
62 if fs.device == self.mount_name
63 ][0]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010064 else:
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000065 # Mount the controller if not already in use
66 self.mount_point = target.path.join(mount_root, self.mount_name)
67 target.execute('mkdir -p {} 2>/dev/null'\
68 .format(self.mount_point), as_root=True)
69 target.execute('mount -t cgroup -o {} {} {}'\
Patrick Bellasib569a562016-11-29 10:39:28 +000070 .format(','.join(self.clist),
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000071 self.mount_name,
72 self.mount_point),
73 as_root=True)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010074
Patrick Bellasi15f9c032016-04-26 15:23:56 +010075 # Check if this controller uses "noprefix" option
76 output = target.execute('mount | grep "{} "'.format(self.mount_name))
77 if 'noprefix' in output:
78 self._noprefix = True
79 # self.logger.debug('Controller %s using "noprefix" option',
80 # self.kind)
81
82 self.logger.debug('Controller %s mounted under: %s (noprefix=%s)',
83 self.kind, self.mount_point, self._noprefix)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010084
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000085 # Mark this contoller as available
86 self.target = target
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010087
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000088 # Create root control group
89 self.cgroup('/')
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010090
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000091 def cgroup(self, name):
92 if not self.target:
93 raise RuntimeError('CGroup creation failed: {} controller not mounted'\
94 .format(self.kind))
95 if name not in self._cgroups:
96 self._cgroups[name] = CGroup(self, name)
97 return self._cgroups[name]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010098
Patrick Bellasi9c9a7482015-11-03 11:49:31 +000099 def exists(self, name):
100 if not self.target:
101 raise RuntimeError('CGroup creation failed: {} controller not mounted'\
102 .format(self.kind))
103 if name not in self._cgroups:
104 self._cgroups[name] = CGroup(self, name, create=False)
105 return self._cgroups[name].existe()
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100106
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000107 def list_all(self):
108 self.logger.debug('Listing groups for %s controller', self.kind)
109 output = self.target.execute('{} find {} -type d'\
Patrick Bellasi3acf5d52016-04-26 15:31:05 +0100110 .format(self.target.busybox, self.mount_point),
111 as_root=True)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000112 cgroups = []
Patrick Bellasie2e5e682016-02-23 12:12:28 +0000113 for cg in output.splitlines():
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000114 cg = cg.replace(self.mount_point + '/', '/')
115 cg = cg.replace(self.mount_point, '/')
116 cg = cg.strip()
117 if cg == '':
118 continue
119 self.logger.debug('Populate %s cgroup: %s', self.kind, cg)
120 cgroups.append(cg)
121 return cgroups
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100122
Patrick Bellasi3cab7862016-08-26 16:27:23 +0100123 def move_tasks(self, source, dest, exclude=[]):
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100124 try:
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000125 srcg = self._cgroups[source]
126 dstg = self._cgroups[dest]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100127 except KeyError as e:
128 raise ValueError('Unkown group: {}'.format(e))
Patrick Bellasi3cab7862016-08-26 16:27:23 +0100129 output = self.target._execute_util(
130 'cgroups_tasks_move {} {} \'{}\''.format(
131 srcg.directory, dstg.directory, exclude),
132 as_root=True)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100133
Patrick Bellasi21d18f82016-08-26 18:13:47 +0100134 def move_all_tasks_to(self, dest, exclude=[]):
135 """
136 Move all the tasks to the specified CGroup
137
138 Tasks are moved from all their original CGroup the the specified on.
139 The tasks which name matches one of the string in exclude are moved
140 instead in the root CGroup for the controller.
141 The name of a tasks to exclude must be a substring of the task named as
142 reported by the "ps" command. Indeed, this list will be translated into
143 a: "ps | grep -e name1 -e name2..." in order to obtain the PID of these
144 tasks.
145
146 :param exclude: list of commands to keep in the root CGroup
147 :type exlude: list(str)
148 """
149
150 if isinstance(exclude, str):
151 exclude = [exclude]
152 if not isinstance(exclude, list):
153 raise ValueError('wrong type for "exclude" parameter, '
154 'it must be a str or a list')
155
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100156 logging.debug('Moving all tasks into %s', dest)
Patrick Bellasi21d18f82016-08-26 18:13:47 +0100157
158 # Build list of tasks to exclude
159 grep_filters = ''
160 for comm in exclude:
Brendan Jackman3dd4ea62016-11-25 16:04:34 +0000161 grep_filters += '-e {} '.format(comm)
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100162 logging.debug(' using grep filter: %s', grep_filters)
Patrick Bellasi21d18f82016-08-26 18:13:47 +0100163 if grep_filters != '':
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100164 logging.debug(' excluding tasks which name matches:')
165 logging.debug(' %s', ', '.join(exclude))
Patrick Bellasi21d18f82016-08-26 18:13:47 +0100166
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000167 for cgroup in self._cgroups:
168 if cgroup != dest:
Patrick Bellasi21d18f82016-08-26 18:13:47 +0100169 self.move_tasks(cgroup, dest, grep_filters)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100170
Patrick Bellasi42efd0a2016-08-26 16:25:43 +0100171 def tasks(self, cgroup):
172 try:
173 cg = self._cgroups[cgroup]
174 except KeyError as e:
175 raise ValueError('Unkown group: {}'.format(e))
176 output = self.target._execute_util(
177 'cgroups_tasks_in {}'.format(cg.directory),
178 as_root=True)
179 entries = output.splitlines()
180 tasks = {}
181 for task in entries:
182 tid = task.split(',')[0]
183 try:
184 tname = task.split(',')[1]
185 except: continue
186 try:
187 tcmdline = task.split(',')[2]
188 except:
189 tcmdline = ''
190 tasks[int(tid)] = (tname, tcmdline)
191 return tasks
192
Patrick Bellasid8ae3ab2016-08-26 16:28:45 +0100193 def tasks_count(self, cgroup):
194 try:
195 cg = self._cgroups[cgroup]
196 except KeyError as e:
197 raise ValueError('Unkown group: {}'.format(e))
198 output = self.target.execute(
199 '{} wc -l {}/tasks'.format(
200 self.target.busybox, cg.directory),
201 as_root=True)
202 return int(output.split()[0])
203
204 def tasks_per_group(self):
205 tasks = {}
206 for cg in self.list_all():
207 tasks[cg] = self.tasks_count(cg)
208 return tasks
209
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000210class CGroup(object):
211
212 def __init__(self, controller, name, create=True):
213 self.logger = logging.getLogger('cgroups.' + controller.kind)
214 self.target = controller.target
215 self.controller = controller
216 self.name = name
217
218 # Control cgroup path
219 self.directory = controller.mount_point
220 if name != '/':
221 self.directory = self.target.path.join(controller.mount_point, name[1:])
222
223 # Setup path for tasks file
224 self.tasks_file = self.target.path.join(self.directory, 'tasks')
225 self.procs_file = self.target.path.join(self.directory, 'cgroup.procs')
226
227 if not create:
228 return
229
Patrick Bellasi7112cfe2016-02-25 16:54:16 +0000230 self.logger.debug('Creating cgroup %s', self.directory)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000231 self.target.execute('[ -d {0} ] || mkdir -p {0}'\
232 .format(self.directory), as_root=True)
233
234 def exists(self):
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100235 try:
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000236 self.target.execute('[ -d {0} ]'\
Patrick Bellasi3acf5d52016-04-26 15:31:05 +0100237 .format(self.directory), as_root=True)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000238 return True
239 except TargetError:
240 return False
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100241
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000242 def get(self):
243 conf = {}
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100244
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000245 logging.debug('Reading %s attributes from:',
246 self.controller.kind)
247 logging.debug(' %s',
248 self.directory)
Patrick Bellasia65ff132016-02-23 12:11:06 +0000249 output = self.target._execute_util(
250 'cgroups_get_attributes {} {}'.format(
Patrick Bellasi3acf5d52016-04-26 15:31:05 +0100251 self.directory, self.controller.kind),
252 as_root=True)
Patrick Bellasia65ff132016-02-23 12:11:06 +0000253 for res in output.splitlines():
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000254 attr = res.split(':')[0]
255 value = res.split(':')[1]
256 conf[attr] = value
257
258 return conf
259
260 def set(self, **attrs):
261 for idx in attrs:
262 if isiterable(attrs[idx]):
263 attrs[idx] = list_to_ranges(attrs[idx])
264 # Build attribute path
Patrick Bellasi658005a2016-04-26 15:26:44 +0100265 if self.controller._noprefix:
266 attr_name = '{}'.format(idx)
267 else:
268 attr_name = '{}.{}'.format(self.controller.kind, idx)
269 path = self.target.path.join(self.directory, attr_name)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000270
271 self.logger.debug('Set attribute [%s] to: %s"',
272 path, attrs[idx])
273
274 # Set the attribute value
Patrick Bellasi658005a2016-04-26 15:26:44 +0100275 try:
276 self.target.write_value(path, attrs[idx])
277 except TargetError:
278 # Check if the error is due to a non-existing attribute
279 attrs = self.get()
280 if idx not in attrs:
281 raise ValueError('Controller [{}] does not provide attribute [{}]'\
282 .format(self.controller.kind, attr_name))
283 raise
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000284
285 def get_tasks(self):
286 task_ids = self.target.read_value(self.tasks_file).split()
287 logging.debug('Tasks: %s', task_ids)
288 return map(int, task_ids)
289
290 def add_task(self, tid):
291 self.target.write_value(self.tasks_file, tid, verify=False)
292
293 def add_tasks(self, tasks):
294 for tid in tasks:
295 self.add_task(tid)
296
297 def add_proc(self, pid):
298 self.target.write_value(self.procs_file, pid, verify=False)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100299
300CgroupSubsystemEntry = namedtuple('CgroupSubsystemEntry', 'name hierarchy num_cgroups enabled')
301
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100302class CgroupsModule(Module):
303
304 name = 'cgroups'
Patrick Bellasi616f2292016-05-13 18:17:22 +0100305 stage = 'setup'
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100306
307 @staticmethod
308 def probe(target):
Patrick Bellasi4b58c572016-04-26 15:33:23 +0100309 if not target.is_rooted:
310 return False
311 if target.file_exists('/proc/cgroups'):
312 return True
313 return target.config.has('cgroups')
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100314
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100315 def __init__(self, target):
316 super(CgroupsModule, self).__init__(target)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000317
318 self.logger = logging.getLogger('CGroups')
319
Patrick Bellasib2ec9572016-11-29 10:02:57 +0000320 # Set Devlib's CGroups mount point
321 self.cgroup_root = target.path.join(
322 target.working_directory, 'cgroups')
323
Patrick Bellasi103f7922016-11-29 10:13:01 +0000324 # Get the list of the available controllers
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000325 subsys = self.list_subsystems()
Patrick Bellasi103f7922016-11-29 10:13:01 +0000326 if len(subsys) == 0:
327 self.logger.warning('No CGroups controller available')
328 return
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000329
Patrick Bellasib569a562016-11-29 10:39:28 +0000330 # Map hierarchy IDs into a list of controllers
331 hierarchy = {}
332 for ss in subsys:
333 try:
334 hierarchy[ss.hierarchy].append(ss.name)
335 except KeyError:
336 hierarchy[ss.hierarchy] = [ss.name]
337 self.logger.debug('Available hierarchies: %s', hierarchy)
338
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000339 # Initialize controllers
Patrick Bellasi103f7922016-11-29 10:13:01 +0000340 self.logger.info('Available controllers:')
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000341 self.controllers = {}
Patrick Bellasi103f7922016-11-29 10:13:01 +0000342 for ss in subsys:
Patrick Bellasib569a562016-11-29 10:39:28 +0000343 hid = ss.hierarchy
344 controller = Controller(ss.name, hid, hierarchy[hid])
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000345 try:
Patrick Bellasib2ec9572016-11-29 10:02:57 +0000346 controller.mount(self.target, self.cgroup_root)
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000347 except TargetError:
Patrick Bellasib569a562016-11-29 10:39:28 +0000348 message = 'Failed to mount "{}" controller'
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000349 raise TargetError(message.format(controller.kind))
Patrick Bellasib569a562016-11-29 10:39:28 +0000350 self.logger.info(' %-12s : %s', controller.kind,
351 controller.mount_point)
Patrick Bellasi103f7922016-11-29 10:13:01 +0000352 self.controllers[ss.name] = controller
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100353
354 def list_subsystems(self):
355 subsystems = []
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000356 for line in self.target.execute('{} cat /proc/cgroups'\
Patrick Bellasie2e5e682016-02-23 12:12:28 +0000357 .format(self.target.busybox)).splitlines()[1:]:
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100358 line = line.strip()
359 if not line or line.startswith('#'):
360 continue
361 name, hierarchy, num_cgroups, enabled = line.split()
362 subsystems.append(CgroupSubsystemEntry(name,
363 int(hierarchy),
364 int(num_cgroups),
365 boolean(enabled)))
366 return subsystems
367
368
Patrick Bellasi9c9a7482015-11-03 11:49:31 +0000369 def controller(self, kind):
370 if kind not in self.controllers:
371 self.logger.warning('Controller %s not available', kind)
372 return None
373 return self.controllers[kind]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +0100374
Patrick Bellasib2ec9572016-11-29 10:02:57 +0000375 def run_into_cmd(self, cgroup, cmdline):
Brendan Jackmandbd12992017-01-12 16:34:34 +0000376 """
377 Get the command to run a command into a given cgroup
378
379 :param cmdline: Commdand to be run into cgroup
380 :param cgroup: Name of cgroup to run command into
381 :returns: A command to run `cmdline` into `cgroup`
382 """
Patrick Bellasib2ec9572016-11-29 10:02:57 +0000383 return 'CGMOUNT={} {} cgroups_run_into {} {}'\
384 .format(self.cgroup_root, self.target.shutils,
385 cgroup, cmdline)
386
Patrick Bellasi28739392016-04-22 11:43:49 +0100387 def run_into(self, cgroup, cmdline):
388 """
389 Run the specified command into the specified CGroup
Brendan Jackmandbd12992017-01-12 16:34:34 +0000390
391 :param cmdline: Command to be run into cgroup
392 :param cgroup: Name of cgroup to run command into
393 :returns: Output of command.
Patrick Bellasi28739392016-04-22 11:43:49 +0100394 """
Brendan Jackmand0e28f02017-01-12 16:38:12 +0000395 cmd = self.run_into_cmd(cgroup, cmdline)
Brendan Jackmande619372017-01-12 16:45:54 +0000396 raw_output = self.target.execute(cmd)
397
398 # First line of output comes from shutils; strip it out.
399 return raw_output.split('\n', 1)[1]
Patrick Bellasi28739392016-04-22 11:43:49 +0100400
401 def cgroups_tasks_move(self, srcg, dstg, exclude=''):
402 """
403 Move all the tasks from the srcg CGroup to the dstg one.
404 A regexps of tasks names can be used to defined tasks which should not
405 be moved.
406 """
407 return self.target._execute_util(
408 'cgroups_tasks_move {} {} {}'.format(srcg, dstg, exclude),
409 as_root=True)
410
Patrick Bellasi75a086d2016-08-26 16:29:43 +0100411 def isolate(self, cpus, exclude=[]):
412 """
413 Remove all userspace tasks from specified CPUs.
414
415 A list of CPUs can be specified where we do not want userspace tasks
416 running. This functions creates a sandbox cpuset CGroup where all
417 user-space tasks and not-pinned kernel-space tasks are moved into.
418 This should allows to isolate the specified CPUs which will not get
419 tasks running unless explicitely moved into the isolated group.
420
421 :param cpus: the list of CPUs to isolate
422 :type cpus: list(int)
423
424 :return: the (sandbox, isolated) tuple, where:
425 sandbox is the CGroup of sandboxed CPUs
426 isolated is the CGroup of isolated CPUs
427 """
428 all_cpus = set(range(self.target.number_of_cpus))
429 sbox_cpus = list(all_cpus - set(cpus))
430 isol_cpus = list(all_cpus - set(sbox_cpus))
431
432 # Create Sandbox and Isolated cpuset CGroups
433 cpuset = self.controller('cpuset')
434 sbox_cg = cpuset.cgroup('/DEVLIB_SBOX')
435 isol_cg = cpuset.cgroup('/DEVLIB_ISOL')
436
437 # Set CPUs for Sandbox and Isolated CGroups
438 sbox_cg.set(cpus=sbox_cpus, mems=0)
439 isol_cg.set(cpus=isol_cpus, mems=0)
440
441 # Move all currently running tasks to the Sandbox CGroup
442 cpuset.move_all_tasks_to('/DEVLIB_SBOX', exclude)
443
444 return sbox_cg, isol_cg
445
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100446 def freeze(self, exclude=[], thaw=False):
447 """
Patrick Bellasi730bb602016-08-31 11:40:10 +0100448 Freeze all user-space tasks but the specified ones
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100449
450 A freezer cgroup is used to stop all the tasks in the target system but
451 the ones which name match one of the path specified by the exclude
452 paramater. The name of a tasks to exclude must be a substring of the
453 task named as reported by the "ps" command. Indeed, this list will be
454 translated into a: "ps | grep -e name1 -e name2..." in order to obtain
455 the PID of these tasks.
456
457 :param exclude: list of commands paths to exclude from freezer
Patrick Bellasi730bb602016-08-31 11:40:10 +0100458 :type exclude: list(str)
459
460 :param thaw: if true thaw tasks instead
461 :type thaw: bool
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100462 """
463
464 # Create Freezer CGroup
465 freezer = self.controller('freezer')
Brendan Jackmanc89f7122016-11-25 11:56:42 +0000466 if freezer is None:
467 raise RuntimeError('freezer cgroup controller not present')
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100468 freezer_cg = freezer.cgroup('/DEVLIB_FREEZER')
Quentin Perret4b364392017-08-21 18:16:10 +0100469 cmd = 'cgroups_freezer_set_state {{}} {}'.format(freezer_cg.directory)
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100470
471 if thaw:
472 # Restart froozen tasks
Quentin Perret4b364392017-08-21 18:16:10 +0100473 freezer.target._execute_util(cmd.format('THAWED'), as_root=True)
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100474 # Remove all tasks from freezer
475 freezer.move_all_tasks_to('/')
476 return
477
478 # Move all tasks into the freezer group
479 freezer.move_all_tasks_to('/DEVLIB_FREEZER', exclude)
480
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100481 # Get list of not frozen tasks, which is reported as output
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100482 tasks = freezer.tasks('/')
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100483
484 # Freeze all tasks
Quentin Perret4b364392017-08-21 18:16:10 +0100485 freezer.target._execute_util(cmd.format('FROZEN'), as_root=True)
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100486
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100487 return tasks
488