This will enable easier and more efficient mass-deployment of identical applications
using the spanning tree method.
self.sudo = False
self.build = None
+ self.install = None
self.depends = None
self.buildDepends = None
self.sources = None
if proc.wait():
raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
+ def _replace_paths(self, command):
+ """
+ Replace all special path tags with shell-escaped actual paths.
+ """
+ # need to append ${HOME} if paths aren't absolute, to MAKE them absolute.
+ root = '' if self.home_path.startswith('/') else "${HOME}/"
+ return ( command
+ .replace("${SOURCES}", root+server.shell_escape(self.home_path))
+ .replace("${BUILD}", root+server.shell_escape(os.path.join(self.home_path,'build'))) )
+
def _build(self):
if self.sources:
sources = self.sources.split(' ')
if self.build:
- # Install build dependencies
+ # Build sources
(out,err),proc = server.popen_ssh_command(
- "cd %(home)s ; %(command)s" % {
- 'command' : self.build,
+ "cd %(home)s && mkdir -p build && cd build && %(command)s" % {
+ 'command' : self._replace_paths(self.build),
'home' : server.shell_escape(self.home_path),
},
host = self.node.hostname,
if proc.wait():
raise RuntimeError, "Failed instal build sources: %s %s" % (out,err,)
+ # Make archive
+ (out,err),proc = server.popen_ssh_command(
+ "cd %(home)s && tar czf build.tar.gz build" % {
+ 'command' : self._replace_paths(self.build),
+ 'home' : server.shell_escape(self.home_path),
+ },
+ host = self.node.hostname,
+ port = None,
+ user = self.slicename,
+ agent = None,
+ ident_key = self.ident_path,
+ server_key = self.node.server_key
+ )
+
+ if proc.wait():
+ raise RuntimeError, "Failed instal build sources: %s %s" % (out,err,)
+
+ if self.install:
+ # Install application
+ (out,err),proc = server.popen_ssh_command(
+ "cd %(home)s && cd build && %(command)s" % {
+ 'command' : self._replace_paths(self.install),
+ 'home' : server.shell_escape(self.home_path),
+ },
+ host = self.node.hostname,
+ port = None,
+ user = self.slicename,
+ agent = None,
+ ident_key = self.ident_path,
+ server_key = self.node.server_key
+ )
+
+ if proc.wait():
+ raise RuntimeError, "Failed instal build sources: %s %s" % (out,err,)
"build": dict({
"name": "build",
"help": "Build commands to execute after deploying the sources. "
- "Sources will be in the initial working folder. "
- "Example: cd my-app && ./configure && make && make install.\n"
- "Try to make the commands return with a nonzero exit code on error.",
+ "Sources will be in the ${SOURCES} folder. "
+ "Example: tar xzf ${SOURCES}/my-app.tgz && cd my-app && ./configure && make && make clean.\n"
+ "Try to make the commands return with a nonzero exit code on error.\n"
+ "Also, do not install any programs here, use the 'install' attribute. This will "
+ "help keep the built files constrained to the build folder (which may "
+ "not be the home folder), and will result in faster deployment. Also, "
+ "make sure to clean up temporary files, to reduce bandwidth usage between "
+ "nodes when transferring built packages.",
+ "type": Attribute.STRING,
+ "flags": Attribute.DesignOnly,
+ "validation_function": validation.is_string
+ }),
+ "install": dict({
+ "name": "install",
+ "help": "Commands to transfer built files to their final destinations. "
+ "Sources will be in the initial working folder, and a special "
+ "tag ${SOURCES} can be used to reference the experiment's "
+ "home folder (where the application commands will run).\n"
+ "ALL sources and targets needed for execution must be copied there, "
+ "if building has been enabled.\n"
+ "That is, 'slave' nodes will not automatically get any source files.",
"type": Attribute.STRING,
"flags": Attribute.DesignOnly,
"validation_function": validation.is_string
"stop_function": stop_application,
"configure_function": configure_application,
"box_attributes": ["command", "sudo", "stdin",
- "depends", "build-depends", "build",
+ "depends", "build-depends", "build", "install",
"sources" ],
"connector_types": ["node"],
"traces": ["stdout", "stderr"]
instance.defer_create(10, "Application")
instance.defer_create_set(10, "command", "./consts")
instance.defer_create_set(10, "buildDepends", "gcc")
- instance.defer_create_set(10, "build", "gcc consts.c -o consts")
+ instance.defer_create_set(10, "build", "gcc ${SOURCES}/consts.c -o consts")
+ instance.defer_create_set(10, "install", "cp consts ${SOURCES}/consts")
instance.defer_create_set(10, "sources", os.path.join(os.path.dirname(planetlab.__file__),'scripts','consts.c'))
instance.defer_add_trace(10, "stdout")
instance.defer_connect(10, "node", 2, "apps")