| 1 | """Laten BuildSlave for Disribute Resource Management Application API |
|---|
| 2 | |
|---|
| 3 | Author: Lital Natan <procscsi@gmail.com> |
|---|
| 4 | |
|---|
| 5 | """ |
|---|
| 6 | |
|---|
| 7 | from twisted.internet import threads |
|---|
| 8 | from buildbot.buildslave import AbstractLatentBuildSlave |
|---|
| 9 | import drmaa |
|---|
| 10 | |
|---|
| 11 | class DRMAALatentBuildSlave(AbstractLatentBuildSlave): |
|---|
| 12 | """Latent BuildSlave for Disribute Resource Management Application API |
|---|
| 13 | |
|---|
| 14 | BuildSlave managed by a Job Distribution System |
|---|
| 15 | When a build is requested, the slave is started on a compute node |
|---|
| 16 | When all builds are done and the slave is idle, it shuts down and the |
|---|
| 17 | job is terminated. |
|---|
| 18 | |
|---|
| 19 | """ |
|---|
| 20 | |
|---|
| 21 | _drmaa_session = None |
|---|
| 22 | drmaa_session_contact = None |
|---|
| 23 | last_job_id = None |
|---|
| 24 | job_template = None |
|---|
| 25 | |
|---|
| 26 | def __init__(self, buildslave_setup_command, *args, **kwargs): |
|---|
| 27 | """Default Constructor |
|---|
| 28 | |
|---|
| 29 | buildslave_setup_command -- the o/s command starting the BuildBot slave |
|---|
| 30 | its recommended to use a command starting a |
|---|
| 31 | non-daemon slave instance. |
|---|
| 32 | *args -- non-keyword arguments for the BuildBot slave |
|---|
| 33 | **kwargs -- keyword arguments for the BuildBot slave |
|---|
| 34 | |
|---|
| 35 | """ |
|---|
| 36 | |
|---|
| 37 | AbstractLatentBuildSlave.__init__(self, *args, **kwargs) |
|---|
| 38 | self.job_template = self._get_blank_job_template() |
|---|
| 39 | self.job_template.remoteCommand = buildslave_setup_command |
|---|
| 40 | |
|---|
| 41 | def _get_blank_job_template(self): |
|---|
| 42 | """Creates a new, default job template from the DRMAA session """ |
|---|
| 43 | |
|---|
| 44 | drmaa_session = self._get_persistent_drmaa_session() |
|---|
| 45 | return drmaa_session.createJobTemplate() |
|---|
| 46 | |
|---|
| 47 | def _get_persistent_drmaa_session(self): |
|---|
| 48 | """Obtains a singleton of the DRMAA session """ |
|---|
| 49 | |
|---|
| 50 | if not DRMAALatentBuildSlave._drmaa_session: |
|---|
| 51 | session = None |
|---|
| 52 | if self.drmaa_session_contact: |
|---|
| 53 | session = drmaa.Session(self.drmaa_session_contact) |
|---|
| 54 | else: |
|---|
| 55 | session = drmaa.Session() |
|---|
| 56 | self.drmaa_session_contact = session.contact |
|---|
| 57 | DRMAALatentBuildSlave._drmaa_session = session |
|---|
| 58 | return DRMAALatentBuildSlave._drmaa_session |
|---|
| 59 | |
|---|
| 60 | def _run_job(self): |
|---|
| 61 | """Submits the BuildBot slave job using """ |
|---|
| 62 | |
|---|
| 63 | drmaa_session = self._get_persistent_drmaa_session() |
|---|
| 64 | self.last_job_id = drmaa_session.runJob(self.job_template) |
|---|
| 65 | |
|---|
| 66 | def _terminate_job(self): |
|---|
| 67 | """Terminates the current running BuildBot slave """ |
|---|
| 68 | |
|---|
| 69 | drmaa_session = self._get_persistent_drmaa_session() |
|---|
| 70 | drmaa_session.control(self.last_job_id, drmaa.JobControlAction.TERMINATE) |
|---|
| 71 | self.last_job_id = None |
|---|
| 72 | |
|---|
| 73 | def start_instance(self): |
|---|
| 74 | """Starts the BuildBot slave -> Deferred thread |
|---|
| 75 | |
|---|
| 76 | Implements AbstractLatentBuildSlave |
|---|
| 77 | |
|---|
| 78 | """ |
|---|
| 79 | |
|---|
| 80 | print "Starting remote slave instance" |
|---|
| 81 | return threads.deferToThread(self._start_instance) |
|---|
| 82 | |
|---|
| 83 | def stop_instance(self, fast=False): |
|---|
| 84 | """Stops the BuildBot slave -> Deferred thread |
|---|
| 85 | |
|---|
| 86 | Implements AbstractLatentBuildSlave |
|---|
| 87 | |
|---|
| 88 | """ |
|---|
| 89 | |
|---|
| 90 | print "Stopping remote slave instance" |
|---|
| 91 | return threads.deferToThread(self._stop_instance) |
|---|
| 92 | |
|---|
| 93 | def _start_instance(self): |
|---|
| 94 | """Starts the BuildBot slave -> Deferred thread |
|---|
| 95 | |
|---|
| 96 | This method exists for extending sub-classes to overwrite if needed |
|---|
| 97 | """ |
|---|
| 98 | |
|---|
| 99 | self._run_job() |
|---|
| 100 | |
|---|
| 101 | def _stop_instance(self): |
|---|
| 102 | """Stops the BuildBot slave -> Deferred thread |
|---|
| 103 | |
|---|
| 104 | This method exists for extending sub-classes to overwrite if needed |
|---|
| 105 | """ |
|---|
| 106 | |
|---|
| 107 | self._terminate_job() |
|---|
| 108 | |
|---|
| 109 | def buildFinished(self, sb): |
|---|
| 110 | """Stops the BuildSlave job when idle""" |
|---|
| 111 | |
|---|
| 112 | self.building.remove(sb.builder_name) |
|---|
| 113 | if not self.building: |
|---|
| 114 | self._setBuildWaitTimer() |
|---|
| 115 | self.insubstantiate() |
|---|