1# Copyright (C) 2018 Codethink Limited 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU Lesser General Public 5# License as published by the Free Software Foundation; either 6# version 2 of the License, or (at your option) any later version. 7# 8# This library is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11# Lesser General Public License for more details. 12# 13# You should have received a copy of the GNU Lesser General Public 14# License along with this library. If not, see <http://www.gnu.org/licenses/>. 15# 16# Author: 17# Tristan Daniël Maat <tristan.maat@codethink.co.uk> 18# 19from ruamel import yaml 20 21from ..._message import Message, MessageType 22 23from .job import Job 24 25 26# ElementJob() 27# 28# A job to run an element's commands. When this job is spawned 29# `action_cb` will be called, and when it completes `complete_cb` will 30# be called. 31# 32# Args: 33# scheduler (Scheduler): The scheduler 34# action_name (str): The queue action name 35# max_retries (int): The maximum number of retries 36# action_cb (callable): The function to execute on the child 37# complete_cb (callable): The function to execute when the job completes 38# element (Element): The element to work on 39# kwargs: Remaining Job() constructor arguments 40# 41# Here is the calling signature of the action_cb: 42# 43# action_cb(): 44# 45# This function will be called in the child task 46# 47# Args: 48# element (Element): The element passed to the Job() constructor 49# 50# Returns: 51# (object): Any abstract simple python object, including a string, int, 52# bool, list or dict, this must be a simple serializable object. 53# 54# Here is the calling signature of the complete_cb: 55# 56# complete_cb(): 57# 58# This function will be called when the child task completes 59# 60# Args: 61# job (Job): The job object which completed 62# element (Element): The element passed to the Job() constructor 63# status (JobStatus): The status of whether the workload raised an exception 64# result (object): The deserialized object returned by the `action_cb`, or None 65# if `success` is False 66# 67class ElementJob(Job): 68 def __init__(self, *args, element, queue, action_cb, complete_cb, **kwargs): 69 super().__init__(*args, **kwargs) 70 self.queue = queue 71 self._element = element 72 self._action_cb = action_cb # The action callable function 73 self._complete_cb = complete_cb # The complete callable function 74 75 # Set the task wide ID for logging purposes 76 self.set_task_id(element._unique_id) 77 78 @property 79 def element(self): 80 return self._element 81 82 def child_process(self): 83 84 # Print the element's environment at the beginning of any element's log file. 85 # 86 # This should probably be omitted for non-build tasks but it's harmless here 87 elt_env = self._element.get_environment() 88 env_dump = yaml.round_trip_dump(elt_env, default_flow_style=False, allow_unicode=True) 89 self.message(MessageType.LOG, 90 "Build environment for element {}".format(self._element.name), 91 detail=env_dump) 92 93 # Run the action 94 return self._action_cb(self._element) 95 96 def parent_complete(self, status, result): 97 self._complete_cb(self, self._element, status, self._result) 98 99 def message(self, message_type, message, **kwargs): 100 args = dict(kwargs) 101 args['scheduler'] = True 102 self._scheduler.context.message( 103 Message(self._element._unique_id, 104 message_type, 105 message, 106 **args)) 107 108 def child_process_data(self): 109 data = {} 110 111 workspace = self._element._get_workspace() 112 if workspace is not None: 113 data['workspace'] = workspace.to_dict() 114 115 return data 116