blob: 12057f855aedfe27127c8c17f45d162fe4b8ef8f [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")),
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500134 tmpfsdir = d.getVar("RUNQEMU_TMPFS_DIR"),
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500135 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500137 self.runner = QemuRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500139 tmpdir = d.getVar("TMPDIR"),
140 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
141 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142 logfile = self.qemulog,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500143 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600144 use_kvm = use_kvm,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 dump_dir = dump_dir,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500146 dump_host_cmds = d.getVar("testimage_dump_host"),
Andrew Geissler82c905d2020-04-13 13:39:40 -0500147 logger = logger,
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500148 tmpfsdir = d.getVar("RUNQEMU_TMPFS_DIR"),
Andrew Geissler82c905d2020-04-13 13:39:40 -0500149 serial_ports = len(d.getVar("SERIAL_CONSOLES").split()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
151 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
152
153 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600154 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500155
156 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
157 if os.path.islink(qemuloglink):
158 os.unlink(qemuloglink)
159 os.symlink(self.qemulog, qemuloglink)
160
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500161 self.logger.info("rootfs file: %s" % self.rootfs)
162 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163 super(QemuTarget, self).deploy()
164
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500165 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
166 if launch_cmd:
Brad Bishopc342db32019-05-15 21:57:59 -0400167 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd, qemuparams=params)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500168 else:
169 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
170
171 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500172 if ssh:
173 self.ip = self.runner.ip
174 self.server_ip = self.runner.server_ip
175 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176 else:
177 self.stop()
178 if os.path.exists(self.qemulog):
179 with open(self.qemulog, 'r') as f:
180 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
Brad Bishop08902b02019-08-20 09:16:51 -0400181 raise RuntimeError("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500182
183 def check(self):
184 return self.runner.is_alive()
185
186 def stop(self):
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500187 try:
188 self.runner.stop()
189 except:
190 pass
Andrew Geissler82c905d2020-04-13 13:39:40 -0500191 self.logger.removeHandler(self.loggerhandler)
Andrew Geissler475cb722020-07-10 16:00:51 -0500192 self.loggerhandler.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 self.connection = None
194 self.ip = None
195 self.server_ip = None
196
197 def restart(self, params=None):
198 if self.runner.restart(params):
199 self.ip = self.runner.ip
200 self.server_ip = self.runner.server_ip
201 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
202 else:
Brad Bishop08902b02019-08-20 09:16:51 -0400203 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 -0500204
Brad Bishop977dc1a2019-02-06 16:01:43 -0500205 def run_serial(self, command, timeout=60):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500206 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500207
208
209class SimpleRemoteTarget(BaseTarget):
210
211 def __init__(self, d):
212 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500213 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 -0500214 self.ip = addr.split(":")[0]
215 try:
216 self.port = addr.split(":")[1]
217 except IndexError:
218 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500219 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500220 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500221 if not self.server_ip:
222 try:
223 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
224 except Exception as e:
225 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 -0500226 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500227
228 def deploy(self):
229 super(SimpleRemoteTarget, self).deploy()
230
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600231 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500232 if ssh:
233 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500234
235 def stop(self):
236 self.connection = None
237 self.ip = None
238 self.server_ip = None