diff options
author | Jannis Pohlmann <jannis.pohlmann@codethink.co.uk> | 2012-01-23 17:52:37 +0000 |
---|---|---|
committer | Jannis Pohlmann <jannis.pohlmann@codethink.co.uk> | 2012-01-23 18:26:51 +0000 |
commit | d8f4dbdfe07df8cbb576e32f653c86190f07c392 (patch) | |
tree | f3844aece4a8ff488504b040d6b773102367042c /morph | |
parent | 9d59ed4d78747902cd141f743a6aeabd9e531dc8 (diff) | |
download | morph-d8f4dbdfe07df8cbb576e32f653c86190f07c392.tar.gz |
Add controller, worker classes and a new "build-distributed" command.
This commit introduces four new classes:
BuildController:
* takes an app instance and a tempdir
* allows to add BuildWorker objects
* provides a build() method that takes a set of blobs and
a build order that is then built by assigning work to the
build workers as needed
* the build() method takes care of polling the workers for
their state, moving them between busy and idle states
reliably, collect and print their output in a non-confusing
order, and makes sure to wait for all workers to finish
before processing the next group in the build order.
* at this point, when waiting for one or more workers to
become idle to assign them another blob to build, the
controller always picks the worker that has been idling
for the longest period of time. this can be changed later.
BuildWorker:
* base class for all worker classes
* takes a name and an app instance
* has a idle_since datetime property
* provides a build() method that takes a Blob object and builds
it in whatever way the subclasses implement it
* provides a check_complete(timeout) method that checks whether
the worker has finished building the blob yet or not
LocalBuildWorker:
* worker class for local builds that don't go through SSH
* it uses morphlib.execute.Execute to run morph in a child process
in build()
* at the moment, this class executes "./morph" instead of "morph"
as it assumes the user to run morph from its source tree. obviously,
this will have to be fixed later.
RemoteBuildWorker:
* doesn't implement anything yet, will be used for distributing
work to other machines running morph via SSH
Notes:
* At the moment, there is a degree of undesired redundancy when
building a stratum in a worker, as this will cause the worker to
rebuild all its dependencies. This will have to be fixed as it is
avoidable and wastes a lot of time and processing power.
Diffstat (limited to 'morph')
-rwxr-xr-x | morph | 68 |
1 files changed, 60 insertions, 8 deletions
@@ -67,6 +67,12 @@ class Morph(cliapp.Application): metavar='TIMEOUT', default=10) + self.settings.string_list(['worker'], + 'IP or host name of a machine to distribute ' + 'build work to', + metavar='HOSTNAME') + + def cmd_build(self, args): '''Build a binary from a morphology. @@ -102,7 +108,7 @@ class Morph(cliapp.Application): # build things in this order ret.append(builder.build(blobs, order)) - + # we may not have permission to tempdir.remove() ex = morphlib.execute.Execute('.', lambda msg: None) ex.runv(["rm", "-rf", tempdir.dirname]) @@ -111,20 +117,20 @@ class Morph(cliapp.Application): raise cliapp.AppException('Extra args on command line: %s' % args) return ret - + def cmd_testsysimg(self, args): '''Run tests for a built system image. - + Command line arguments are the filename of the system image, and the filenames of the Python modules that contain the test "stories". Each module must have a variable called "story", which is a list of tuples. Each tuple is either two strings (one to send, the other a regular expression for what is expected in return), or two strings and a timeout in seconds. - + testsysimg runs the image under KVM, and accesses it via a serial console, and runs the test stories, one by one. - + ''' if not args: @@ -145,11 +151,11 @@ class Morph(cliapp.Application): def cmd_test(self, args): '''Build and test a system morphology. - + The tests are specified in the morphology's test-stories field. - + ''' - + for morph, built in self.cmd_build(args): if morph.kind == 'system': self.msg('running tests on system %s' % morph.name) @@ -214,6 +220,52 @@ class Morph(cliapp.Application): source_manager) builder.get_cache_id(blob) + def cmd_build_distributed(self, args): + tempdir = morphlib.tempdir.Tempdir() + morph_loader = MorphologyLoader(self.settings) + source_manager = morphlib.sourcemanager.SourceManager(self) + + # create a build controller + controller = morphlib.buildcontroller.BuildController(self, tempdir) + + # create and add the build workers + if len(self.settings['worker']) == 0: + worker = morphlib.buildworker.LocalBuildWorker("local-1", self) + controller.add_worker(worker) + worker = morphlib.buildworker.LocalBuildWorker("local-2", self) + controller.add_worker(worker) + else: + for worker in self.settings['worker']: + worker = morphlib.buildworker.RemoteBuildWorker(self) + controller.add_worker(worker) + + result = [] + + while len(args) >= 3: + # read the build tuple from the command line + repo, ref, filename = args[:3] + args = args[3:] + + # derive a build order from the dependency graph + graph = BuildDependencyGraph(source_manager, morph_loader, + repo, ref, filename) + graph.resolve() + blobs, order = graph.build_order() + + self.msg('Building %s|%s|%s' % (repo, ref, filename)) + + # build the tuple and all its dependencies + result.append(controller.build(blobs, order)) + + # we may not have permission to tempdir.remove() + ex = morphlib.execute.Execute('.', lambda msg: None) + ex.runv(["rm", "-rf", tempdir.dirname]) + + if args: + raise cliapp.AppException('Extra args on command line: %s' % args) + + return result + def msg(self, msg): '''Show a message to the user about what is going on.''' logging.debug(msg) |