canonical / jhack

Chock-full of Juju hackery.
Apache License 2.0
48 stars 23 forks source link

jenv assumes multipass is installed and crashes if it is not #79

Closed dstathis closed 1 year ago

dstathis commented 1 year ago
dylan@protostar:~$ jhack jenv
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/dylan/repos/jhack/venv/lib/python3.10/site-packages/jhack/utils/print_env.py:101 in        │
│ print_env                                                                                        │
│                                                                                                  │
│    98 │   │   f"{python_v.major}.{python_v.minor}.{python_v.micro} ({sys.executable})"           │
│    99 │   )                                                                                      │
│   100 │                                                                                          │
│ ❱ 101 │   multipass_version = get_multipass_version()                                            │
│   102 │   data = {                                                                               │
│   103 │   │   "jhack": get_jhack_version(),                                                      │
│   104 │   │   "python": python_version,                                                          │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │         format = <Format.auto: 'auto'>                                                       │ │
│ │       python_v = sys.version_info(major=3, minor=10, micro=6, releaselevel='final',          │ │
│ │                  serial=0)                                                                   │ │
│ │ python_version = '3.10.6 (/home/dylan/repos/jhack/venv/bin/python3)'                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /home/dylan/repos/jhack/venv/lib/python3.10/site-packages/jhack/utils/print_env.py:79 in         │
│ get_multipass_version                                                                            │
│                                                                                                  │
│    76 def get_multipass_version():                                                               │
│    77 │   """Multipass --version."""                                                             │
│    78 │   try:                                                                                   │
│ ❱  79 │   │   multipass_version = get_output("multipass version --format json")                  │
│    80 │   except subprocess.CalledProcessError:                                                  │
│    81 │   │   logger.info("multipass not found")                                                 │
│    82 │   │   multipass_version = None                                                           │
│                                                                                                  │
│ /home/dylan/repos/jhack/venv/lib/python3.10/site-packages/jhack/utils/print_env.py:24 in         │
│ get_output                                                                                       │
│                                                                                                  │
│    21                                                                                            │
│    22 def get_output(command: str) -> Optional[str]:                                             │
│    23 │   try:                                                                                   │
│ ❱  24 │   │   p = subprocess.run(command.split(), capture_output=True, text=True)                │
│    25 │   │   return p.stdout.strip() if p.returncode == 0 else None                             │
│    26 │   except subprocess.CalledProcessError as e:                                             │
│    27 │   │   logger.info(e)                                                                     │
│                                                                                                  │
│ ╭────────────────── locals ───────────────────╮                                                  │
│ │ command = 'multipass version --format json' │                                                  │
│ ╰─────────────────────────────────────────────╯                                                  │
│                                                                                                  │
│ /usr/lib/python3.10/subprocess.py:501 in run                                                     │
│                                                                                                  │
│    498 │   │   kwargs['stdout'] = PIPE                                                           │
│    499 │   │   kwargs['stderr'] = PIPE                                                           │
│    500 │                                                                                         │
│ ❱  501 │   with Popen(*popenargs, **kwargs) as process:                                          │
│    502 │   │   try:                                                                              │
│    503 │   │   │   stdout, stderr = process.communicate(input, timeout=timeout)                  │
│    504 │   │   except TimeoutExpired as exc:                                                     │
│                                                                                                  │
│ ╭───────────────────────────── locals ─────────────────────────────╮                             │
│ │ capture_output = True                                            │                             │
│ │          check = False                                           │                             │
│ │          input = None                                            │                             │
│ │         kwargs = {'text': True, 'stdout': -1, 'stderr': -1}      │                             │
│ │      popenargs = (['multipass', 'version', '--format', 'json'],) │                             │
│ │        timeout = None                                            │                             │
│ ╰──────────────────────────────────────────────────────────────────╯                             │
│                                                                                                  │
│ /usr/lib/python3.10/subprocess.py:969 in __init__                                                │
│                                                                                                  │
│    966 │   │   │   │   │   self.stderr = io.TextIOWrapper(self.stderr,                           │
│    967 │   │   │   │   │   │   │   encoding=encoding, errors=errors)                             │
│    968 │   │   │                                                                                 │
│ ❱  969 │   │   │   self._execute_child(args, executable, preexec_fn, close_fds,                  │
│    970 │   │   │   │   │   │   │   │   pass_fds, cwd, env,                                       │
│    971 │   │   │   │   │   │   │   │   startupinfo, creationflags, shell,                        │
│    972 │   │   │   │   │   │   │   │   p2cread, p2cwrite,                                        │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               args = ['multipass', 'version', '--format', 'json']                            │ │
│ │            bufsize = -1                                                                      │ │
│ │            c2pread = 3                                                                       │ │
│ │           c2pwrite = 4                                                                       │ │
│ │          close_fds = True                                                                    │ │
│ │      creationflags = 0                                                                       │ │
│ │                cwd = None                                                                    │ │
│ │           encoding = 'locale'                                                                │ │
│ │                env = None                                                                    │ │
│ │             errors = None                                                                    │ │
│ │            errread = 5                                                                       │ │
│ │           errwrite = 6                                                                       │ │
│ │         executable = None                                                                    │ │
│ │       extra_groups = None                                                                    │ │
│ │                  f = <_io.TextIOWrapper name=5 encoding='UTF-8'>                             │ │
│ │                gid = None                                                                    │ │
│ │               gids = None                                                                    │ │
│ │              group = None                                                                    │ │
│ │     line_buffering = False                                                                   │ │
│ │            p2cread = -1                                                                      │ │
│ │           p2cwrite = -1                                                                      │ │
│ │           pass_fds = ()                                                                      │ │
│ │           pipesize = -1                                                                      │ │
│ │         preexec_fn = None                                                                    │ │
│ │    restore_signals = True                                                                    │ │
│ │               self = <Popen: returncode: 255 args: ['multipass', 'version', '--format',      │ │
│ │                      'json']>                                                                │ │
│ │              shell = False                                                                   │ │
│ │  start_new_session = False                                                                   │ │
│ │        startupinfo = None                                                                    │ │
│ │             stderr = -1                                                                      │ │
│ │              stdin = None                                                                    │ │
│ │             stdout = -1                                                                      │ │
│ │               text = True                                                                    │ │
│ │                uid = None                                                                    │ │
│ │              umask = -1                                                                      │ │
│ │ universal_newlines = None                                                                    │ │
│ │               user = None                                                                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/lib/python3.10/subprocess.py:1845 in _execute_child                                         │
│                                                                                                  │
│   1842 │   │   │   │   │   │   err_filename = orig_executable                                    │
│   1843 │   │   │   │   │   if errno_num != 0:                                                    │
│   1844 │   │   │   │   │   │   err_msg = os.strerror(errno_num)                                  │
│ ❱ 1845 │   │   │   │   │   raise child_exception_type(errno_num, err_msg, err_filename)          │
│   1846 │   │   │   │   raise child_exception_type(err_msg)                                       │
│   1847                                                                                           │
│   1848                                                                                           │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │                    args = ['multipass', 'version', '--format', 'json']                       │ │
│ │                 c2pread = 3                                                                  │ │
│ │                c2pwrite = 4                                                                  │ │
│ │    child_exception_type = <class 'OSError'>                                                  │ │
│ │ child_exec_never_called = False                                                              │ │
│ │               close_fds = True                                                               │ │
│ │           creationflags = 0                                                                  │ │
│ │                     cwd = None                                                               │ │
│ │                     env = None                                                               │ │
│ │                env_list = None                                                               │ │
│ │            err_filename = 'multipass'                                                        │ │
│ │                 err_msg = 'No such file or directory'                                        │ │
│ │               errno_num = 2                                                                  │ │
│ │            errpipe_data = bytearray(b'OSError:2:')                                           │ │
│ │            errpipe_read = 7                                                                  │ │
│ │           errpipe_write = 8                                                                  │ │
│ │                 errread = 5                                                                  │ │
│ │                errwrite = 6                                                                  │ │
│ │          exception_name = bytearray(b'OSError')                                              │ │
│ │              executable = b'multipass'                                                       │ │
│ │         executable_list = (                                                                  │ │
│ │                           │   b'/home/dylan/repos/jhack/venv/bin/multipass',                 │ │
│ │                           │   b'/home/dylan/.local/bin/multipass',                           │ │
│ │                           │   b'/home/dylan/bin/multipass',                                  │ │
│ │                           │   b'/home/dylan/bin/multipass',                                  │ │
│ │                           │   b'/usr/local/sbin/multipass',                                  │ │
│ │                           │   b'/usr/local/bin/multipass',                                   │ │
│ │                           │   b'/usr/sbin/multipass',                                        │ │
│ │                           │   b'/usr/bin/multipass',                                         │ │
│ │                           │   b'/sbin/multipass',                                            │ │
│ │                           │   b'/bin/multipass',                                             │ │
│ │                           │   ... +3                                                         │ │
│ │                           )                                                                  │ │
│ │             fds_to_keep = {8}                                                                │ │
│ │                     gid = None                                                               │ │
│ │                    gids = None                                                               │ │
│ │               hex_errno = bytearray(b'2')                                                    │ │
│ │        low_fds_to_close = []                                                                 │ │
│ │         orig_executable = 'multipass'                                                        │ │
│ │                 p2cread = -1                                                                 │ │
│ │                p2cwrite = -1                                                                 │ │
│ │                    part = b''                                                                │ │
│ │                pass_fds = ()                                                                 │ │
│ │                     pid = 1307211                                                            │ │
│ │              preexec_fn = None                                                               │ │
│ │         restore_signals = True                                                               │ │
│ │                    self = <Popen: returncode: 255 args: ['multipass', 'version', '--format', │ │
│ │                           'json']>                                                           │ │
│ │                   shell = False                                                              │ │
│ │       start_new_session = False                                                              │ │
│ │             startupinfo = None                                                               │ │
│ │                     sts = 65280                                                              │ │
│ │                     uid = None                                                               │ │
│ │                   umask = -1                                                                 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
FileNotFoundError: [Errno 2] No such file or directory: 'multipass'
dstathis commented 1 year ago

Is multipass version actually helpful? As far as I can tell it would have nothing to do with the functioning of charms.

dstathis commented 1 year ago

Also I would guess this happens with microk8s and lxd which are both not always present. A simple fix would be to check which lxd before trying to get the version.

jamesbeedy commented 1 year ago

Hitting this on my end too ... seems to happen even if multipass is installed

https://paste.ubuntu.com/p/pSkzrgnzWz/

PietroPasotti commented 1 year ago

the issue is jhack's snap strict confinement. From jhack's point of view, there is no multipass. Will need to change the output conditional of the IS_SNAPPED var. Probably jenv only makes sense if you're running jhack from sources, because in most cases you're not quite interested in what juju jhack is running, but what you are running locally.