From 517adc4f06693d1629b78f53b42bbe964a58e359 Mon Sep 17 00:00:00 2001 From: Tiago Nobrega Date: Fri, 8 Nov 2024 12:04:40 -0300 Subject: [PATCH 1/2] fix(snap): check if LXD is actually installed On recent Ubuntu systems, "lxc" might be "/usr/sbin/lxc", which is provided by the "lxd-installer" package and will install the LXD snap if it's not installed. This installation can then take a long time if the store is having issues. For the purposes of the configure and remove hooks we *don't* want to install LXD just to check that it has no stale images, so update the hooks to do some early detection and bail out if LXD is not installed. Fixes #1982 --- snap/hooks/configure | 24 ++++++++++++++++++++++++ snap/hooks/remove | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/snap/hooks/configure b/snap/hooks/configure index 3594428e0..a7a221e5a 100755 --- a/snap/hooks/configure +++ b/snap/hooks/configure @@ -17,11 +17,13 @@ remote image version: core22 ----------------------------------------------- """ import json +import platform import re import subprocess import sys from datetime import datetime +from pathlib import Path from charmcraft import snap @@ -73,6 +75,24 @@ def _delete_lxd_instance(instance: dict) -> None: print(f"Failed to remove LXD instance {instance['name']}.", file=sys.stderr) +def _has_lxd() -> bool: + try: + lxc_binary = subprocess.check_output(["which", "lxc"]) + except subprocess.CalledProcessError: + return False + + if lxc_binary == b"/usr/sbin/lxc": + # In Ubuntu, /usr/sbin/lxc is a wrapper that might install LXD, which we + # *don't* want to do + is_ubuntu = "ubuntu" in platform.uname().version.lower() + if is_ubuntu: + # /usr/sbin/lxc will only install LXD if /snap/bin/lxc doesn't exist + return Path("/snap/bin/lxc").exists() + + # In all other cases the result of "which lxc" should be valid + return True + + def configure_hook_main(): # Unique valid base instances directory to prevent duplication. image_slots = {} @@ -85,6 +105,10 @@ def configure_hook_main(): print(f"Unsupported snap configuration: {reason}.", file=sys.stderr) sys.exit(1) + if not _has_lxd(): + print("LXD is not installed.", file=sys.stderr) + return + # Remove only base images in LXD related project try: lxd_images_json = subprocess.check_output( diff --git a/snap/hooks/remove b/snap/hooks/remove index 907896737..43c28167f 100755 --- a/snap/hooks/remove +++ b/snap/hooks/remove @@ -3,13 +3,37 @@ """Remove all related LXD images and instances when removing the snap.""" import json +import platform import subprocess import sys +from pathlib import Path PROJECT_NAME = "charmcraft" +def _has_lxd() -> bool: + try: + lxc_binary = subprocess.check_output(["which", "lxc"]) + except subprocess.CalledProcessError: + return False + + if lxc_binary == b"/usr/sbin/lxc": + # In Ubuntu, /usr/sbin/lxc is a wrapper that might install LXD, which we + # *don't* want to do + is_ubuntu = "ubuntu" in platform.uname().version.lower() + if is_ubuntu: + # /usr/sbin/lxc will only install LXD if /snap/bin/lxc doesn't exist + return Path("/snap/bin/lxc").exists() + + # In all other cases the result of "which lxc" should be valid + return True + + def remove_hook_main(): + if not _has_lxd(): + print("LXD is not installed.", file=sys.stderr) + return + # Remove all images in LXD related project try: lxd_images_json = subprocess.check_output( From 933a4d93b7f3fd85c5e252b639b385d34450a584 Mon Sep 17 00:00:00 2001 From: Tiago Nobrega Date: Fri, 8 Nov 2024 14:25:05 -0300 Subject: [PATCH 2/2] fixup! fix(snap): check if LXD is actually installed --- snap/hooks/configure | 18 +----------------- snap/hooks/remove | 18 +----------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/snap/hooks/configure b/snap/hooks/configure index a7a221e5a..9683bbf55 100755 --- a/snap/hooks/configure +++ b/snap/hooks/configure @@ -17,13 +17,11 @@ remote image version: core22 ----------------------------------------------- """ import json -import platform import re import subprocess import sys from datetime import datetime -from pathlib import Path from charmcraft import snap @@ -76,21 +74,7 @@ def _delete_lxd_instance(instance: dict) -> None: def _has_lxd() -> bool: - try: - lxc_binary = subprocess.check_output(["which", "lxc"]) - except subprocess.CalledProcessError: - return False - - if lxc_binary == b"/usr/sbin/lxc": - # In Ubuntu, /usr/sbin/lxc is a wrapper that might install LXD, which we - # *don't* want to do - is_ubuntu = "ubuntu" in platform.uname().version.lower() - if is_ubuntu: - # /usr/sbin/lxc will only install LXD if /snap/bin/lxc doesn't exist - return Path("/snap/bin/lxc").exists() - - # In all other cases the result of "which lxc" should be valid - return True + return subprocess.run(["snap", "list", "lxd"]).returncode == 0 def configure_hook_main(): diff --git a/snap/hooks/remove b/snap/hooks/remove index 43c28167f..77332f2ec 100755 --- a/snap/hooks/remove +++ b/snap/hooks/remove @@ -3,30 +3,14 @@ """Remove all related LXD images and instances when removing the snap.""" import json -import platform import subprocess import sys -from pathlib import Path PROJECT_NAME = "charmcraft" def _has_lxd() -> bool: - try: - lxc_binary = subprocess.check_output(["which", "lxc"]) - except subprocess.CalledProcessError: - return False - - if lxc_binary == b"/usr/sbin/lxc": - # In Ubuntu, /usr/sbin/lxc is a wrapper that might install LXD, which we - # *don't* want to do - is_ubuntu = "ubuntu" in platform.uname().version.lower() - if is_ubuntu: - # /usr/sbin/lxc will only install LXD if /snap/bin/lxc doesn't exist - return Path("/snap/bin/lxc").exists() - - # In all other cases the result of "which lxc" should be valid - return True + return subprocess.run(["snap", "list", "lxd"]).returncode == 0 def remove_hook_main():