blob: 59a9c35a096035e92c82d9dcc2a90e99c4f56dbc [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Copyright (C) 2013 Intel Corporation
2#
3# Released under the MIT license (see COPYING.MIT)
4
5# This module is used by testimage.bbclass for setting up and controlling a target machine.
6
7import os
8import shutil
9import subprocess
10import bb
11import traceback
12import sys
13import logging
14from oeqa.utils.sshcontrol import SSHControl
15from oeqa.utils.qemurunner import QemuRunner
16from oeqa.utils.qemutinyrunner import QemuTinyRunner
17from oeqa.utils.dump import TargetDumper
18from oeqa.controllers.testtargetloader import TestTargetLoader
19from abc import ABCMeta, abstractmethod
20
Patrick Williamsc0f7c042017-02-23 20:41:17 -060021class BaseTarget(object, metaclass=ABCMeta):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022
23 supported_image_fstypes = []
24
Brad Bishopd7bf8c12018-02-25 22:55:05 -050025 def __init__(self, d, logger):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026 self.connection = None
27 self.ip = None
28 self.server_ip = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -050029 self.datetime = d.getVar('DATETIME')
30 self.testdir = d.getVar("TEST_LOG_DIR")
31 self.pn = d.getVar("PN")
Brad Bishopd7bf8c12018-02-25 22:55:05 -050032 self.logger = logger
Patrick Williamsc124f4f2015-09-15 14:41:29 -050033
34 @abstractmethod
35 def deploy(self):
36
37 self.sshlog = os.path.join(self.testdir, "ssh_target_log.%s" % self.datetime)
38 sshloglink = os.path.join(self.testdir, "ssh_target_log")
39 if os.path.islink(sshloglink):
40 os.unlink(sshloglink)
41 os.symlink(self.sshlog, sshloglink)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050042 self.logger.info("SSH log file: %s" % self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050043
44 @abstractmethod
Patrick Williamsc0f7c042017-02-23 20:41:17 -060045 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 pass
47
48 @abstractmethod
49 def stop(self):
50 pass
51
52 @classmethod
53 def get_extra_files(self):
54 return None
55
56 @classmethod
57 def match_image_fstype(self, d, image_fstypes=None):
58 if not image_fstypes:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050059 image_fstypes = d.getVar('IMAGE_FSTYPES').split(' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060 possible_image_fstypes = [fstype for fstype in self.supported_image_fstypes if fstype in image_fstypes]
61 if possible_image_fstypes:
62 return possible_image_fstypes[0]
63 else:
64 return None
65
66 def get_image_fstype(self, d):
67 image_fstype = self.match_image_fstype(d)
68 if image_fstype:
69 return image_fstype
70 else:
71 bb.fatal("IMAGE_FSTYPES should contain a Target Controller supported image fstype: %s " % ', '.join(map(str, self.supported_image_fstypes)))
72
73 def restart(self, params=None):
74 self.stop()
75 self.start(params)
76
77 def run(self, cmd, timeout=None):
78 return self.connection.run(cmd, timeout)
79
80 def copy_to(self, localpath, remotepath):
81 return self.connection.copy_to(localpath, remotepath)
82
83 def copy_from(self, remotepath, localpath):
84 return self.connection.copy_from(remotepath, localpath)
85
86
87
88class QemuTarget(BaseTarget):
89
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050090 supported_image_fstypes = ['ext3', 'ext4', 'cpio.gz', 'wic']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091
Brad Bishopd7bf8c12018-02-25 22:55:05 -050092 def __init__(self, d, logger, image_fstype=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093
Brad Bishop316dfdd2018-06-25 12:45:53 -040094 import oe.types
95
Brad Bishopd7bf8c12018-02-25 22:55:05 -050096 super(QemuTarget, self).__init__(d, logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097
Brad Bishop6e60e8b2018-02-01 10:27:11 -050098 self.rootfs = ''
99 self.kernel = ''
100 self.image_fstype = ''
101
102 if d.getVar('FIND_ROOTFS') == '1':
103 self.image_fstype = image_fstype or self.get_image_fstype(d)
104 self.rootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), d.getVar("IMAGE_LINK_NAME") + '.' + self.image_fstype)
105 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 -0500106 self.qemulog = os.path.join(self.testdir, "qemu_boot_log.%s" % self.datetime)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500107 dump_target_cmds = d.getVar("testimage_dump_target")
108 dump_host_cmds = d.getVar("testimage_dump_host")
109 dump_dir = d.getVar("TESTIMAGE_DUMP_DIR")
110 qemu_use_kvm = d.getVar("QEMU_USE_KVM")
111 if qemu_use_kvm and \
Brad Bishop316dfdd2018-06-25 12:45:53 -0400112 (oe.types.boolean(qemu_use_kvm) and "x86" in d.getVar("MACHINE") or \
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500113 d.getVar("MACHINE") in qemu_use_kvm.split()):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600114 use_kvm = True
115 else:
116 use_kvm = False
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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500122 loggerhandler = logging.FileHandler(self.qemurunnerlog)
123 loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500124 self.logger.addHandler(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")),
136 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500138 self.runner = QemuRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500140 tmpdir = d.getVar("TMPDIR"),
141 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
142 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500143 logfile = self.qemulog,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500144 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600145 use_kvm = use_kvm,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500146 dump_dir = dump_dir,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500147 dump_host_cmds = d.getVar("testimage_dump_host"),
148 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149
150 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
151
152 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600153 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500154
155 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
156 if os.path.islink(qemuloglink):
157 os.unlink(qemuloglink)
158 os.symlink(self.qemulog, qemuloglink)
159
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500160 self.logger.info("rootfs file: %s" % self.rootfs)
161 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162 super(QemuTarget, self).deploy()
163
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500164 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
165 if launch_cmd:
166 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd)
167 else:
168 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
169
170 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500171 if ssh:
172 self.ip = self.runner.ip
173 self.server_ip = self.runner.server_ip
174 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500175 else:
176 self.stop()
177 if os.path.exists(self.qemulog):
178 with open(self.qemulog, 'r') as f:
179 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
180 raise bb.build.FuncFailed("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
181
182 def check(self):
183 return self.runner.is_alive()
184
185 def stop(self):
186 self.runner.stop()
187 self.connection = None
188 self.ip = None
189 self.server_ip = None
190
191 def restart(self, params=None):
192 if self.runner.restart(params):
193 self.ip = self.runner.ip
194 self.server_ip = self.runner.server_ip
195 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
196 else:
197 raise bb.build.FuncFailed("%s - FAILED to re-start qemu - check the task log and the boot log" % self.pn)
198
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500199 def run_serial(self, command, timeout=5):
200 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500201
202
203class SimpleRemoteTarget(BaseTarget):
204
205 def __init__(self, d):
206 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500207 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 -0500208 self.ip = addr.split(":")[0]
209 try:
210 self.port = addr.split(":")[1]
211 except IndexError:
212 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500213 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500214 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500215 if not self.server_ip:
216 try:
217 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
218 except Exception as e:
219 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 -0500220 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500221
222 def deploy(self):
223 super(SimpleRemoteTarget, self).deploy()
224
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600225 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500226 if ssh:
227 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500228
229 def stop(self):
230 self.connection = None
231 self.ip = None
232 self.server_ip = None