blob: 1868ad32066e53f200930c57ec9213b4bfa19aa7 [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")
Brad Bishop977dc1a2019-02-06 16:01:43 -0500110 if not dump_dir:
111 dump_dir = os.path.join(d.getVar('LOG_DIR'), 'runtime-hostdump')
112 use_kvm = oe.types.qemu_use_kvm(d.getVar('QEMU_USE_KVM'), d.getVar('TARGET_ARCH'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500113
114 # Log QemuRunner log output to a file
115 import oe.path
116 bb.utils.mkdirhier(self.testdir)
117 self.qemurunnerlog = os.path.join(self.testdir, 'qemurunner_log.%s' % self.datetime)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500118 loggerhandler = logging.FileHandler(self.qemurunnerlog)
119 loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500120 self.logger.addHandler(loggerhandler)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121 oe.path.symlink(os.path.basename(self.qemurunnerlog), os.path.join(self.testdir, 'qemurunner_log'), force=True)
122
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500123 if d.getVar("DISTRO") == "poky-tiny":
124 self.runner = QemuTinyRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500126 tmpdir = d.getVar("TMPDIR"),
127 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
128 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 logfile = self.qemulog,
130 kernel = self.kernel,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500131 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
132 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500133 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500134 self.runner = QemuRunner(machine=d.getVar("MACHINE"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135 rootfs=self.rootfs,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500136 tmpdir = d.getVar("TMPDIR"),
137 deploy_dir_image = d.getVar("DEPLOY_DIR_IMAGE"),
138 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139 logfile = self.qemulog,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500140 boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600141 use_kvm = use_kvm,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142 dump_dir = dump_dir,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500143 dump_host_cmds = d.getVar("testimage_dump_host"),
144 logger = logger)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145
146 self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
147
148 def deploy(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600149 bb.utils.mkdirhier(self.testdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
151 qemuloglink = os.path.join(self.testdir, "qemu_boot_log")
152 if os.path.islink(qemuloglink):
153 os.unlink(qemuloglink)
154 os.symlink(self.qemulog, qemuloglink)
155
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500156 self.logger.info("rootfs file: %s" % self.rootfs)
157 self.logger.info("Qemu log file: %s" % self.qemulog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500158 super(QemuTarget, self).deploy()
159
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500160 def start(self, params=None, ssh=True, extra_bootparams='', runqemuparams='', launch_cmd='', discard_writes=True):
161 if launch_cmd:
162 start = self.runner.launch(get_ip=ssh, launch_cmd=launch_cmd)
163 else:
164 start = self.runner.start(params, get_ip=ssh, extra_bootparams=extra_bootparams, runqemuparams=runqemuparams, discard_writes=discard_writes)
165
166 if start:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500167 if ssh:
168 self.ip = self.runner.ip
169 self.server_ip = self.runner.server_ip
170 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500171 else:
172 self.stop()
173 if os.path.exists(self.qemulog):
174 with open(self.qemulog, 'r') as f:
175 bb.error("Qemu log output from %s:\n%s" % (self.qemulog, f.read()))
176 raise bb.build.FuncFailed("%s - FAILED to start qemu - check the task log and the boot log" % self.pn)
177
178 def check(self):
179 return self.runner.is_alive()
180
181 def stop(self):
182 self.runner.stop()
183 self.connection = None
184 self.ip = None
185 self.server_ip = None
186
187 def restart(self, params=None):
188 if self.runner.restart(params):
189 self.ip = self.runner.ip
190 self.server_ip = self.runner.server_ip
191 self.connection = SSHControl(ip=self.ip, logfile=self.sshlog)
192 else:
193 raise bb.build.FuncFailed("%s - FAILED to re-start qemu - check the task log and the boot log" % self.pn)
194
Brad Bishop977dc1a2019-02-06 16:01:43 -0500195 def run_serial(self, command, timeout=60):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500196 return self.runner.run_serial(command, timeout=timeout)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500197
198
199class SimpleRemoteTarget(BaseTarget):
200
201 def __init__(self, d):
202 super(SimpleRemoteTarget, self).__init__(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500203 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 -0500204 self.ip = addr.split(":")[0]
205 try:
206 self.port = addr.split(":")[1]
207 except IndexError:
208 self.port = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500209 self.logger.info("Target IP: %s" % self.ip)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500210 self.server_ip = d.getVar("TEST_SERVER_IP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500211 if not self.server_ip:
212 try:
213 self.server_ip = subprocess.check_output(['ip', 'route', 'get', self.ip ]).split("\n")[0].split()[-1]
214 except Exception as e:
215 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 -0500216 self.logger.info("Server IP: %s" % self.server_ip)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217
218 def deploy(self):
219 super(SimpleRemoteTarget, self).deploy()
220
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600221 def start(self, params=None, ssh=True, extra_bootparams=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500222 if ssh:
223 self.connection = SSHControl(self.ip, logfile=self.sshlog, port=self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224
225 def stop(self):
226 self.connection = None
227 self.ip = None
228 self.server_ip = None