more reliably restart client when server restarts

Splitting subiquity into server and client means that in general
old versions of the client can still be running when the server is
updated (the client running on tty1 will be restarted by snapd/systemd
when the snap is updated but clients running via e.g. ssh will not). I
implemented a way for the client to detect this and restart itself: the
server sets a header in all responses that indicates if it has been
updated. So far so good. But the way it knows that it has been updated
is to check the presence of a file that is only created when subiquity
itself triggers the refresh, so it's not there in the case of manual
refresh, and as reported in https://bugs.launchpad.net/bugs/1921820 this
can lead to the client crashing because it cannot parse the new server's
response. This simply changes to creating the marker file in the snap
post-refresh hook, which will be executed for manual snap refreshes as
well.

While I'm at it, remove the rest of the post-install hook that restarted
subiquity clients running on the serial line as the generic machinery
will work for these too.
This commit is contained in:
Michael Hudson-Doyle 2021-03-31 12:19:55 +13:00
parent b0ac3960be
commit 132440451d
3 changed files with 7 additions and 6 deletions

View File

@ -1,6 +1,3 @@
#!/bin/sh #!/bin/sh
# snapd will restart snap.subiquity.subiquity-service.service for us, mkdir -p /run/subiquity
# but any processes running on the serial lines are created via touch /run/subiquity/updating
# systemd overrides in the installer layer of the squashfs and so need
# restarting separately.
systemctl restart 'serial-subiquity@*.service'

View File

@ -191,7 +191,6 @@ class RefreshController(SubiquityController):
@with_context() @with_context()
async def start_update(self, context): async def start_update(self, context):
open(self.app.state_path('updating'), 'w').close()
change = await self.app.snapd.post( change = await self.app.snapd.post(
'v2/snaps/{}'.format(self.snap_name), 'v2/snaps/{}'.format(self.snap_name),
{'action': 'refresh'}) {'action': 'refresh'})

View File

@ -118,6 +118,9 @@ class ResponseSet:
return _FakeFileResponse(f) return _FakeFileResponse(f)
update_marker_file = '.subiquity/run/subiquity/updating'
class FakeSnapdConnection: class FakeSnapdConnection:
def __init__(self, snap_data_dir, scale_factor): def __init__(self, snap_data_dir, scale_factor):
self.snap_data_dir = snap_data_dir self.snap_data_dir = snap_data_dir
@ -130,6 +133,8 @@ class FakeSnapdConnection:
def post(self, path, body, **args): def post(self, path, body, **args):
if path == "v2/snaps/subiquity" and body['action'] == 'refresh': if path == "v2/snaps/subiquity" and body['action'] == 'refresh':
# The post-refresh hook does this in the real world.
open(update_marker_file, 'w').close()
return _FakeMemoryResponse({ return _FakeMemoryResponse({
"type": "async", "type": "async",
"change": "7", "change": "7",