blob: 005ebaa7f3928dbddebaffa4c32d41e423782c65 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002# Copyright (C) 2013 Intel Corporation
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: MIT
5#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006
7# This module is used by testimage.bbclass for setting up and controlling a target machine.
8
9import os
10import shutil
11import subprocess
12import bb
13import traceback
14import sys
15import logging
16from oeqa.utils.sshcontrol import SSHControl
17from oeqa.utils.qemurunner import QemuRunner
18from oeqa.utils.qemutinyrunner import QemuTinyRunner
19from oeqa.utils.dump import TargetDumper
Andrew Geisslerc926e172021-05-07 16:11:35 -050020from oeqa.utils.dump import MonitorDumper
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021from oeqa.controllers.testtargetloader import TestTargetLoader
22from abc import ABCMeta, abstractmethod
23
Patrick Williamsc0f7c042017-02-23 20:41:17 -060024class BaseTarget(object, metaclass=ABCMeta):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025
26 supported_image_fstypes = []
27
Brad Bishopd7bf8c12018-02-25 22:55:05 -050028 def __init__(self, d, logger):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 self.connection = None
30 self.ip = None
31 self.server_ip = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -050032 self.datetime = d.getVar('DATETIME')
33 self.testdir = d.getVar("TEST_LOG_DIR")
34 self.pn = d.getVar("PN")
Brad Bishopd7bf8c12018-02-25 22:55:05 -050035 self.logger = logger
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036
37 @abstractmethod
38 def deploy(self):
39
40 self.sshlog = os.path.join(self.testdir, "ssh_target_log.%s" % self.datetime)
41 sshloglink = os.path.join(self.testdir, "ssh_target_log")
42 if os.path.islink(sshloglink):
43 os.unlink(sshloglink)
44 os.symlink(self.sshlog, sshloglink)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050045 self.logger.info("SSH log file: %s" % self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
47 @abstractmethod
Patrick Williamsc0f7c042017-02-23 20:41:17 -060048 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049 pass
50
51 @abstractmethod
52 def stop(self):
53 pass
54
55 @classmethod
56 def get_extra_files(self):
57 return None
58
59 @classmethod
60 def match_image_fstype(self, d, image_fstypes=None):
61 if not image_fstypes:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050062 image_fstypes = d.getVar('IMAGE_FSTYPES').split(' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050063 possible_image_fstypes = [fstype for fstype in self.supported_image_fstypes if fstype in image_fstypes]
64 if possible_image_fstypes:
65 return possible_image_fstypes[0]
66 else:
67 return None
68
69 def get_image_fstype(self, d):
70 image_fstype = self.match_image_fstype(d)
71 if image_fstype:
72 return image_fstype
73 else:
74 bb.fatal("IMAGE_FSTYPES should contain a Target Controller supported image fstype: %s " % ', '.join(map(str, self.supported_image_fstypes)))
75
76 def restart(self, params=None):
77 self.stop()
78 self.start(params)
79
80 def run(self, cmd, timeout=None):
81 return self.connection.run(cmd, timeout)
82
83 def copy_to(self, localpath, remotepath):
84 return self.connection.copy_to(localpath, remotepath)
85
86 def copy_from(self, remotepath, localpath):
87 return self.connection.copy_from(remotepath, localpath)
88
89
90
91class QemuTarget(BaseTarget):
92
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050093 supported_image_fstypes = ['ext3', 'ext4', 'cpio.gz', 'wic']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050094
Brad Bishopd7bf8c12018-02-25 22:55:05 -050095 def __init__(self, d, logger, image_fstype=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096
Brad Bishop316dfdd2018-06-25 12:45:53 -040097 import oe.types
98
Brad Bishopd7bf8c12018-02-25 22:55:05 -050099 super(QemuTarget, self).__init__(d, logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500101 self.rootfs = ''
102 self.kernel = ''
103 self.image_fstype = ''
104
105 if d.getVar('FIND_ROOTFS') == '1':
106 self.image_fstype = image_fstype or self.get_image_fstype(d)
107 self.rootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), d.getVar("IMAGE_LINK_NAME") + '.' + self.image_fstype)
108 self.kernel = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), d.getVar("KERNEL_IMAGETYPE", False) + '-' + d.getVar('MACHINE', False) + '.bin')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500109 self.qemulog = os.path.join(self.testdir, "qemu_boot_log.%s" % self.datetime)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500110 dump_target_cmds = d.getVar("testimage_dump_target")
111 dump_host_cmds = d.getVar("testimage_dump_host")
Andrew Geisslerc926e172021-05-07 16:11:35 -0500112 dump_monitor_cmds = d.getVar("testimage_dump_monitor")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500113 dump_dir = d.getVar("TESTIMAGE_DUMP_DIR")
Brad Bishop977dc1a2019-02-06 16:01:43 -0500114 if not dump_dir:
115 dump_dir = os.path.join(d.getVar('LOG_DIR'), 'runtime-hostdump')
116 use_kvm = oe.types.qemu_use_kvm(d.getVar('QEMU_USE_KVM'), d.getVar('TARGET_ARCH'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117
118 # Log QemuRunner log output to a file
119 import oe.path
120 bb.utils.mkdirhier(self.testdir)
121 self.qemurunnerlog = os.path.join(self.testdir, 'qemurunner_log.%s' % self.datetime)
Andrew Geissler82c905d2020-04-13 13:39:40 -0500122 self.loggerhandler = logging.FileHandler(self.qemurunnerlog)
123 self.loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
124 self.logger.addHandler(self.loggerhandler)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 oe.path.symlink(os.path.basename(self.qemurunnerlog), os.path.join(self.testdir, 'qemurunner_log'), force=True)
126
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500127 if d.getVar("DISTRO") == "poky-tiny":
128 self.runner = QemuTinyRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500130 tmpdir = d.getVar("TMPDIR"),
131 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
132 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500133 logfile = self.qemulog,
134 kernel = self.kernel,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500135 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500136 tmpfsdir = d.getVar("RUNQEMU_TMPFS_DIR"),
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500137 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500139 self.runner = QemuRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500140 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500141 tmpdir = d.getVar("TMPDIR"),
142 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
143 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 logfile = self.qemulog,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500145 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600146 use_kvm = use_kvm,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147 dump_dir = dump_dir,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500148 dump_host_cmds = d.getVar("testimage_dump_host"),
Andrew Geissler82c905d2020-04-13 13:39:40 -0500149 logger = logger,
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500150 tmpfsdir = d.getVar("RUNQEMU_TMPFS_DIR"),
Andrew Geissler82c905d2020-04-13 13:39:40 -0500151 serial_ports = len(d.getVar("SERIAL_CONSOLES").split()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152
153 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
Andrew Geisslerc926e172021-05-07 16:11:35 -0500154 self.monitor_dumper = MonitorDumper(dump_monitor_cmds, dump_dir, self.runner)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500155
156 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600157 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500158
159 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
160 if os.path.islink(qemuloglink):
161 os.unlink(qemuloglink)
162 os.symlink(self.qemulog, qemuloglink)
163
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500164 self.logger.info("rootfs file: %s" % self.rootfs)
165 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500166 super(QemuTarget, self).deploy()
167
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500168 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
169 if launch_cmd:
Brad Bishopc342db32019-05-15 21:57:59 -0400170 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd, qemuparams=params)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500171 else:
172 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
173
174 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500175 if ssh:
176 self.ip = self.runner.ip
177 self.server_ip = self.runner.server_ip
178 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179 else:
180 self.stop()
181 if os.path.exists(self.qemulog):
182 with open(self.qemulog, 'r') as f:
183 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
Brad Bishop08902b02019-08-20 09:16:51 -0400184 raise RuntimeError("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185
186 def check(self):
187 return self.runner.is_alive()
188
189 def stop(self):
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500190 try:
191 self.runner.stop()
192 except:
193 pass
Andrew Geissler82c905d2020-04-13 13:39:40 -0500194 self.logger.removeHandler(self.loggerhandler)
Andrew Geissler475cb722020-07-10 16:00:51 -0500195 self.loggerhandler.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500196 self.connection = None
197 self.ip = None
198 self.server_ip = None
199
200 def restart(self, params=None):
201 if self.runner.restart(params):
202 self.ip = self.runner.ip
203 self.server_ip = self.runner.server_ip
204 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
205 else:
Brad Bishop08902b02019-08-20 09:16:51 -0400206 raise RuntimError("%s - FAILED to re-start qemu - check the task log and the boot log" % self.pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500207
Brad Bishop977dc1a2019-02-06 16:01:43 -0500208 def run_serial(self, command, timeout=60):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500209 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500210
211
212class SimpleRemoteTarget(BaseTarget):
213
214 def __init__(self, d):
215 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500216 addr = d.getVar("TEST_TARGET_IP") or bb.fatal('Please set TEST_TARGET_IP with the IP address of the machine you want to run the tests on.')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217 self.ip = addr.split(":")[0]
218 try:
219 self.port = addr.split(":")[1]
220 except IndexError:
221 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500222 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500223 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224 if not self.server_ip:
225 try:
226 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
227 except Exception as e:
228 bb.fatal("Failed to determine the host IP address (alternatively you can set TEST_SERVER_IP with the IP address of this machine): %s" % e)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500229 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500230
231 def deploy(self):
232 super(SimpleRemoteTarget, self).deploy()
233
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600234 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500235 if ssh:
236 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500237
238 def stop(self):
239 self.connection = None
240 self.ip = None
241 self.server_ip = None