Wait for installer exit and live shell before followup probes
This commit is contained in:
@@ -505,6 +505,17 @@ class Console:
|
||||
re.escape(token.encode()) + rb':INSTALL_EXIT:[0-9]+\x1f')
|
||||
return self.expect(pattern, timeout, failure_pattern=failure)
|
||||
|
||||
def finish_installer(self, token, timeout=30):
|
||||
# Completion text can arrive before the process exits and readline
|
||||
# resumes. Input sent during that gap can be discarded by the TTY.
|
||||
deadline = time.monotonic() + timeout
|
||||
returned = self.expect(rb'\x1e' + re.escape(token.encode()) +
|
||||
rb':INSTALL_EXIT:([0-9]+)\x1f', timeout)
|
||||
status = int(returned.group(1))
|
||||
if status:
|
||||
raise SmokeError(f'Installer returned status {status} after completion')
|
||||
self.expect(rb'hydra-live[^\r\n]*[#$] ', max(0, deadline - time.monotonic()))
|
||||
|
||||
def command(self, command, timeout=60):
|
||||
token = secrets.token_hex(12)
|
||||
self.buffer = b''
|
||||
@@ -818,6 +829,7 @@ def main(argv=None):
|
||||
console.send(password + '\n')
|
||||
console.expect_installer(rb'Installation completed\. Diagnostic log: [^\r\n]+',
|
||||
args.install_timeout, installer_token)
|
||||
console.finish_installer(installer_token)
|
||||
checkpoint('real_installer', b'Installer completed via guest controlling TTY')
|
||||
console.command("sudo -n mkdir -p /mnt/hydra-validation && sudo -n mount /dev/vda2 /mnt/hydra-validation && printf %s " +
|
||||
shlex.quote(sentinel) + " | sudo -n tee /mnt/hydra-validation/var/lib/hydra-acceptance-sentinel >/dev/null && sudo -n umount /mnt/hydra-validation", 60)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import socket
|
||||
import select
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
@@ -152,6 +153,35 @@ class SmokeTests(unittest.TestCase):
|
||||
console.expect_installer(rb'Repeat password: ', 0.05, 'testtoken')
|
||||
self.assertNotIn('test-secret', str(caught.exception))
|
||||
|
||||
def test_installer_followup_waits_for_exit_and_new_shell_prompt(self):
|
||||
console, guest = self.installer_console()
|
||||
premature = []
|
||||
def respond():
|
||||
guest.sendall(b'Installation completed. Diagnostic log: /run/installer.log\r\n')
|
||||
premature.append(bool(select.select([guest], [], [], 0.05)[0]))
|
||||
guest.sendall(b'\x1etesttoken:INSTALL_EXIT:0\x1f')
|
||||
premature.append(bool(select.select([guest], [], [], 0.05)[0]))
|
||||
guest.sendall(b'\x1b[?2004hhydra-live@hydra-os ~ $ ')
|
||||
data = b''
|
||||
while not data.endswith(b'\n'):
|
||||
data += guest.recv(65536)
|
||||
result = subprocess.run(['/bin/sh', '-c', data.decode()], capture_output=True)
|
||||
guest.sendall(result.stdout)
|
||||
worker = threading.Thread(target=respond, daemon=True)
|
||||
worker.start()
|
||||
console.expect_installer(rb'Installation completed\. Diagnostic log: [^\r\n]+',
|
||||
1, 'testtoken')
|
||||
console.finish_installer('testtoken', timeout=1)
|
||||
self.assertEqual(console.command('printf ready', timeout=1), b'ready')
|
||||
worker.join(timeout=1)
|
||||
self.assertEqual(premature, [False, False], 'command reached installer before shell was ready')
|
||||
|
||||
def test_installer_completion_does_not_override_nonzero_return(self):
|
||||
console, guest = self.installer_console()
|
||||
guest.sendall(b'\x1etesttoken:INSTALL_EXIT:1\x1fhydra-live@hydra-os ~ $ ')
|
||||
with self.assertRaisesRegex(self.mod.SmokeError, 'Installer.*status 1'):
|
||||
console.finish_installer('testtoken', timeout=0.05)
|
||||
|
||||
def test_frame_real_shell_roundtrip_does_not_accept_sentinel_in_echo(self):
|
||||
one, two = socket.socketpair()
|
||||
self.addCleanup(one.close)
|
||||
|
||||
Reference in New Issue
Block a user