From: Uladzimir Bely <ubely@ilbers.de>
To: isar-users@googlegroups.com
Subject: [PATCH 7/8] cibuilder.py: enable output from remote scripts
Date: Fri, 18 Aug 2023 09:07:05 +0200 [thread overview]
Message-ID: <20230818070706.27913-8-ubely@ilbers.de> (raw)
In-Reply-To: <20230818070706.27913-1-ubely@ilbers.de>
With this patch, `ssh_start()` and `vm_start()` functions become able
to return stdout and stderr.
Function `remote_send_file()` can be used to deliver files on remote
machine.
Function `remote_run()` is allowed to just run remote commands and it
doesn't fail now when non-zero returncode. This allows to handle any
returncode in a testcase, e.g.:
```
def test_custom(self):
self.init()
self.vm_start('arm64', 'bullseye', image='isar-image-ci')
ret = self.remote_run(cmd='<custom_command>`)
if ret[0] != 0:
self.log.error(ret[2])
self.fail("Failed to run <custom_command>")
```
Signed-off-by: Uladzimir Bely <ubely@ilbers.de>
---
testsuite/cibuilder.py | 128 +++++++++++++++++++++++++----------------
1 file changed, 80 insertions(+), 48 deletions(-)
diff --git a/testsuite/cibuilder.py b/testsuite/cibuilder.py
index 73c8ee2c..12f0e193 100755
--- a/testsuite/cibuilder.py
+++ b/testsuite/cibuilder.py
@@ -243,16 +243,25 @@ class CIBuilder(Test):
'-p %s -o IdentityFile=%s %s@%s ' \
% (port, priv_key, user, host)
- self.log.debug('Connect command:\n' + cmd_prefix)
-
return cmd_prefix
def exec_cmd(self, cmd, cmd_prefix):
- rc = subprocess.call('exec ' + str(cmd_prefix) + ' "' + str(cmd) + '"', shell=True,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- return rc
+ proc = subprocess.run('exec ' + str(cmd_prefix) + ' "' + str(cmd) + '"', shell=True,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ return proc.returncode, proc.stdout, proc.stderr
+
+
+ def remote_send_file(self, src, dest, mode):
+ priv_key = self.prepare_priv_key()
+ cmd_prefix = self.get_ssh_cmd_prefix(self.ssh_user, self.ssh_host, self.ssh_port, priv_key)
+
+ proc = subprocess.run('cat %s | %s install -m %s /dev/stdin %s' %
+ (src, cmd_prefix, mode, dest), shell=True,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ return proc.returncode, proc.stdout, proc.stderr
def run_script(self, script, cmd_prefix):
script_dir = self.params.get('test_script_dir',
@@ -260,44 +269,45 @@ class CIBuilder(Test):
script_path = script_dir + script.split()[0]
script_args = ' '.join(script.split()[1:])
- self.log.debug("script_path: '%s'" % (script_path))
- self.log.debug("script args: '%s'" % (script_args))
-
if not os.path.exists(script_path):
self.log.error('Script not found: ' + script_path)
- return 2
+ return (2, '', 'Script not found: ' + script_path)
+
+ rc, stdout, stderr = self.remote_send_file(script_path, "./ci.sh", "755")
+
+ if rc != 0:
+ self.log.error('Failed to deploy the script on target')
+ return (rc, stdout, stderr)
- # Copy the script to the target
- rc = subprocess.call('cat %s | %s install -m 755 /dev/stdin ./ci.sh' % (script_path, cmd_prefix), shell=True,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(1)
- # Run the script remotely with the arguments
- if rc == 0:
- rc = subprocess.call('%s ./ci.sh %s' % (cmd_prefix, script_args), shell=True,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- return rc
+ proc = subprocess.run('%s ./ci.sh %s' % (cmd_prefix, script_args), shell=True,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ return (proc.returncode, proc.stdout, proc.stderr)
def wait_connection(self, cmd_prefix, timeout):
- self.log.debug('Waiting for SSH server ready...')
+ self.log.info('Waiting for SSH server ready...')
rc = None
+ stdout = ""
+ stderr = ""
+
goodcnt = 0
# Use 3 good SSH ping attempts to consider SSH connection is stable
while time.time() < timeout and goodcnt < 3:
goodcnt += 1
- rc = self.exec_cmd('/bin/true', cmd_prefix)
+ rc, stdout, stderr = self.exec_cmd('/bin/true', cmd_prefix)
time.sleep(1)
if rc != 0:
goodcnt = 0
time_left = timeout - time.time()
- self.log.debug('SSH ping result: %d, left: %.fs' % (rc, time_left))
+ self.log.info('SSH ping result: %d, left: %.fs' % (rc, time_left))
- return rc
+ return rc, stdout, stderr
def prepare_priv_key(self):
@@ -310,45 +320,57 @@ class CIBuilder(Test):
return priv_key
- def remote_run(self, user, host, port, cmd, script, timeout=0):
+ def remote_run(self, cmd=None, script=None, timeout=0):
+ if cmd:
+ self.log.info('Remote command is `%s`' % (cmd))
+ if script:
+ self.log.info('Remote script is `%s`' % (script))
+
priv_key = self.prepare_priv_key()
- cmd_prefix = self.get_ssh_cmd_prefix(user, host, port, priv_key)
+ cmd_prefix = self.get_ssh_cmd_prefix(self.ssh_user, self.ssh_host, self.ssh_port, priv_key)
- rc = 0
- if timeout:
- rc = self.wait_connection(cmd_prefix, timeout)
+ rc = None
+ stdout = ""
+ stderr = ""
+
+ if timeout != 0:
+ rc, stdout, stderr = self.wait_connection(cmd_prefix, timeout)
- if rc == 0:
+ if rc == 0 or timeout == 0:
if cmd is not None:
- rc = self.exec_cmd(cmd, cmd_prefix)
- self.log.debug('`' + cmd + '` returned ' + str(rc))
+ rc, stdout, stderr = self.exec_cmd(cmd, cmd_prefix)
+ self.log.info('`' + cmd + '` returned ' + str(rc))
elif script is not None:
- rc = self.run_script(script, cmd_prefix)
- self.log.debug('`' + script + '` returned ' + str(rc))
- else:
- return None
+ rc, stdout, stderr = self.run_script(script, cmd_prefix)
+ self.log.info('`' + script + '` returned ' + str(rc))
- return rc
+ return rc, stdout, stderr
def ssh_start(self, user='ci', host='localhost', port=22,
cmd=None, script=None):
self.log.info('===================================================')
self.log.info('Running Isar SSH test for `%s@%s:%s`' % (user, host, port))
- self.log.info('Remote command is `%s`' % (cmd))
- self.log.info('Remote script is `%s`' % (script))
self.log.info('Isar build folder is: ' + self.build_dir)
self.log.info('===================================================')
self.check_init()
+ self.ssh_user = user
+ self.ssh_host = host
+ self.ssh_port = port
+
+ priv_key = self.prepare_priv_key()
+ cmd_prefix = self.get_ssh_cmd_prefix(self.ssh_user, self.ssh_host, self.ssh_port, priv_key)
+ self.log.info('Connect command:\n' + cmd_prefix)
+
if cmd is not None or script is not None:
- rc = self.remote_run(user, host, port, cmd, script)
+ rc, stdout, stderr = self.remote_run(cmd, script)
if rc != 0:
self.fail('Failed with rc=%s' % rc)
- return
+ return stdout, stderr
self.fail('No command to run specified')
@@ -378,7 +400,7 @@ class CIBuilder(Test):
p1 = subprocess.Popen('exec ' + ' '.join(cmdline), shell=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
- self.log.debug("Started VM with pid %s" % (p1.pid))
+ self.log.info("Started VM with pid %s" % (p1.pid))
return p1, cmdline, boot_log
@@ -401,7 +423,7 @@ class CIBuilder(Test):
time.sleep(0.01)
data = os.read(fd, 1024)
if login_prompt in data:
- self.log.debug('Got login prompt')
+ self.log.info('Got login prompt')
return 0
if fd == p1.stderr.fileno():
app_log.error(p1.stderr.readline().rstrip())
@@ -456,7 +478,7 @@ class CIBuilder(Test):
del(self.vm_dict[vm])
self.vm_dump_dict(vm)
- self.log.debug("Stopped VM with pid %s" % (pid))
+ self.log.info("Stopped VM with pid %s" % (pid))
def vm_start(self, arch='amd64', distro='buster',
@@ -485,6 +507,9 @@ class CIBuilder(Test):
run_qemu = True
+ stdout = ""
+ stderr = ""
+
if vm in self.vm_dict:
pid, cmdline, boot_log = self.vm_dict[vm]
@@ -492,11 +517,11 @@ class CIBuilder(Test):
proc = subprocess.run("ps -o cmd= %d" % (pid), shell=True, text=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if cmdline[0] in proc.stdout:
- self.log.debug("Found '%s' process with pid '%d', use it" % (cmdline[0], pid))
+ self.log.info("Found '%s' process with pid '%d', use it" % (cmdline[0], pid))
run_qemu = False
if run_qemu:
- self.log.debug("No qemu-system process for `%s` found, run new VM" % (vm))
+ self.log.info("No qemu-system process for `%s` found, run new VM" % (vm))
p1, cmdline, boot_log = self.vm_turn_on(arch, distro, image, enforce_pcbios)
self.vm_dict[vm] = p1.pid, cmdline, boot_log
@@ -508,15 +533,20 @@ class CIBuilder(Test):
self.fail('Failed to boot qemu machine')
if cmd is not None or script is not None:
- user='ci'
- host='localhost'
- port = 22
+ self.ssh_user='ci'
+ self.ssh_host='localhost'
+ self.ssh_port = 22
for arg in cmdline:
match = re.match(r".*hostfwd=tcp::(\d*).*", arg)
if match:
- port = match.group(1)
+ self.ssh_port = match.group(1)
break
- rc = self.remote_run(user, host, port, cmd, script, timeout)
+
+ priv_key = self.prepare_priv_key()
+ cmd_prefix = self.get_ssh_cmd_prefix(self.ssh_user, self.ssh_host, self.ssh_port, priv_key)
+ self.log.info('Connect command:\n' + cmd_prefix)
+
+ rc, stdout, stderr = self.remote_run(cmd, script, timeout)
if rc != 0:
if stop_vm:
self.vm_turn_off(vm)
@@ -531,3 +561,5 @@ class CIBuilder(Test):
if stop_vm:
self.vm_turn_off(vm)
+
+ return stdout, stderr
--
2.20.1
next prev parent reply other threads:[~2023-08-18 7:07 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-18 7:06 [PATCH 0/8] Testsuite improvements for SSH-based tests Uladzimir Bely
2023-08-18 7:06 ` [PATCH 1/8] cibuilder.py: Support custom arguments passing to CI scripts Uladzimir Bely
2023-08-18 7:07 ` [PATCH 2/8] meta-isar: Add more extra space to qemu ext4 images Uladzimir Bely
2023-08-18 7:07 ` [PATCH 3/8] cibuilder.py: Split vm_start function to smaller subfunctions Uladzimir Bely
2023-08-18 7:07 ` [PATCH 4/8] cibuilder.py: Simplify remote_run command Uladzimir Bely
2023-08-18 7:07 ` [PATCH 5/8] cibuilder.py: Reuse the same qemu machine in ssh-based tests Uladzimir Bely
2023-08-18 7:07 ` [PATCH 6/8] citest.py: Adapt tests to qemu reuse Uladzimir Bely
2023-08-18 7:07 ` Uladzimir Bely [this message]
2023-08-18 7:07 ` [PATCH 8/8] testsuite: Switch to remote scripts with arguments Uladzimir Bely
2023-08-24 15:34 ` [PATCH 0/8] Testsuite improvements for SSH-based tests Uladzimir Bely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230818070706.27913-8-ubely@ilbers.de \
--to=ubely@ilbers.de \
--cc=isar-users@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox