* [PATCH 1/3] initrdscripts: add install scripts with a second rootfs
2014-03-30 14:47 [PATCH 0/3] Master image generation and hw testing Stefan Stanacar
@ 2014-03-30 14:47 ` Stefan Stanacar
2014-03-30 14:47 ` [PATCH 2/3] recipes-extended: add master image for testing purposes Stefan Stanacar
2014-03-30 14:47 ` [PATCH 3/3] lib/oeqa: add a test target controller for EFI targets Stefan Stanacar
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Stanacar @ 2014-03-30 14:47 UTC (permalink / raw)
To: openembedded-core
These are meant to be used by a master image, for a simple
initial setup.
The install scripts are similar to the default ones, but:
- custom partitioning, replaces the swap partiton with a second root filesystem
- adds labels to the partitions
- preconfigures a boot loader entry for the second rootfs
Part of [YOCTO #5614]
Signed-off-by: Stefan Stanacar <stefanx.stanacar@intel.com>
---
.../initrdscripts/files/init-install-efi-testfs.sh | 199 +++++++++++++++++++
.../initrdscripts/files/init-install-testfs.sh | 211 +++++++++++++++++++++
.../initramfs-live-install-efi-testfs_1.0.bb | 14 ++
.../initramfs-live-install-testfs_1.0.bb | 14 ++
4 files changed, 438 insertions(+)
create mode 100644 meta/recipes-core/initrdscripts/files/init-install-efi-testfs.sh
create mode 100644 meta/recipes-core/initrdscripts/files/init-install-testfs.sh
create mode 100644 meta/recipes-core/initrdscripts/initramfs-live-install-efi-testfs_1.0.bb
create mode 100644 meta/recipes-core/initrdscripts/initramfs-live-install-testfs_1.0.bb
diff --git a/meta/recipes-core/initrdscripts/files/init-install-efi-testfs.sh b/meta/recipes-core/initrdscripts/files/init-install-efi-testfs.sh
new file mode 100644
index 0000000..2fea761
--- /dev/null
+++ b/meta/recipes-core/initrdscripts/files/init-install-efi-testfs.sh
@@ -0,0 +1,199 @@
+#!/bin/sh -e
+#
+# Copyright (c) 2012, Intel Corporation.
+# All rights reserved.
+#
+# install.sh [device_name] [rootfs_name]
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+# We need 200 Mb for the boot partition
+boot_size=200
+
+# 50% for the second rootfs
+testfs_ratio=50
+
+found="no"
+
+echo "Searching for a hard drive..."
+for device in 'hda' 'hdb' 'sda' 'sdb' 'mmcblk0' 'mmcblk1'
+do
+ if [ -e /sys/block/${device}/removable ]; then
+ if [ "$(cat /sys/block/${device}/removable)" = "0" ]; then
+ found="yes"
+
+ while true; do
+ # Try sleeping here to avoid getting kernel messages
+ # obscuring/confusing user
+ sleep 5
+ echo "Found drive at /dev/${device}. Do you want to install this image there ? [y/n]"
+ read answer
+ if [ "$answer" = "y" ] ; then
+ break
+ fi
+
+ if [ "$answer" = "n" ] ; then
+ found=no
+ break
+ fi
+
+ echo "Please answer y or n"
+ done
+ fi
+ fi
+
+ if [ "$found" = "yes" ]; then
+ break;
+ fi
+
+done
+
+if [ "$found" = "no" ]; then
+ exit 1
+fi
+
+echo "Installing image on /dev/${device}"
+
+#
+# The udev automounter can cause pain here, kill it
+#
+rm -f /etc/udev/rules.d/automount.rules
+rm -f /etc/udev/scripts/mount*
+
+#
+# Unmount anything the automounter had mounted
+#
+umount /dev/${device}* 2> /dev/null || /bin/true
+
+mkdir -p /tmp
+cat /proc/mounts > /etc/mtab
+
+disk_size=$(parted /dev/${device} unit mb print | grep Disk | cut -d" " -f 3 | sed -e "s/MB//")
+
+testfs_size=$((disk_size*testfs_ratio/100))
+rootfs_size=$((disk_size-boot_size-testfs_size))
+
+rootfs_start=$((boot_size))
+rootfs_end=$((rootfs_start+rootfs_size))
+testfs_start=$((rootfs_end))
+
+# MMC devices are special in a couple of ways
+# 1) they use a partition prefix character 'p'
+# 2) they are detected asynchronously (need rootwait)
+rootwait=""
+part_prefix=""
+if [ ! "${device#mmcblk}" = "${device}" ]; then
+ part_prefix="p"
+ rootwait="rootwait"
+fi
+bootfs=/dev/${device}${part_prefix}1
+rootfs=/dev/${device}${part_prefix}2
+testfs=/dev/${device}${part_prefix}3
+
+echo "*****************"
+echo "Boot partition size: $boot_size MB ($bootfs)"
+echo "Rootfs partition size: $rootfs_size MB ($rootfs)"
+echo "Testfs partition size: $testfs_size MB ($testfs)"
+echo "*****************"
+echo "Deleting partition table on /dev/${device} ..."
+dd if=/dev/zero of=/dev/${device} bs=512 count=2
+
+echo "Creating new partition table on /dev/${device} ..."
+parted /dev/${device} mklabel gpt
+
+echo "Creating boot partition on $bootfs"
+parted /dev/${device} mkpart primary 0% $boot_size
+parted /dev/${device} set 1 boot on
+
+echo "Creating rootfs partition on $rootfs"
+parted /dev/${device} mkpart primary $rootfs_start $rootfs_end
+
+echo "Creating testfs partition on $testfs"
+parted /dev/${device} mkpart primary $testfs_start 100%
+
+parted /dev/${device} print
+
+echo "Formatting $bootfs to vfat..."
+mkfs.vfat -n "boot" $bootfs
+
+echo "Formatting $rootfs to ext3..."
+mkfs.ext3 -L "platform" $rootfs
+
+echo "Formatting $testfs to ext3..."
+mkfs.ext3 -L "testrootfs" $testfs
+
+mkdir /ssd
+mkdir /rootmnt
+mkdir /bootmnt
+
+mount $rootfs /ssd
+mount -o rw,loop,noatime,nodiratime /media/$1/$2 /rootmnt
+
+echo "Copying rootfs files..."
+cp -a /rootmnt/* /ssd
+
+touch /ssd/etc/masterimage
+
+if [ -d /ssd/etc/ ] ; then
+ # We dont want udev to mount our root device while we're booting...
+ if [ -d /ssd/etc/udev/ ] ; then
+ echo "/dev/${device}" >> /ssd/etc/udev/mount.blacklist
+ fi
+fi
+
+umount /ssd
+umount /rootmnt
+
+echo "Preparing boot partition..."
+mount $bootfs /ssd
+
+EFIDIR="/ssd/EFI/BOOT"
+mkdir -p $EFIDIR
+cp /media/$1/vmlinuz /ssd
+# Copy the efi loader
+cp /media/$1/EFI/BOOT/*.efi $EFIDIR
+
+if [ -f /media/$1/EFI/BOOT/grub.cfg ]; then
+ GRUBCFG="$EFIDIR/grub.cfg"
+ cp /media/$1/EFI/BOOT/grub.cfg $GRUBCFG
+ # Update grub config for the installed image
+ # Delete the install entry
+ sed -i "/menuentry 'install'/,/^}/d" $GRUBCFG
+ # Delete the initrd lines
+ sed -i "/initrd /d" $GRUBCFG
+ # Delete any LABEL= strings
+ sed -i "s/ LABEL=[^ ]*/ /" $GRUBCFG
+ # Delete any root= strings
+ sed -i "s/ root=[^ ]*/ /" $GRUBCFG
+ # Add the root= and other standard boot options
+ sed -i "s@linux /vmlinuz *@linux /vmlinuz root=$rootfs rw $rootwait quiet @" $GRUBCFG
+fi
+
+if [ -d /media/$1/loader ]; then
+ GUMMIBOOT_CFGS="/ssd/loader/entries/*.conf"
+ # copy config files for gummiboot
+ cp -dr /media/$1/loader /ssd
+ # delete the install entry
+ rm -f /ssd/loader/entries/install.conf
+ # delete the initrd lines
+ sed -i "/initrd /d" $GUMMIBOOT_CFGS
+ # delete any LABEL= strings
+ sed -i "s/ LABEL=[^ ]*/ /" $GUMMIBOOT_CFGS
+ # delete any root= strings
+ sed -i "s/ root=[^ ]*/ /" $GUMMIBOOT_CFGS
+ # add the root= and other standard boot options
+ sed -i "s@options *@options root=$rootfs rw $rootwait quiet @" $GUMMIBOOT_CFGS
+ # Add the test label
+ echo -ne "title test\nlinux /test-kernel\noptions root=$testfs rw $rootwait quiet\n" > /ssd/loader/entries/test.conf
+fi
+
+umount /ssd
+sync
+
+echo "Remove your installation media, and press ENTER"
+
+read enter
+
+echo "Rebooting..."
+reboot -f
diff --git a/meta/recipes-core/initrdscripts/files/init-install-testfs.sh b/meta/recipes-core/initrdscripts/files/init-install-testfs.sh
new file mode 100644
index 0000000..d2f2420
--- /dev/null
+++ b/meta/recipes-core/initrdscripts/files/init-install-testfs.sh
@@ -0,0 +1,211 @@
+#!/bin/sh -e
+#
+# Copyright (C) 2008-2011 Intel
+#
+# install.sh [device_name] [rootfs_name] [video_mode] [vga_mode]
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+# We need 20 Mb for the boot partition
+boot_size=200
+
+# 50% for the the test partition
+testfs_ratio=50
+
+# Get a list of hard drives
+hdnamelist=""
+live_dev_name=${1%%/*}
+
+echo "Searching for hard drives ..."
+
+for device in `ls /sys/block/`; do
+ case $device in
+ loop*)
+ # skip loop device
+ ;;
+ ram*)
+ # skip ram device
+ ;;
+ *)
+ # skip the device LiveOS is on
+ # Add valid hard drive name to the list
+ if [ $device != $live_dev_name -a -e /dev/$device ]; then
+ hdnamelist="$hdnamelist $device"
+ fi
+ ;;
+ esac
+done
+
+TARGET_DEVICE_NAME=""
+for hdname in $hdnamelist; do
+ # Display found hard drives and their basic info
+ echo "-------------------------------"
+ echo /dev/$hdname
+ if [ -r /sys/block/$hdname/device/vendor ]; then
+ echo -n "VENDOR="
+ cat /sys/block/$hdname/device/vendor
+ fi
+ echo -n "MODEL="
+ cat /sys/block/$hdname/device/model
+ cat /sys/block/$hdname/device/uevent
+ echo
+ # Get user choice
+ while true; do
+ echo -n "Do you want to install this image there? [y/n] "
+ read answer
+ if [ "$answer" = "y" -o "$answer" = "n" ]; then
+ break
+ fi
+ echo "Please answer y or n"
+ done
+ if [ "$answer" = "y" ]; then
+ TARGET_DEVICE_NAME=$hdname
+ break
+ fi
+done
+
+if [ -n "$TARGET_DEVICE_NAME" ]; then
+ echo "Installing image on /dev/$TARGET_DEVICE_NAME ..."
+else
+ echo "No hard drive selected. Installation aborted."
+ exit 1
+fi
+
+device=$TARGET_DEVICE_NAME
+
+#
+# The udev automounter can cause pain here, kill it
+#
+rm -f /etc/udev/rules.d/automount.rules
+rm -f /etc/udev/scripts/mount*
+
+#
+# Unmount anything the automounter had mounted
+#
+umount /dev/${device}* 2> /dev/null || /bin/true
+
+if [ ! -b /dev/loop0 ] ; then
+ mknod /dev/loop0 b 7 0
+fi
+
+mkdir -p /tmp
+cat /proc/mounts > /etc/mtab
+
+disk_size=$(parted /dev/${device} unit mb print | grep Disk | cut -d" " -f 3 | sed -e "s/MB//")
+
+testfs_size=$((disk_size*testfs_ratio/100))
+rootfs_size=$((disk_size-boot_size-testfs_size))
+
+rootfs_start=$((boot_size))
+rootfs_end=$((rootfs_start+rootfs_size))
+testfs_start=$((rootfs_end))
+
+# MMC devices are special in a couple of ways
+# 1) they use a partition prefix character 'p'
+# 2) they are detected asynchronously (need rootwait)
+rootwait=""
+part_prefix=""
+if [ ! "${device#mmcblk}" = "${device}" ]; then
+ part_prefix="p"
+ rootwait="rootwait"
+fi
+bootfs=/dev/${device}${part_prefix}1
+rootfs=/dev/${device}${part_prefix}2
+testfs=/dev/${device}${part_prefix}3
+
+echo "*****************"
+echo "Boot partition size: $boot_size MB ($bootfs)"
+echo "Rootfs partition size: $rootfs_size MB ($rootfs)"
+echo "Testfs partition size: $testfs_size MB ($testfs)"
+echo "*****************"
+echo "Deleting partition table on /dev/${device} ..."
+dd if=/dev/zero of=/dev/${device} bs=512 count=2
+
+echo "Creating new partition table on /dev/${device} ..."
+parted /dev/${device} mklabel msdos
+
+echo "Creating boot partition on $bootfs"
+parted /dev/${device} mkpart primary 0% $boot_size
+
+echo "Creating rootfs partition on $rootfs"
+parted /dev/${device} mkpart primary $rootfs_start $rootfs_end
+
+echo "Creating testfs partition on $testfs"
+parted /dev/${device} mkpart primary $testfs_start 100%
+
+parted /dev/${device} print
+
+echo "Formatting $bootfs to ext3..."
+mkfs.ext3 -L "boot" $bootfs
+
+echo "Formatting $rootfs to ext3..."
+mkfs.ext3 -L "rootfs" $rootfs
+
+echo "Formatting $testfs to ext3..."
+mkfs.ext3 -L "testrootfs" $testfs
+
+mkdir /tgt_root
+mkdir /src_root
+mkdir -p /boot
+
+# Handling of the target root partition
+mount $rootfs /tgt_root
+mount -o rw,loop,noatime,nodiratime /media/$1/$2 /src_root
+echo "Copying rootfs files..."
+cp -a /src_root/* /tgt_root
+if [ -d /tgt_root/etc/ ] ; then
+ echo "$bootfs /boot ext3 defaults 1 2" >> /tgt_root/etc/fstab
+ # We dont want udev to mount our root device while we're booting...
+ if [ -d /tgt_root/etc/udev/ ] ; then
+ echo "/dev/${device}" >> /tgt_root/etc/udev/mount.blacklist
+ fi
+fi
+umount /tgt_root
+umount /src_root
+
+# Handling of the target boot partition
+mount $bootfs /boot
+echo "Preparing boot partition..."
+if [ -f /etc/grub.d/40_custom ] ; then
+ echo "Preparing custom grub2 menu..."
+ GRUBCFG="/boot/grub/grub.cfg"
+ mkdir -p $(dirname $GRUBCFG)
+ cp /etc/grub.d/40_custom $GRUBCFG
+ sed -i "s@__ROOTFS__@$rootfs $rootwait@g" $GRUBCFG
+ sed -i "s/__VIDEO_MODE__/$3/g" $GRUBCFG
+ sed -i "s/__VGA_MODE__/$4/g" $GRUBCFG
+ sed -i "s/__CONSOLE__/$5/g" $GRUBCFG
+ sed -i "/#/d" $GRUBCFG
+ sed -i "/exec tail/d" $GRUBCFG
+
+ # Add the test label
+ echo -ne "\nmenuentry 'test' {\nlinux /test-kernel root=$testfs rw $rootwait quiet\n}\n" >> $GRUBCFG
+
+ chmod 0444 $GRUBCFG
+fi
+grub-install /dev/${device}
+echo "(hd0) /dev/${device}" > /boot/grub/device.map
+
+# If grub.cfg doesn't exist, assume GRUB 0.97 and create a menu.lst
+if [ ! -f /boot/grub/grub.cfg ] ; then
+ echo "Preparing custom grub menu..."
+ echo "default 0" > /boot/grub/menu.lst
+ echo "timeout 30" >> /boot/grub/menu.lst
+ echo "title Live Boot/Install-Image" >> /boot/grub/menu.lst
+ echo "root (hd0,0)" >> /boot/grub/menu.lst
+ echo "kernel /vmlinuz root=$rootfs rw $3 $4 quiet" >> /boot/grub/menu.lst
+fi
+
+cp /media/$1/vmlinuz /boot/
+
+umount /boot
+
+sync
+
+echo "Remove your installation media, and press ENTER"
+
+read enter
+
+echo "Rebooting..."
+reboot -f
diff --git a/meta/recipes-core/initrdscripts/initramfs-live-install-efi-testfs_1.0.bb b/meta/recipes-core/initrdscripts/initramfs-live-install-efi-testfs_1.0.bb
new file mode 100644
index 0000000..a54960c
--- /dev/null
+++ b/meta/recipes-core/initrdscripts/initramfs-live-install-efi-testfs_1.0.bb
@@ -0,0 +1,14 @@
+SUMMARY = "Live image install script for with a second rootfs/kernel option"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+SRC_URI = "file://init-install-efi-testfs.sh"
+
+RDEPENDS_${PN} = "parted e2fsprogs-mke2fs dosfstools"
+
+do_install() {
+ install -m 0755 ${WORKDIR}/init-install-efi-testfs.sh ${D}/install-efi.sh
+}
+
+INHIBIT_DEFAULT_DEPS = "1"
+FILES_${PN} = " /install-efi.sh "
+COMPATIBLE_HOST = "(i.86|x86_64).*-linux"
diff --git a/meta/recipes-core/initrdscripts/initramfs-live-install-testfs_1.0.bb b/meta/recipes-core/initrdscripts/initramfs-live-install-testfs_1.0.bb
new file mode 100644
index 0000000..db4cf54
--- /dev/null
+++ b/meta/recipes-core/initrdscripts/initramfs-live-install-testfs_1.0.bb
@@ -0,0 +1,14 @@
+SUMMARY = "Live image install script with a second rootfs/kernel"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+SRC_URI = "file://init-install-testfs.sh"
+
+RDEPENDS_${PN} = "grub parted e2fsprogs-mke2fs"
+
+do_install() {
+ install -m 0755 ${WORKDIR}/init-install-testfs.sh ${D}/install.sh
+}
+
+INHIBIT_DEFAULT_DEPS = "1"
+FILES_${PN} = " /install.sh "
+COMPATIBLE_HOST = "(i.86|x86_64).*-linux"
--
1.8.5.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/3] recipes-extended: add master image for testing purposes
2014-03-30 14:47 [PATCH 0/3] Master image generation and hw testing Stefan Stanacar
2014-03-30 14:47 ` [PATCH 1/3] initrdscripts: add install scripts with a second rootfs Stefan Stanacar
@ 2014-03-30 14:47 ` Stefan Stanacar
2014-03-30 14:47 ` [PATCH 3/3] lib/oeqa: add a test target controller for EFI targets Stefan Stanacar
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Stanacar @ 2014-03-30 14:47 UTC (permalink / raw)
To: openembedded-core
Add a custom recipe with custom initramfs and installers, that makes
it easy to deploy a master image for testing purposes.
We need a master image running on the target hardware, that should be a
known good build, with a set of utilities installed so that we use it
to deploy the images under test.
This core-image-testmaster recipe isn't a requirement per se, any image can
be used as long as the required conditions are met.
The test code assumes:
- that the device has a second rootfs labeled as testrootfs
- it has a properly configured bootloader entry (called test) for the second kernel and rootfs
- the master image has a /etc/masterimage file so it can differentiate between master
and test images
- the master image has tar, mount, bash (basically the normal linux utilities not the busybox
ones)
[YOCTO #5614]
Signed-off-by: Stefan Stanacar <stefanx.stanacar@intel.com>
---
.../images/core-image-testmaster-initramfs.bb | 19 +++++++++++++++++++
meta/recipes-extended/images/core-image-testmaster.bb | 18 ++++++++++++++++++
2 files changed, 37 insertions(+)
create mode 100644 meta/recipes-extended/images/core-image-testmaster-initramfs.bb
create mode 100644 meta/recipes-extended/images/core-image-testmaster.bb
diff --git a/meta/recipes-extended/images/core-image-testmaster-initramfs.bb b/meta/recipes-extended/images/core-image-testmaster-initramfs.bb
new file mode 100644
index 0000000..563260d
--- /dev/null
+++ b/meta/recipes-extended/images/core-image-testmaster-initramfs.bb
@@ -0,0 +1,19 @@
+DESCRIPTION = "Small image capable of booting a device with custom install scripts, \
+adding a second rootfs, used for testing."
+
+# use -testfs live-install scripts
+PACKAGE_INSTALL = "initramfs-live-boot initramfs-live-install-testfs initramfs-live-install-efi-testfs busybox udev base-passwd ${ROOTFS_BOOTSTRAP_INSTALL}"
+
+# Do not pollute the initrd image with rootfs features
+IMAGE_FEATURES = ""
+
+export IMAGE_BASENAME = "core-image-testmaster-initramfs"
+IMAGE_LINGUAS = ""
+
+LICENSE = "MIT"
+
+IMAGE_FSTYPES = "${INITRAMFS_FSTYPES}"
+inherit core-image
+
+IMAGE_ROOTFS_SIZE = "8192"
+BAD_RECOMMENDATIONS += "busybox-syslog"
diff --git a/meta/recipes-extended/images/core-image-testmaster.bb b/meta/recipes-extended/images/core-image-testmaster.bb
new file mode 100644
index 0000000..ac2fdbe
--- /dev/null
+++ b/meta/recipes-extended/images/core-image-testmaster.bb
@@ -0,0 +1,18 @@
+DESCRIPTION = "A master image to be deployed on a target useful for testing other images"
+
+IMAGE_FEATURES += "ssh-server-openssh package-management"
+
+inherit core-image
+
+# the deploy code requires bash and
+# normal linux utilities not busybox ones
+IMAGE_INSTALL += "\
+ bash coreutils util-linux tar gzip kmod \
+ python-modules python-misc \
+ e2fsprogs e2fsprogs-mke2fs parted \
+ "
+# we need a particular initramfs for live images
+# that pulls custom install scripts which take
+# care of partitioning for us
+INITRD_IMAGE = "core-image-testmaster-initramfs"
+
--
1.8.5.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 3/3] lib/oeqa: add a test target controller for EFI targets
2014-03-30 14:47 [PATCH 0/3] Master image generation and hw testing Stefan Stanacar
2014-03-30 14:47 ` [PATCH 1/3] initrdscripts: add install scripts with a second rootfs Stefan Stanacar
2014-03-30 14:47 ` [PATCH 2/3] recipes-extended: add master image for testing purposes Stefan Stanacar
@ 2014-03-30 14:47 ` Stefan Stanacar
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Stanacar @ 2014-03-30 14:47 UTC (permalink / raw)
To: openembedded-core
The purpose of this module is to deploy a test image on a EFI-enabled hardware
and run our runtime tests. A bit of background:
- testimage.bbclass uses the concept of TEST_TARGET which is a class name
that is responsible for target deploying. A layer can provide
it's own TEST_TARGET. Right now has OE-core has a QemuTarget and a SimpleRemoteTarget
(ssh into an already up and running machine and run tests), the default one being qemu.
- basically testimage does something like:
target.deploy()
try:
target.start()
runTests()
finally:
target.stop()
This module assumes a running EFI machine with gummiboot as bootloader and
core-image-testmaster installed (or similar). Also your hardware under test has
to be in a DHCP-enabled network that gives it the same IP for each reboot.
One time setup (master image):
- build core-image-testmaster with EFI_PROVIDER = "gummiboot"
- install the image on the target
Test image setup:
- build your test image, e.g core-image-sato as you usually do, but with these in local.conf:
IMAGE_FSTYPES += "tar.gz"
- Now run the tests:
INHERIT += "testimage"
TEST_TARGET = "GummibootTarget"
TEST_TARGET_IP = "192.168.2.3"
bitbake core-image-sato -c testimage
Other notes:
- TEST_POWERCONTROL_CMD (togheter with TEST_POWERCONTROL_EXTRA_ARGS) can be a command that runs on the host and does power cycling.
The test code passes one argument to that command: off, on or cycle (off then on). In my case I use something like
TEST_POWERCONTROL_CMD="powercontrol.exp test 10.11.12.1 nuc1" in local.conf.
Basically my expect script does: 'ssh test@10.11.12.1 "pyctl nuc1 <arg>" and runs a python script there that controls power for a label called nuc1'.
The reason why my expect script has to ssh into another machine is because of network topology, and that machine is the one actually connected
to the test rack and the power strip. That's why TEST_POWERCONTROL_CMD and _ARGS need to be customized for one's setup, the only requirement being
that it accepts: on/off/cycle as the last argument.
- if no command is defined it would use classic reboot. This is fine as long as the machine
actually reboots (as in the ssh test hasn't failed), but it's useful for "simple-setup-with-one-board-on-the-desk" scenario, where
some manual interaction is okay from time to time.
[YOCTO #5614]
Signed-off-by: Stefan Stanacar <stefanx.stanacar@intel.com>
---
meta/lib/oeqa/controllers/masterimage.py | 133 +++++++++++++++++++++++++++++++
meta/lib/oeqa/runtime/ssh.py | 2 +
2 files changed, 135 insertions(+)
create mode 100644 meta/lib/oeqa/controllers/masterimage.py
diff --git a/meta/lib/oeqa/controllers/masterimage.py b/meta/lib/oeqa/controllers/masterimage.py
new file mode 100644
index 0000000..188c630
--- /dev/null
+++ b/meta/lib/oeqa/controllers/masterimage.py
@@ -0,0 +1,133 @@
+import os
+import bb
+import traceback
+import time
+
+import oeqa.targetcontrol
+import oeqa.utils.sshcontrol as sshcontrol
+import oeqa.utils.commands as commands
+
+class GummibootTarget(oeqa.targetcontrol.SimpleRemoteTarget):
+
+ def __init__(self, d):
+ # let our base class do the ip thing
+ super(GummibootTarget, self).__init__(d)
+
+ # test rootfs + kernel
+ self.rootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("IMAGE_LINK_NAME", True) + '.tar.gz')
+ self.kernel = os.path.join(d.getVar("DEPLOY_DIR_IMAGE", True), d.getVar("KERNEL_IMAGETYPE"))
+ if not os.path.isfile(self.rootfs):
+ # we could've checked that IMAGE_FSTYPES contains tar.gz but the config for running testimage might not be
+ # the same as the config with which the image was build, ie
+ # you bitbake core-image-sato with IMAGE_FSTYPES += "tar.gz"
+ # and your autobuilder overwrites the config, adds the test bits and runs bitbake core-image-sato -c testimage
+ bb.fatal("No rootfs found. Did you build the image ?\nIf yes, did you build it with IMAGE_FSTYPES += \"tar.gz\" ? \
+ \nExpected path: %s" % self.rootfs)
+ if not os.path.isfile(self.kernel):
+ bb.fatal("No kernel found. Expected path: %s" % self.kernel)
+
+ # if the user knows what he's doing, then by all means...
+ # test-rootfs.tar.gz and test-kernel are hardcoded names in other places
+ # they really have to be used like that in commands though
+ cmds = d.getVar("TEST_DEPLOY_CMDS", True)
+
+ # this the value we need to set in the LoaderEntryOneShot EFI variable
+ # so the system boots the 'test' bootloader label and not the default
+ # The first four bytes are EFI bits, and the rest is an utf-16le string
+ # (EFI vars values need to be utf-16)
+ # $ echo -en "test\0" | iconv -f ascii -t utf-16le | hexdump -C
+ # 00000000 74 00 65 00 73 00 74 00 00 00 |t.e.s.t...|
+ self.efivarvalue = r'\x07\x00\x00\x00\x74\x00\x65\x00\x73\x00\x74\x00\x00\x00'
+
+ if cmds:
+ self.deploy_cmds = cmds.split("\n")
+ else:
+ self.deploy_cmds = [
+ 'mount -L boot /boot',
+ 'mkdir -p /mnt/testrootfs',
+ 'mount -L testrootfs /mnt/testrootfs',
+ 'modprobe efivarfs',
+ 'mount -t efivarfs efivarfs /sys/firmware/efi/efivars',
+ 'cp ~/test-kernel /boot',
+ 'rm -rf /mnt/testrootfs/*',
+ 'tar xzvf ~/test-rootfs.tar.gz -C /mnt/testrootfs',
+ 'printf "%s" > /sys/firmware/efi/efivars/LoaderEntryOneShot-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f' % self.efivarvalue
+ ]
+
+ # master ssh connection
+ self.master = None
+
+ # this is the name of the command that controls the power for a board
+ # e.g: TEST_POWERCONTROL_CMD = "/home/user/myscripts/powercontrol.py ${MACHINE} what-ever-other-args-the-script-wants"
+ # the command should take as the last argument "off" and "on" and "cycle" (off, on)
+ self.powercontrol_cmd = d.getVar("TEST_POWERCONTROL_CMD", True) or None
+ self.powercontrol_args = d.getVar("TEST_POWERCONTROL_EXTRA_ARGS") or ""
+ self.origenv = os.environ
+ if self.powercontrol_cmd:
+ if self.powercontrol_args:
+ self.powercontrol_cmd = "%s %s" % (self.powercontrol_cmd, self.powercontrol_args)
+ # the external script for controlling power might use ssh
+ # ssh + keys means we need the original user env
+ bborigenv = d.getVar("BB_ORIGENV", False) or {}
+ for key in bborigenv:
+ val = bborigenv.getVar(key, True)
+ if val is not None:
+ self.origenv[key] = str(val)
+ self.power_ctl("on")
+
+ def power_ctl(self, msg):
+ if self.powercontrol_cmd:
+ cmd = "%s %s" % (self.powercontrol_cmd, msg)
+ commands.runCmd(cmd, preexec_fn=os.setsid, env=self.origenv)
+
+ def power_cycle(self, conn):
+ if self.powercontrol_cmd:
+ # be nice, don't just cut power
+ conn.run("shutdown -h now")
+ time.sleep(10)
+ self.power_ctl("cycle")
+ else:
+ status, output = conn.run("reboot")
+ if status != 0:
+ bb.error("Failed rebooting target and no power control command defined. You need to manually reset the device.\n%s" % output)
+
+ def deploy(self):
+ bb.plain("%s - deploying image on target" % self.pn)
+ # base class just sets the ssh log file for us
+ super(GummibootTarget, self).deploy()
+ self.master = sshcontrol.SSHControl(ip=self.ip, logfile=self.sshlog, timeout=600, port=self.port)
+ try:
+ self._deploy()
+ except Exception as e:
+ bb.fatal("Failed deploying test image: %s" % e)
+
+ def _deploy(self):
+ # make sure we are in the right image
+ status, output = self.master.run("cat /etc/masterimage")
+ if status != 0:
+ raise Exception("No ssh connectivity or target isn't running a master image.\n%s" % output)
+
+ # make sure these aren't mounted
+ self.master.run("umount /boot; umount /mnt/testrootfs; umount /sys/firmware/efi/efivars;")
+
+ # from now on, every deploy cmd should return 0
+ # else an exception will be thrown by sshcontrol
+ self.master.ignore_status = False
+ self.master.copy_to(self.rootfs, "~/test-rootfs.tar.gz")
+ self.master.copy_to(self.kernel, "~/test-kernel")
+ for cmd in self.deploy_cmds:
+ self.master.run(cmd)
+
+
+ def start(self, params=None):
+ bb.plain("%s - boot test image on target" % self.pn)
+ self.power_cycle(self.master)
+ # there are better ways than a timeout but this should work for now
+ time.sleep(120)
+ # set the ssh object for the target/test image
+ self.connection = sshcontrol.SSHControl(self.ip, logfile=self.sshlog, port=self.port)
+ bb.plain("%s - start running tests" % self.pn)
+
+ def stop(self):
+ bb.plain("%s - reboot/powercycle target" % self.pn)
+ self.power_cycle(self.connection)
diff --git a/meta/lib/oeqa/runtime/ssh.py b/meta/lib/oeqa/runtime/ssh.py
index 8c96020..e648660 100644
--- a/meta/lib/oeqa/runtime/ssh.py
+++ b/meta/lib/oeqa/runtime/ssh.py
@@ -14,3 +14,5 @@ class SshTest(oeRuntimeTest):
def test_ssh(self):
(status, output) = self.target.run('uname -a')
self.assertEqual(status, 0, msg="SSH Test failed: %s" % output)
+ (status, output) = self.target.run('cat /etc/masterimage')
+ self.assertEqual(status, 1, msg="This isn't the right image - /etc/masterimage shouldn't be here %s" % output)
--
1.8.5.3
^ permalink raw reply related [flat|nested] 4+ messages in thread