summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu.vizoso@collabora.com>2016-10-27 14:19:24 (GMT)
committerTomeu Vizoso <tomeu.vizoso@collabora.com>2016-10-27 14:19:24 (GMT)
commit59c9369ea0499bbac0abfe35de55cb3f46a64145 (patch)
tree2e08518516a9973b29b21b55801041d1f89ec365
parentc52ffb9f23d55925d412f10000ebf6fea361214d (diff)
downloadlava-dispatcher-depthcharge.tar.gz
lava-dispatcher-depthcharge.tar.xz
WIP: Add support for the depthcharge bootloaderdepthcharge
-rw-r--r--etc/kernel-dtb-initrd.its.jinja248
-rw-r--r--lava_dispatcher/pipeline/actions/boot/depthcharge.py211
-rw-r--r--lava_dispatcher/pipeline/actions/boot/strategies.py1
-rwxr-xr-xsetup.py2
4 files changed, 262 insertions, 0 deletions
diff --git a/etc/kernel-dtb-initrd.its.jinja2 b/etc/kernel-dtb-initrd.its.jinja2
new file mode 100644
index 0000000..50ac8ca
--- /dev/null
+++ b/etc/kernel-dtb-initrd.its.jinja2
@@ -0,0 +1,48 @@
+/dts-v1/;
+
+/ {
+ description = "Linux kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+ images {
+ kernel@1{
+ description = "vmlinuz";
+ data = /incbin/("{{kernel_file_name}}");
+ type = "kernel_noload";
+ arch = "arm";
+ os = "linux";
+ compression = "none";
+ hash@1{
+ algo = "sha1";
+ };
+ };
+ fdt@1{
+ description = "dtb";
+ data = /incbin/("{{dtb_file_name}}");
+ type = "flat_dt";
+ arch = "arm";
+ compression = "none";
+ hash@1{
+ algo = "sha1";
+ };
+ };
+ ramdisk@1{
+ description = "initrd.img";
+ data = /incbin/("{{ramdisk_file_name}}");
+ type = "ramdisk";
+ arch = "arm";
+ os = "linux";
+ compression = "none";
+ hash@1{
+ algo = "sha1";
+ };
+ };
+ };
+ configurations {
+ default = "conf@1";
+ conf@1{
+ kernel = "kernel@1";
+ fdt = "fdt@1";
+ ramdisk = "ramdisk@1";
+ };
+ };
+};
diff --git a/lava_dispatcher/pipeline/actions/boot/depthcharge.py b/lava_dispatcher/pipeline/actions/boot/depthcharge.py
new file mode 100644
index 0000000..ac3ed8b
--- /dev/null
+++ b/lava_dispatcher/pipeline/actions/boot/depthcharge.py
@@ -0,0 +1,211 @@
+# Copyright (C) 2014 Linaro Limited
+#
+# Author: Neil Williams <neil.williams@linaro.org>
+#
+# This file is part of LAVA Dispatcher.
+#
+# LAVA Dispatcher is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LAVA Dispatcher is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along
+# with this program; if not, see <http://www.gnu.org/licenses>.
+
+# List just the subclasses supported for this base strategy
+# imported by the parser to populate the list of subclasses.
+
+import os.path
+from jinja2 import Template
+from lava_dispatcher.pipeline.action import (
+ Action,
+ Pipeline,
+ Timeout,
+ InfrastructureError,
+)
+from lava_dispatcher.pipeline.logical import Boot
+from lava_dispatcher.pipeline.actions.boot import BootAction, AutoLoginAction
+from lava_dispatcher.pipeline.actions.boot.environment import ExportDeviceEnvironment
+from lava_dispatcher.pipeline.shell import ExpectShellSession
+from lava_dispatcher.pipeline.connections.serial import ConnectDevice
+from lava_dispatcher.pipeline.power import ResetDevice
+
+def depthcharge_accepts(device, parameters):
+ if 'method' not in parameters:
+ raise RuntimeError("method not specified in boot parameters")
+ if parameters['method'] != 'depthcharge':
+ return False
+ if 'actions' not in device:
+ raise RuntimeError("Invalid device configuration")
+ if 'boot' not in device['actions']:
+ return False
+ if 'methods' not in device['actions']['boot']:
+ raise RuntimeError("Device misconfiguration")
+ return True
+
+
+class Depthcharge(Boot):
+ """
+ The Depthcharge method prepares the command to run on the dispatcher but this
+ command needs to start a new connection and then interrupt depthcharge.
+ An expect shell session can then be handed over to the DepthchargeAction.
+ self.run_command is a blocking call, so Boot needs to use
+ a direct spawn call via ShellCommand (which wraps pexpect.spawn) then
+ hand this pexpect wrapper to subsequent actions as a shell connection.
+ """
+ def __init__(self, parent, parameters):
+ super(Depthcharge, self).__init__(parent)
+ self.action = DepthchargeAction()
+ self.action.section = self.action_type
+ self.action.job = self.job
+ parent.add_action(self.action, parameters)
+
+ @classmethod
+ def accepts(cls, device, parameters):
+ if not depthcharge_accepts(device, parameters):
+ return False
+ return 'depthcharge' in device['actions']['boot']['methods']
+
+
+class DepthchargeAction(BootAction):
+ """
+ Wraps the Retry Action to allow for actions which precede
+ the reset, e.g. Connect.
+ """
+ def __init__(self):
+ super(DepthchargeAction, self).__init__()
+ self.name = "depthcharge-action"
+ self.description = "interactive depthcharge action"
+ self.summary = "pass depthcharge commands"
+
+ def populate(self, parameters):
+ self.internal_pipeline = Pipeline(parent=self, job=self.job, parameters=parameters)
+ # customize the device configuration for this job
+ self.internal_pipeline.add_action(DepthchargePrepareFITAction())
+ self.internal_pipeline.add_action(DepthchargePrepareArgsAction())
+ self.internal_pipeline.add_action(ConnectDevice())
+ self.internal_pipeline.add_action(DepthchargeRetry())
+
+
+class DepthchargeRetry(BootAction):
+
+ def __init__(self):
+ super(DepthchargeRetry, self).__init__()
+ self.name = "depthcharge-retry"
+ self.description = "interactive depthcharge retry action"
+ self.summary = "depthcharge commands with retry"
+
+ def populate(self, parameters):
+ self.internal_pipeline = Pipeline(parent=self, job=self.job, parameters=parameters)
+ self.internal_pipeline.add_action(ResetDevice())
+ self.internal_pipeline.add_action(DepthchargeWaitForBoot())
+ # Add AutoLoginAction unconditionally as this action does nothing if
+ # the configuration does not contain 'auto_login'
+ self.internal_pipeline.add_action(AutoLoginAction())
+ self.internal_pipeline.add_action(ExpectShellSession()) # wait
+ self.internal_pipeline.add_action(ExportDeviceEnvironment())
+
+ def run(self, connection, args=None):
+ connection = super(DepthchargeRetry, self).run(connection, args)
+ # Log an error only when needed
+ if self.errors:
+ self.logger.error(self.errors)
+ self.data['boot-result'] = 'failed'
+ else:
+ self.data['boot-result'] = 'success'
+ return connection
+
+
+class DepthchargeWaitForBoot(Action):
+ """
+ Wait for Depthcharge to start running the kernel
+ """
+ def __init__(self):
+ super(DepthchargeWaitForBoot, self).__init__()
+ self.name = "depthcharge-wait-boot"
+ self.description = "wait for depthcharge to start running the kernel"
+ self.summary = "depthcharge"
+ self.params = None
+ #self.timeout = Timeout(self.name, 30)
+
+ def run(self, connection, args=None):
+ if not connection:
+ self.errors = "%s started without a connection already in use" % self.name
+ connection = super(DepthchargeWaitForBoot, self).run(connection, args)
+ connection.prompt_str = "Exiting depthcharge with code 4 at timestamp"
+ self.logger.debug("Waiting for %s" % connection.prompt_str)
+ connection.timeout = self.connection_timeout
+ self.wait(connection)
+ return connection
+
+
+class DepthchargePrepareFITAction(Action):
+ """
+ Wraps kernel, DTB and ramdisk in a FIT image
+ """
+ def __init__(self):
+ super(DepthchargePrepareFITAction, self).__init__()
+ self.name = "depthcharge-prepare-fit"
+ self.description = "convert kernel to uimage or append dtb"
+ self.summary = "prepare/convert kernel"
+
+ def validate(self):
+ super(DepthchargePrepareFITAction, self).validate()
+
+ def run(self, connection, args=None):
+ connection = super(DepthchargePrepareFITAction, self).run(connection, args)
+
+ kernel_filename = self.data['download_action']['kernel']['file']
+ target_path = os.path.dirname(kernel_filename)
+ kernel_filename = os.path.basename(kernel_filename)
+
+ dtb_filename = self.data['download_action']['dtb']['file']
+ dtb_filename = os.path.basename(dtb_filename)
+
+ ramdisk_filename = self.data['download_action']['ramdisk']['file']
+ ramdisk_filename = os.path.basename(ramdisk_filename)
+
+ its_path = os.path.join(target_path, 'kernel-dtb-initrd.its')
+ itb_path = os.path.join(target_path, 'kernel-dtb-initrd.itb')
+
+ template_path = "/usr/share/lava-dispatcher/kernel-dtb-initrd.its.jinja2"
+ template_data = open(template_path).read()
+ t = Template(template_data)
+ its_data = t.render(kernel_file_name=kernel_filename,
+ dtb_file_name=dtb_filename,
+ ramdisk_file_name=ramdisk_filename)
+ open(its_path, "w").write(its_data)
+
+ cmd = "mkimage -f %s %s" % (its_path, itb_path)
+ if not self.run_command(cmd.split(' ')):
+ raise InfrastructureError("FIT image creation failed")
+
+ return connection
+
+
+class DepthchargePrepareArgsAction(Action):
+ """
+ Writes kernel arguments to cmdline.txt, to be served via tftp
+ """
+ def __init__(self):
+ super(DepthchargePrepareArgsAction, self).__init__()
+ self.name = "depthcharge-prepare-cmdline"
+ self.description = "write cmdline.txt"
+ self.summary = "write cmdline.txt"
+
+ def run(self, connection, args=None):
+ connection = super(DepthchargePrepareArgsAction, self).run(connection, args)
+ kernel_filename = self.data['download_action']['kernel']['file']
+ target_path = os.path.dirname(kernel_filename)
+ target_path = os.path.join(target_path, "cmdline.txt")
+
+ cmdline = "console=ttyS2,115200n8 console=tty1 ignore_loglevel rw rootwait rootdelay=10 root=/dev/nfs nfsroot=10.42.0.1:/home/tomeu/nfsroot,tcp,hard,intr ip=dhcp log_buf_len=16M drm.debug=0x0 no_console_suspend"
+ open(target_path, "w").write(cmdline)
+
+ return connection
diff --git a/lava_dispatcher/pipeline/actions/boot/strategies.py b/lava_dispatcher/pipeline/actions/boot/strategies.py
index 83b7654..1c83a71 100644
--- a/lava_dispatcher/pipeline/actions/boot/strategies.py
+++ b/lava_dispatcher/pipeline/actions/boot/strategies.py
@@ -34,4 +34,5 @@ from lava_dispatcher.pipeline.actions.boot.lxc import BootLxc
from lava_dispatcher.pipeline.actions.boot.ipxe import IPXE
from lava_dispatcher.pipeline.actions.boot.grub import Grub
from lava_dispatcher.pipeline.actions.boot.iso import BootIsoInstaller
+from lava_dispatcher.pipeline.actions.boot.depthcharge import Depthcharge
from lava_dispatcher.pipeline.actions.boot.bootloader_defaults import BootloaderDefaults
diff --git a/setup.py b/setup.py
index 22248d3..a479598 100755
--- a/setup.py
+++ b/setup.py
@@ -116,6 +116,8 @@ setup(
['etc/lava-slave.init']),
('/usr/share/lava-dispatcher/',
['etc/lava-slave.service'])
+ ('/usr/share/lava-dispatcher/',
+ ['etc/kernel-dtb-initrd.its']),
],
scripts=[
'lava-dispatch',