feat(selfhost): start full updates from administration
This commit is contained in:
@@ -109,6 +109,9 @@ class Controller:
|
||||
if record.get("status") in ("queued", "running"):
|
||||
record.update(status="interrupted", errorCode="INTERRUPTED", updatedAt=engine.now())
|
||||
engine.write_json(path, record)
|
||||
if (REQUEST_ID.fullmatch(str(record.get("requestId", "")))
|
||||
and (self.active is None or record.get("startedAt", "") > self.read(self.active).get("startedAt", ""))):
|
||||
self.active = record["requestId"]
|
||||
updater.status() # Detect an abandoned engine job without touching an active CLI job.
|
||||
except BaseException:
|
||||
self.daemon_lock.close()
|
||||
|
||||
@@ -418,7 +418,14 @@ class Updater:
|
||||
for name in required:
|
||||
if old[name].get("profiles") or new[name].get("profiles") or new[name].get("build"):
|
||||
raise UpdateError("Build-Kontexte und Compose-Profile werden nicht unterstützt.")
|
||||
if old[name].get("volumes", []) != new[name].get("volumes", []):
|
||||
old_mounts, new_mounts = old[name].get("volumes", []), new[name].get("volumes", [])
|
||||
# One-time bootstrap of the constrained updater API; never relax data-mount checks.
|
||||
control_mount = {"type": "bind", "source": "/run/fedeo-updater", "target": "/run/fedeo-updater",
|
||||
"read_only": True, "bind": {}}
|
||||
control_variants = (control_mount, {**control_mount, "bind": {"create_host_path": True}})
|
||||
if name == "backend" and not any(v.get("target") == "/run/fedeo-updater" for v in old_mounts):
|
||||
new_mounts = [v for v in new_mounts if v not in control_variants]
|
||||
if old_mounts != new_mounts:
|
||||
raise UpdateError(f"Datenpfade/Mounts von {name} würden verändert; zuerst manuell migrieren.")
|
||||
if old[name].get("container_name") != new[name].get("container_name"):
|
||||
raise UpdateError(f"Container-Identität von {name} würde verändert.")
|
||||
|
||||
@@ -130,6 +130,7 @@ class ServiceTests(unittest.TestCase):
|
||||
self.controller.close()
|
||||
self.controller = s.Controller(self.root, updater_factory=self.factory)
|
||||
self.server.controller = self.controller
|
||||
self.assertEqual(self.request('GET', '/v1/status')[1]['request']['requestId'], request_id)
|
||||
status, _ = self.request('POST', '/v1/check', {'requestId': request_id, 'version': '3.2.0'})
|
||||
self.assertEqual(status, 200)
|
||||
self.assertEqual(len(self.factory.calls), 1)
|
||||
|
||||
@@ -449,6 +449,26 @@ class UpdateTests(unittest.TestCase):
|
||||
self.run_update()
|
||||
self.assert_untouched()
|
||||
|
||||
def test_first_update_can_add_only_the_readonly_control_directory(self):
|
||||
control_line = b' - /run/fedeo-updater:/run/fedeo-updater:ro\n'
|
||||
self.assertIn(control_line, self.original_compose)
|
||||
(self.root / 'docker-compose.yml').write_bytes(self.original_compose.replace(control_line, b' []\n'))
|
||||
result = self.run_update()
|
||||
self.assertEqual(result['status'], 'succeeded')
|
||||
self.assertIn(control_line, (self.root / 'docker-compose.yml').read_bytes())
|
||||
|
||||
def test_control_mount_bootstrap_rejects_write_access_or_another_host_directory(self):
|
||||
control_line = b' - /run/fedeo-updater:/run/fedeo-updater:ro\n'
|
||||
(self.root / 'docker-compose.yml').write_bytes(self.original_compose.replace(control_line, b' []\n'))
|
||||
for replacement in (b' - /run/fedeo-updater:/run/fedeo-updater:rw\n',
|
||||
b' - /var/run/docker.sock:/run/fedeo-updater:ro\n'):
|
||||
with self.subTest(replacement=replacement):
|
||||
self.http.files['docker-compose.selfhost.yml'] = self.original_compose.replace(control_line, replacement)
|
||||
self.http.refresh()
|
||||
with self.assertRaisesRegex(u.UpdateError, 'Datenpfade'):
|
||||
self.run_update()
|
||||
self.assertFalse(self.called('stop'))
|
||||
|
||||
def test_external_storage_fails_before_maintenance(self):
|
||||
(self.root / '.env').write_bytes(self.original_env.replace(b'http://minio:9000', b'https://storage.example.test'))
|
||||
with self.assertRaisesRegex(u.UpdateError, 'Backup-Adapter'):
|
||||
|
||||
Reference in New Issue
Block a user