blob: 1fdff82889a30ebb235f2491906a29617eb70271 [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)
Andrew Geissler5f350902021-07-23 13:09:54 -0400155 if (self.monitor_dumper):
156 self.monitor_dumper.create_dir("qmp")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157
158 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600159 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500160
161 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
162 if os.path.islink(qemuloglink):
163 os.unlink(qemuloglink)
164 os.symlink(self.qemulog, qemuloglink)
165
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500166 self.logger.info("rootfs file: %s" % self.rootfs)
167 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500168 super(QemuTarget, self).deploy()
169
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500170 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
171 if launch_cmd:
Brad Bishopc342db32019-05-15 21:57:59 -0400172 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd, qemuparams=params)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500173 else:
174 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
175
176 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500177 if ssh:
178 self.ip = self.runner.ip
179 self.server_ip = self.runner.server_ip
180 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 else:
182 self.stop()
183 if os.path.exists(self.qemulog):
184 with open(self.qemulog, 'r') as f:
185 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
Brad Bishop08902b02019-08-20 09:16:51 -0400186 raise RuntimeError("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187
188 def check(self):
189 return self.runner.is_alive()
190
191 def stop(self):
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500192 try:
193 self.runner.stop()
194 except:
195 pass
Andrew Geissler82c905d2020-04-13 13:39:40 -0500196 self.logger.removeHandler(self.loggerhandler)
Andrew Geissler475cb722020-07-10 16:00:51 -0500197 self.loggerhandler.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500198 self.connection = None
199 self.ip = None
200 self.server_ip = None
201
202 def restart(self, params=None):
203 if self.runner.restart(params):
204 self.ip = self.runner.ip
205 self.server_ip = self.runner.server_ip
206 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
207 else:
Brad Bishop08902b02019-08-20 09:16:51 -0400208 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 -0500209
Brad Bishop977dc1a2019-02-06 16:01:43 -0500210 def run_serial(self, command, timeout=60):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500211 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500212
213
214class SimpleRemoteTarget(BaseTarget):
215
216 def __init__(self, d):
217 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500218 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 -0500219 self.ip = addr.split(":")[0]
220 try:
221 self.port = addr.split(":")[1]
222 except IndexError:
223 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500224 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500225 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500226 if not self.server_ip:
227 try:
228 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
229 except Exception as e:
230 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 -0500231 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232
233 def deploy(self):
234 super(SimpleRemoteTarget, self).deploy()
235
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600236 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500237 if ssh:
238 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500239
240 def stop(self):
241 self.connection = None
242 self.ip = None
243 self.server_ip = None