Skip to content

Commit cfe8697

Browse files
committed
Added options continue apply shell
1 parent b0c936d commit cfe8697

File tree

1 file changed

+64
-6
lines changed

1 file changed

+64
-6
lines changed

atomic-update.py

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
VERSION = "0.1.0"
3232
ZYPPER_PID_FILE = "/run/zypp.pid"
3333
VALID_CMD = ["dup", "run", "rollback"]
34-
VALID_OPT = ["--reboot", "--apply", "--shell", "--continue", "--debug", "--help", "--version", "--no-confirm"]
34+
VALID_OPT = ["--reboot", "--apply", "--shell", "--continue", "--no-verify", "--interactive", "--debug", "--help", "--version"]
3535

3636
# Command help/usage info
3737
help_text = """
@@ -50,11 +50,11 @@
5050
--apply - Switch into default snapshot without reboot
5151
--shell - Open shell in new snapshot before exiting
5252
--continue [number] - Use latest or given snapshot as base
53-
--no-verify - Skip verification of new snapshot
53+
--no-verify - Skip verification of snapshot
54+
--interactive - Run dup in interactive mode
5455
--debug - Enable debug output
5556
--help - Print this help and exit
5657
--version - Print version number and exit
57-
--no-confirm - Automatic yes to prompts, run non-interactively
5858
"""
5959

6060
################################
@@ -181,7 +181,7 @@ def sigint_handler(signum, frame):
181181
sys.exit(1)
182182

183183
DEBUG = True if "--debug" in OPT else False
184-
NO_CONFIRM = True if "--no-confirm" in OPT else False
184+
CONFIRM = True if "--interactive" in OPT else False
185185
REBOOT = True if "--reboot" in OPT else False
186186
APPLY = True if "--apply" in OPT else False
187187
SHELL = True if "--shell" in OPT else False
@@ -195,6 +195,27 @@ def sigint_handler(signum, frame):
195195
level=logging.DEBUG if DEBUG else logging.INFO,
196196
)
197197

198+
# check if there's a snapshot number provided to continue from
199+
continue_num = None
200+
if "--continue" in OPT:
201+
try:
202+
continue_num = int(sys.argv[sys.argv.index("--continue") + 1])
203+
if not continue_num in range(1, 999999):
204+
logging.error("Invalid value for option '--continue'. Must be between 1 to 999999 (inclusive)")
205+
sys.exit(1)
206+
except ValueError:
207+
logging.debug("No numerical value provided for option '--continue'")
208+
pass
209+
except IndexError:
210+
logging.debug("No value provided for option '--continue'")
211+
pass
212+
213+
if continue_num:
214+
ret = os.system(f"btrfs subvolume list / | grep '@/.snapshots/{continue_num}/snapshot'")
215+
if ret != 0:
216+
logging.error(f"Provided snapshot {continue_num} for option '--continue' does not exist")
217+
sys.exit(1)
218+
198219
# Bail out if we're not root
199220
if os.getuid() != 0:
200221
logging.error("Bailing out, program must be run with root privileges")
@@ -245,6 +266,10 @@ def sigint_handler(signum, frame):
245266
# get active and default snapshot number
246267
active_snap, default_snap = get_snaps(snapper_root_config)
247268
logging.debug(f"Active snapshot number: {active_snap}, Default snapshot number: {default_snap}")
269+
if CONTINUE:
270+
active_snap = default_snap
271+
if continue_num:
272+
active_snap = continue_num
248273
# create new read-write snapshot to perform dup in
249274
out, ret = shell_exec(f"snapper -c {snapper_root_config} create -c number " \
250275
f"-d 'Atomic update of #{active_snap}' " \
@@ -255,6 +280,7 @@ def sigint_handler(signum, frame):
255280
# get latest atomic snapshot
256281
atomic_snap = get_atomic_snap(snapper_root_config)
257282
logging.debug(f"Latest atomic snapshot number: {atomic_snap}")
283+
logging.info(f"Using snapshot {active_snap} as base for new snapshot {atomic_snap}")
258284
snap_subvol = f"@/.snapshots/{atomic_snap}/snapshot"
259285
snap_dir = snap_subvol.lstrip("@")
260286
# check the latest atomic snapshot exists
@@ -289,18 +315,50 @@ def sigint_handler(signum, frame):
289315
cleanup()
290316
sys.exit()
291317
logging.info("Performing atomic distribution upgrade...")
292-
ret = os.system(f"zypper --root {TMP_DIR} {'--non-interactive' if NO_CONFIRM else ''} --no-cd dist-upgrade")
318+
ret = os.system(f"zypper --root {TMP_DIR} {'' if CONFIRM else '--non-interactive'} --no-cd dist-upgrade")
293319
if ret != 0:
294320
logging.error(f"Zypper returned exit code {ret}. Discarding snapshot {atomic_snap}")
295321
shell_exec(f"snapper -c {snapper_root_config} delete {atomic_snap}")
296322
cleanup()
297323
sys.exit(9)
298324
logging.info(f"Distribution upgrade completed successfully")
325+
if SHELL:
326+
logging.info(f"Opening chroot in snapshot {atomic_snap}")
327+
logging.info("Continue with 'exit' or discard with 'exit 1'")
328+
ret = os.system(f"chroot {snap_dir} env PS1='atomic-update:${{PWD}} # ' bash --noprofile --norc")
329+
if ret != 0:
330+
logging.error(f"Shell returned exit code {ret}. Discarding snapshot {atomic_snap}")
331+
shell_exec(f"snapper -c {snapper_root_config} delete {atomic_snap}")
332+
cleanup()
333+
sys.exit()
299334
logging.info(f"Setting snapshot {atomic_snap} ({snap_dir}) as the new default")
300335
shell_exec(f"snapper -c {snapper_root_config} modify --default {atomic_snap}")
301336
# perform cleanup
302337
cleanup()
303338
if REBOOT:
339+
logging.info("Rebooting now...")
304340
os.system("systemctl reboot")
305341
if APPLY:
306-
pass
342+
logging.info(f"Using default snapshot {atomic_snap} to replace running system...")
343+
logging.info("Applying /usr...")
344+
os.system(f"mount -o bind {snap_dir}/usr /usr")
345+
# find subvols under /usr and mount them
346+
out, ret = shell_exec("LC_ALL=C btrfs subvolume list / | grep -v snapshots | grep '@/usr' | awk '{print $9}'")
347+
for subvol in out.split("\n"):
348+
subvol = subvol.lstrip("@")
349+
os.system(f"mount -o bind {snap_dir}{subvol} {subvol}")
350+
logging.info("Applying /etc...")
351+
os.system(f"mount -o bind {snap_dir}/etc /etc")
352+
logging.info("Applying /boot...")
353+
os.system(f"mount -o bind {snap_dir}/boot /boot")
354+
# find subvols under /boot and mount them
355+
out, ret = shell_exec("LC_ALL=C btrfs subvolume list / | grep -v snapshots | grep '@/boot' | awk '{print $9}'")
356+
for subvol in out.split("\n"):
357+
subvol = subvol.lstrip("@")
358+
os.system(f"mount -o bind {snap_dir}{subvol} {subvol}")
359+
logging.info("Executing systemctl daemon-reexec...")
360+
os.system("systemctl daemon-reexec")
361+
logging.info("Executing systemd-tmpfiles --create...")
362+
os.system("systemd-tmpfiles --create")
363+
logging.info("Applied default snapshot as new base for running system!")
364+
logging.info("Running processes will not be restarted automatically.")

0 commit comments

Comments
 (0)