blob: 25b1194090a22b6a8f081d9676084a5c4dbd5984 [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)
396 return self.target.execute(cmd)
Patrick Bellasi28739392016-04-22 11:43:49 +0100397
398 def cgroups_tasks_move(self, srcg, dstg, exclude=''):
399 """
400 Move all the tasks from the srcg CGroup to the dstg one.
401 A regexps of tasks names can be used to defined tasks which should not
402 be moved.
403 """
404 return self.target._execute_util(
405 'cgroups_tasks_move {} {} {}'.format(srcg, dstg, exclude),
406 as_root=True)
407
Patrick Bellasi75a086d2016-08-26 16:29:43 +0100408 def isolate(self, cpus, exclude=[]):
409 """
410 Remove all userspace tasks from specified CPUs.
411
412 A list of CPUs can be specified where we do not want userspace tasks
413 running. This functions creates a sandbox cpuset CGroup where all
414 user-space tasks and not-pinned kernel-space tasks are moved into.
415 This should allows to isolate the specified CPUs which will not get
416 tasks running unless explicitely moved into the isolated group.
417
418 :param cpus: the list of CPUs to isolate
419 :type cpus: list(int)
420
421 :return: the (sandbox, isolated) tuple, where:
422 sandbox is the CGroup of sandboxed CPUs
423 isolated is the CGroup of isolated CPUs
424 """
425 all_cpus = set(range(self.target.number_of_cpus))
426 sbox_cpus = list(all_cpus - set(cpus))
427 isol_cpus = list(all_cpus - set(sbox_cpus))
428
429 # Create Sandbox and Isolated cpuset CGroups
430 cpuset = self.controller('cpuset')
431 sbox_cg = cpuset.cgroup('/DEVLIB_SBOX')
432 isol_cg = cpuset.cgroup('/DEVLIB_ISOL')
433
434 # Set CPUs for Sandbox and Isolated CGroups
435 sbox_cg.set(cpus=sbox_cpus, mems=0)
436 isol_cg.set(cpus=isol_cpus, mems=0)
437
438 # Move all currently running tasks to the Sandbox CGroup
439 cpuset.move_all_tasks_to('/DEVLIB_SBOX', exclude)
440
441 return sbox_cg, isol_cg
442
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100443 def freeze(self, exclude=[], thaw=False):
444 """
Patrick Bellasi730bb602016-08-31 11:40:10 +0100445 Freeze all user-space tasks but the specified ones
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100446
447 A freezer cgroup is used to stop all the tasks in the target system but
448 the ones which name match one of the path specified by the exclude
449 paramater. The name of a tasks to exclude must be a substring of the
450 task named as reported by the "ps" command. Indeed, this list will be
451 translated into a: "ps | grep -e name1 -e name2..." in order to obtain
452 the PID of these tasks.
453
454 :param exclude: list of commands paths to exclude from freezer
Patrick Bellasi730bb602016-08-31 11:40:10 +0100455 :type exclude: list(str)
456
457 :param thaw: if true thaw tasks instead
458 :type thaw: bool
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100459 """
460
461 # Create Freezer CGroup
462 freezer = self.controller('freezer')
Brendan Jackmanc89f7122016-11-25 11:56:42 +0000463 if freezer is None:
464 raise RuntimeError('freezer cgroup controller not present')
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100465 freezer_cg = freezer.cgroup('/DEVLIB_FREEZER')
466 thawed_cg = freezer.cgroup('/')
467
468 if thaw:
469 # Restart froozen tasks
470 freezer_cg.set(state='THAWED')
471 # Remove all tasks from freezer
472 freezer.move_all_tasks_to('/')
473 return
474
475 # Move all tasks into the freezer group
476 freezer.move_all_tasks_to('/DEVLIB_FREEZER', exclude)
477
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100478 # Get list of not frozen tasks, which is reported as output
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100479 tasks = freezer.tasks('/')
Patrick Bellasi23ad61f2016-08-26 18:14:37 +0100480
481 # Freeze all tasks
482 freezer_cg.set(state='FROZEN')
483
Patrick Bellasic8f118d2016-08-31 11:39:33 +0100484 return tasks
485