blob: 1445e3ecfb9b44362c75cfe7976148330f68a65a [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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120 loggerhandler = logging.FileHandler(self.qemurunnerlog)
121 loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500122 self.logger.addHandler(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"),
146 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147
148 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
149
150 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600151 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152
153 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
154 if os.path.islink(qemuloglink):
155 os.unlink(qemuloglink)
156 os.symlink(self.qemulog, qemuloglink)
157
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500158 self.logger.info("rootfs file: %s" % self.rootfs)
159 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500160 super(QemuTarget, self).deploy()
161
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500162 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
163 if launch_cmd:
Brad Bishopc342db32019-05-15 21:57:59 -0400164 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd, qemuparams=params)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500165 else:
166 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
167
168 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500169 if ssh:
170 self.ip = self.runner.ip
171 self.server_ip = self.runner.server_ip
172 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173 else:
174 self.stop()
175 if os.path.exists(self.qemulog):
176 with open(self.qemulog, 'r') as f:
177 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
Brad Bishop08902b02019-08-20 09:16:51 -0400178 raise RuntimeError("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179
180 def check(self):
181 return self.runner.is_alive()
182
183 def stop(self):
184 self.runner.stop()
185 self.connection = None
186 self.ip = None
187 self.server_ip = None
188
189 def restart(self, params=None):
190 if self.runner.restart(params):
191 self.ip = self.runner.ip
192 self.server_ip = self.runner.server_ip
193 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
194 else:
Brad Bishop08902b02019-08-20 09:16:51 -0400195 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 -0500196
Brad Bishop977dc1a2019-02-06 16:01:43 -0500197 def run_serial(self, command, timeout=60):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500198 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500199
200
201class SimpleRemoteTarget(BaseTarget):
202
203 def __init__(self, d):
204 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500205 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 -0500206 self.ip = addr.split(":")[0]
207 try:
208 self.port = addr.split(":")[1]
209 except IndexError:
210 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500211 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500212 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500213 if not self.server_ip:
214 try:
215 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
216 except Exception as e:
217 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 -0500218 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500219
220 def deploy(self):
221 super(SimpleRemoteTarget, self).deploy()
222
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600223 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500224 if ssh:
225 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500226
227 def stop(self):
228 self.connection = None
229 self.ip = None
230 self.server_ip = None