blob: 7bbba6016b29ae7a208be31cff2c80eaf8b3e9dc [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
20from oeqa.controllers.testtargetloader import TestTargetLoader
21from abc import ABCMeta, abstractmethod
22
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023class BaseTarget(object, metaclass=ABCMeta):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024
25 supported_image_fstypes = []
26
Brad Bishopd7bf8c12018-02-25 22:55:05 -050027 def __init__(self, d, logger):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028 self.connection = None
29 self.ip = None
30 self.server_ip = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -050031 self.datetime = d.getVar('DATETIME')
32 self.testdir = d.getVar("TEST_LOG_DIR")
33 self.pn = d.getVar("PN")
Brad Bishopd7bf8c12018-02-25 22:55:05 -050034 self.logger = logger
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035
36 @abstractmethod
37 def deploy(self):
38
39 self.sshlog = os.path.join(self.testdir, "ssh_target_log.%s" % self.datetime)
40 sshloglink = os.path.join(self.testdir, "ssh_target_log")
41 if os.path.islink(sshloglink):
42 os.unlink(sshloglink)
43 os.symlink(self.sshlog, sshloglink)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050044 self.logger.info("SSH log file: %s" % self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045
46 @abstractmethod
Patrick Williamsc0f7c042017-02-23 20:41:17 -060047 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048 pass
49
50 @abstractmethod
51 def stop(self):
52 pass
53
54 @classmethod
55 def get_extra_files(self):
56 return None
57
58 @classmethod
59 def match_image_fstype(self, d, image_fstypes=None):
60 if not image_fstypes:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050061 image_fstypes = d.getVar('IMAGE_FSTYPES').split(' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062 possible_image_fstypes = [fstype for fstype in self.supported_image_fstypes if fstype in image_fstypes]
63 if possible_image_fstypes:
64 return possible_image_fstypes[0]
65 else:
66 return None
67
68 def get_image_fstype(self, d):
69 image_fstype = self.match_image_fstype(d)
70 if image_fstype:
71 return image_fstype
72 else:
73 bb.fatal("IMAGE_FSTYPES should contain a Target Controller supported image fstype: %s " % ', '.join(map(str, self.supported_image_fstypes)))
74
75 def restart(self, params=None):
76 self.stop()
77 self.start(params)
78
79 def run(self, cmd, timeout=None):
80 return self.connection.run(cmd, timeout)
81
82 def copy_to(self, localpath, remotepath):
83 return self.connection.copy_to(localpath, remotepath)
84
85 def copy_from(self, remotepath, localpath):
86 return self.connection.copy_from(remotepath, localpath)
87
88
89
90class QemuTarget(BaseTarget):
91
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050092 supported_image_fstypes = ['ext3', 'ext4', 'cpio.gz', 'wic']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093
Brad Bishopd7bf8c12018-02-25 22:55:05 -050094 def __init__(self, d, logger, image_fstype=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095
Brad Bishop316dfdd2018-06-25 12:45:53 -040096 import oe.types
97
Brad Bishopd7bf8c12018-02-25 22:55:05 -050098 super(QemuTarget, self).__init__(d, logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050099
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500100 self.rootfs = ''
101 self.kernel = ''
102 self.image_fstype = ''
103
104 if d.getVar('FIND_ROOTFS') == '1':
105 self.image_fstype = image_fstype or self.get_image_fstype(d)
106 self.rootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), d.getVar("IMAGE_LINK_NAME") + '.' + self.image_fstype)
107 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 -0500108 self.qemulog = os.path.join(self.testdir, "qemu_boot_log.%s" % self.datetime)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500109 dump_target_cmds = d.getVar("testimage_dump_target")
110 dump_host_cmds = d.getVar("testimage_dump_host")
111 dump_dir = d.getVar("TESTIMAGE_DUMP_DIR")
Brad Bishop977dc1a2019-02-06 16:01:43 -0500112 if not dump_dir:
113 dump_dir = os.path.join(d.getVar('LOG_DIR'), 'runtime-hostdump')
114 use_kvm = oe.types.qemu_use_kvm(d.getVar('QEMU_USE_KVM'), d.getVar('TARGET_ARCH'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500115
116 # Log QemuRunner log output to a file
117 import oe.path
118 bb.utils.mkdirhier(self.testdir)
119 self.qemurunnerlog = os.path.join(self.testdir, 'qemurunner_log.%s' % self.datetime)
Andrew Geissler82c905d2020-04-13 13:39:40 -0500120 self.loggerhandler = logging.FileHandler(self.qemurunnerlog)
121 self.loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
122 self.logger.addHandler(self.loggerhandler)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500123 oe.path.symlink(os.path.basename(self.qemurunnerlog), os.path.join(self.testdir, 'qemurunner_log'), force=True)
124
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500125 if d.getVar("DISTRO") == "poky-tiny":
126 self.runner = QemuTinyRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500127 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500128 tmpdir = d.getVar("TMPDIR"),
129 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
130 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131 logfile = self.qemulog,
132 kernel = self.kernel,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500133 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
134 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500136 self.runner = QemuRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500138 tmpdir = d.getVar("TMPDIR"),
139 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
140 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141 logfile = self.qemulog,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500142 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 use_kvm = use_kvm,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 dump_dir = dump_dir,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500145 dump_host_cmds = d.getVar("testimage_dump_host"),
Andrew Geissler82c905d2020-04-13 13:39:40 -0500146 logger = logger,
147 serial_ports = len(d.getVar("SERIAL_CONSOLES").split()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148
149 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
150
151 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600152 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153
154 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
155 if os.path.islink(qemuloglink):
156 os.unlink(qemuloglink)
157 os.symlink(self.qemulog, qemuloglink)
158
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500159 self.logger.info("rootfs file: %s" % self.rootfs)
160 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161 super(QemuTarget, self).deploy()
162
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500163 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
164 if launch_cmd:
Brad Bishopc342db32019-05-15 21:57:59 -0400165 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd, qemuparams=params)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500166 else:
167 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
168
169 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500170 if ssh:
171 self.ip = self.runner.ip
172 self.server_ip = self.runner.server_ip
173 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174 else:
175 self.stop()
176 if os.path.exists(self.qemulog):
177 with open(self.qemulog, 'r') as f:
178 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
Brad Bishop08902b02019-08-20 09:16:51 -0400179 raise RuntimeError("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500180
181 def check(self):
182 return self.runner.is_alive()
183
184 def stop(self):
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500185 try:
186 self.runner.stop()
187 except:
188 pass
Andrew Geissler82c905d2020-04-13 13:39:40 -0500189 self.logger.removeHandler(self.loggerhandler)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500190 self.connection = None
191 self.ip = None
192 self.server_ip = None
193
194 def restart(self, params=None):
195 if self.runner.restart(params):
196 self.ip = self.runner.ip
197 self.server_ip = self.runner.server_ip
198 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
199 else:
Brad Bishop08902b02019-08-20 09:16:51 -0400200 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 -0500201
Brad Bishop977dc1a2019-02-06 16:01:43 -0500202 def run_serial(self, command, timeout=60):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500203 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500204
205
206class SimpleRemoteTarget(BaseTarget):
207
208 def __init__(self, d):
209 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500210 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 -0500211 self.ip = addr.split(":")[0]
212 try:
213 self.port = addr.split(":")[1]
214 except IndexError:
215 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500216 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500217 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500218 if not self.server_ip:
219 try:
220 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
221 except Exception as e:
222 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 -0500223 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224
225 def deploy(self):
226 super(SimpleRemoteTarget, self).deploy()
227
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600228 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500229 if ssh:
230 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231
232 def stop(self):
233 self.connection = None
234 self.ip = None
235 self.server_ip = None