Merge ~sylvain-pineau/checkbox-ng:classic-session-autorestart into checkbox-ng:master

Proposed by Sylvain Pineau
Status: Merged
Approved by: Sylvain Pineau
Approved revision: c76786e789a1869b1e02ff3af88cbdd031fa90c2
Merge reported by: Sylvain Pineau
Merged at revision: c76786e789a1869b1e02ff3af88cbdd031fa90c2
Proposed branch: ~sylvain-pineau/checkbox-ng:classic-session-autorestart
Merge into: checkbox-ng:master
Diff against target: 143 lines (+45/-14)
3 files modified
plainbox/impl/session/assistant.py (+8/-1)
plainbox/impl/session/remote_assistant.py (+8/-3)
plainbox/impl/session/restart.py (+29/-10)
Reviewer Review Type Date Requested Status
Devices Certification Bot Needs Fixing
Sylvain Pineau (community) Approve
Review via email: mp+381232@code.launchpad.net

Description of the change

This patchset allows checkbox classic snaps to run test plans like com.canonical.certification::warm-boot-stress-test w/o using remote (and even if a slave daemon is running in the background).

This method is not the best as upon resume (on a Ubuntu server image) the tester won't get any information about the progress of the stress tests and won't get any UI to interact with the running session.

The best solution is to switch to checkbox remote and use an external launcher to drive the tests from another machine.

But still, checkbox classic snaps were missing the ability to run such test plans. To workaround the lack of session feedback I've tweaked the systemd unit to redirect all I/O to /dev/console, example: https://i.imgur.com/T3jf7Ew.jpg

The main fix below is a change in the allowed call sequence from session assistant as the logic to determine the best restart strategy now requires knowledge about the kind of session to resume (local vs remote basically).

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Tested using checkbox-snappy-classic with this launcher (remotely and not but still with the remote service enabled):

[launcher]
app_id = com.canonical.certification:checkbox-test
launcher_version = 1
stock_reports = text, submission_files

[test plan]
unit = com.canonical.certification::warm-boot-stress-test
forced = yes

[test selection]
forced = no

[ui]
output = hide-resource-and-attachment

[environment]
STRESS_BOOT_ITERATIONS=2
STRESS_BOOT_WAIT_DELAY=10
STRESS_BOOT_WAKEUP_DELAY=15

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Local test command line:

ubuntu@ubuntu:~$ STRESS_BOOT_ITERATIONS=2 STRESS_BOOT_WAIT_DELAY=10 STRESS_BOOT_WAKEUP_DELAY=15 checkbox-snappy-classic.checkbox-cli launcher ./mylauncher

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

self-approved

review: Approve
Revision history for this message
Devices Certification Bot (ce-certification-qa) wrote :

The merge was fine but running tests failed.

[xenial] [12:31:13] starting container
Device project added to xenial-testing
[bionic] [12:31:17] starting container
Device project added to bionic-testing
[xenial] [12:31:24] provisioning container
[bionic] [12:31:32] provisioning container
[bionic] [12:32:51] Unable to provision requirements in container!
[bionic] output: https://paste.ubuntu.com/p/NDp28hq9S9/
[bionic] [12:32:54] Fixing file permissions in source directory
[bionic] Destroying failed container to reclaim resources
[xenial] [12:32:59] Unable to provision requirements in container!
[xenial] output: https://paste.ubuntu.com/p/Rr7fNX8Jcz/
[xenial] [12:33:01] Fixing file permissions in source directory
[xenial] Destroying failed container to reclaim resources

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/plainbox/impl/session/assistant.py b/plainbox/impl/session/assistant.py
2index 90edfaf..6e8921e 100644
3--- a/plainbox/impl/session/assistant.py
4+++ b/plainbox/impl/session/assistant.py
5@@ -253,7 +253,7 @@ class SessionAssistant:
6 """
7 UsageExpectation.of(self).enforce()
8 if self._restart_strategy is None:
9- self._restart_strategy = detect_restart_strategy()
10+ self._restart_strategy = detect_restart_strategy(self)
11 self._restart_cmd_callback = cmd_callback
12 # Prevent second call to this method and to the
13 # use_alternate_restart_strategy() method.
14@@ -524,6 +524,13 @@ class SessionAssistant:
15 self.hand_pick_jobs: "select jobs to run (w/o a test plan)",
16 self.finalize_session: "to finalize session",
17 }
18+ if SA_RESTARTABLE in self._flags:
19+ allowed_calls = UsageExpectation.of(self).allowed_calls
20+ allowed_calls[self.configure_application_restart] = (
21+ "configure automatic restart capability")
22+ allowed_calls[self.use_alternate_restart_strategy] = (
23+ "configure automatic restart capability")
24+
25
26 @raises(KeyError, UnexpectedMethodCall)
27 def resume_session(self, session_id: str,
28diff --git a/plainbox/impl/session/remote_assistant.py b/plainbox/impl/session/remote_assistant.py
29index c93e7df..1307bb1 100644
30--- a/plainbox/impl/session/remote_assistant.py
31+++ b/plainbox/impl/session/remote_assistant.py
32@@ -161,7 +161,6 @@ class RemoteSessionAssistant():
33 _logger.info("Resetting RSA")
34 self._state = Idle
35 self._sa = SessionAssistant('service', api_flags={SA_RESTARTABLE})
36- self._sa.configure_application_restart(self._cmd_callback)
37 self._be = None
38 self._session_id = ""
39 self._jobs_count = 0
40@@ -244,12 +243,15 @@ class RemoteSessionAssistant():
41 _logger.debug("start_session: %r", configuration)
42 session_title = 'checkbox-slave'
43 session_desc = 'checkbox-slave session'
44+ session_type = 'checkbox-slave'
45
46 self._launcher = load_configs()
47 if configuration['launcher']:
48 self._launcher.read_string(configuration['launcher'], False)
49- session_title = self._launcher.session_title
50- session_desc = self._launcher.session_desc
51+ if self._launcher.session_title:
52+ session_title = self._launcher.session_title
53+ if self._launcher.session_desc:
54+ session_desc = self._launcher.session_desc
55
56 self._sa.use_alternate_configuration(self._launcher)
57
58@@ -268,7 +270,10 @@ class RemoteSessionAssistant():
59 self._sa.update_app_blob(json.dumps(
60 {'description': session_desc, }).encode("UTF-8"))
61 self._sa.update_app_blob(json.dumps(
62+ {'type': session_type, }).encode("UTF-8"))
63+ self._sa.update_app_blob(json.dumps(
64 {'launcher': configuration['launcher'], }).encode("UTF-8"))
65+ self._sa.configure_application_restart(self._cmd_callback)
66
67 self._session_id = self._sa.get_session_id()
68 tps = self._sa.get_test_plans()
69diff --git a/plainbox/impl/session/restart.py b/plainbox/impl/session/restart.py
70index 6a33483..bd6a735 100644
71--- a/plainbox/impl/session/restart.py
72+++ b/plainbox/impl/session/restart.py
73@@ -22,6 +22,7 @@
74
75 import abc
76 import errno
77+import json
78 import os
79 import shlex
80 import subprocess
81@@ -149,6 +150,9 @@ class SnappyRestartStrategy(IRestartStrategy):
82 section = 'Service'
83 config.add_section(section)
84 config.set(section, 'Type', 'oneshot')
85+ config.set(section, 'StandardOutput', 'tty')
86+ config.set(section, 'StandardError', 'tty')
87+ config.set(section, 'TTYPath', '/dev/console')
88 if os.getenv('USER'):
89 config.set(section, 'User', os.getenv('USER'))
90
91@@ -229,10 +233,11 @@ class RemoteSnappyRestartStrategy(IRestartStrategy):
92 raise
93
94
95-def detect_restart_strategy() -> IRestartStrategy:
96+def detect_restart_strategy(session=None) -> IRestartStrategy:
97 """
98 Detect the restart strategy for the current environment.
99-
100+ :param session:
101+ The current session object.
102 :returns:
103 A restart strategy object.
104 :raises LookupError:
105@@ -255,16 +260,30 @@ def detect_restart_strategy() -> IRestartStrategy:
106 except subprocess.CalledProcessError:
107 return SnappyRestartStrategy()
108
109- # Classic + remote service enabled
110+ # Classic snaps
111 snap_data = os.getenv('SNAP_DATA')
112+ try:
113+ if session:
114+ app_blob = json.loads(session._context.state.metadata.app_blob.decode('UTF-8'))
115+ session_type = app_blob.get("type")
116+ else:
117+ session_type = None
118+ except AttributeError:
119+ session_type = None
120 if snap_data:
121- try:
122- slave_status = subprocess.check_output(
123- ['snapctl', 'get', 'slave'], universal_newlines=True).rstrip()
124- if slave_status == 'enabled':
125- return RemoteSnappyRestartStrategy()
126- except subprocess.CalledProcessError:
127- pass
128+ # Classic snaps w/ remote service enabled and in use
129+ if session_type == "checkbox-slave":
130+ try:
131+ slave_status = subprocess.check_output(
132+ ['snapctl', 'get', 'slave'],
133+ universal_newlines=True).rstrip()
134+ if slave_status == 'enabled':
135+ return RemoteSnappyRestartStrategy()
136+ except subprocess.CalledProcessError:
137+ pass
138+ # Classic snaps w/o remote service
139+ else:
140+ return SnappyRestartStrategy()
141
142 if os.path.isdir('/etc/xdg/autostart'):
143 # NOTE: Assume this is a terminal application

Subscribers

People subscribed via source and target branches