blob: f63936c3ec4e97aa06c8379495fa28ea559cf5ea [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 Bishopd7bf8c12018-02-25 22:55:05 -050094 super(QemuTarget, self).__init__(d, logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095
Brad Bishop6e60e8b2018-02-01 10:27:11 -050096 self.rootfs = ''
97 self.kernel = ''
98 self.image_fstype = ''
99
100 if d.getVar('FIND_ROOTFS') == '1':
101 self.image_fstype = image_fstype or self.get_image_fstype(d)
102 self.rootfs = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), d.getVar("IMAGE_LINK_NAME") + '.' + self.image_fstype)
103 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 -0500104 self.qemulog = os.path.join(self.testdir, "qemu_boot_log.%s" % self.datetime)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500105 dump_target_cmds = d.getVar("testimage_dump_target")
106 dump_host_cmds = d.getVar("testimage_dump_host")
107 dump_dir = d.getVar("TESTIMAGE_DUMP_DIR")
108 qemu_use_kvm = d.getVar("QEMU_USE_KVM")
109 if qemu_use_kvm and \
110 (qemu_use_kvm == "True" and "x86" in d.getVar("MACHINE") or \
111 d.getVar("MACHINE") in qemu_use_kvm.split()):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600112 use_kvm = True
113 else:
114 use_kvm = False
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:
164 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd)
165 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()))
178 raise bb.build.FuncFailed("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
179
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:
195 raise bb.build.FuncFailed("%s - FAILED to re-start qemu - check the task log and the boot log" % self.pn)
196
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500197 def run_serial(self, command, timeout=5):
198 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