PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/extras-3.10/rads/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/extras-3.10/rads/vz.py |
"""VZ / HA functions""" import enum import shlex import subprocess import os from typing import Iterable, Union, Optional import distro class ListCmd(enum.Enum): """vz list base commands""" VZLIST = ['/usr/sbin/vzlist', '-H'] PRLCTL = ['/usr/bin/prlctl', 'list', '-H'] class VZError(Exception): """Raised for errors with VZ and OpenVZ""" def is_vz() -> bool: """Checks if host is a Virtuozzo node""" return bool("Virtuozzo" in distro.name()) def is_openvz() -> bool: """Check if host is an OpenVZ node""" return os.path.isfile('/etc/virtuozzo-release') and not is_vz() def is_vz7() -> bool: """Check if host is a Virtuozzo 7 node""" return bool(is_vz() and distro.major_version() == "7") def is_vps() -> bool: """Check if host is a Virtuozzo container""" try: with open("/proc/vz/veinfo", encoding='ascii') as handle: ve_data = handle.read().strip() except IOError: return False # if veinfo doesn't exist this can't be a vps if ve_data.count("\n") != 0: return False try: veid = int( ve_data.split()[0] ) # if veinfo contains >1 line, this is a CL or VZ node except ValueError: return True # veinfo contains a UUID return veid != 0 def _exec(cmd: Iterable): """For executing prlctl or vzlist""" try: ret = subprocess.run( cmd, capture_output=True, encoding='utf-8', check=False ) except FileNotFoundError as exc: raise VZError(exc) from exc if ret.returncode: # nonzero raise VZError('Error running {!r}. stderr={!r}'.format(cmd, ret.stderr)) return ret def is_ct_running(ctid: Union[str, int]) -> bool: """Checks if a container is running Args: ctid: container ID to check Returns: True if the container is running on this node, False if it isn't or if some other error occurs """ try: ret = subprocess.run( ['/usr/bin/prlctl', 'list', '-H', '-o', 'status', str(ctid)], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, encoding='utf-8', check=True, ) except FileNotFoundError: pass # retry with vzlist except subprocess.CalledProcessError: return False else: return ret.stdout.split()[0] == 'running' try: ret = _exec(['/usr/sbin/vzlist', '-H', '-o', 'status', str(ctid)]) except VZError: # CTID probably doesn't exist return False return ret.stdout.split()[0] == 'running' def uuid2ctid(uuid: str) -> str: """get the legacy CTID of a container Args: uuid: VZ UUID to find the legacy CTID for Raises: VZError: if the prlctl command fails """ ret = _exec(['/usr/bin/prlctl', 'list', '-H', '-o', 'name', uuid]) return ret.stdout.split()[0] def ctid2uuid(ctid: Union[int, str]) -> str: """Obtain the UUID of a container from its legacy CTID Warning: This does not work on VZ4 Args: ctid: Legacy CTID to get the UUID for Raises: VZError: if the prlctl command fails """ ret = _exec(['/usr/bin/prlctl', 'list', '-H', '-o', 'uuid', str(ctid)]) return ret.stdout.split()[0].strip(r'{}') def get_envid(ctid: Union[int, str]) -> str: """Obtain the EnvID of a container Note: This determines what the subdirectory of /vz/root and /vz/private will be. This also has to run on VZ4 which lacks the envid field or prlctl, so we just return the CTID Args: ctid: legacy CTID to find the envid for Raises: VZError: if the prlctl command fails or /etc/virtuozzo-release is missing """ try: with open('/etc/virtuozzo-release', 'r', encoding='utf-8') as handle: if 'Virtuozzo release 4' in handle.read(): return str(ctid) except FileNotFoundError as exc: raise VZError(exc) from exc ret = _exec(['/usr/bin/prlctl', 'list', '-H', '-o', 'envid', str(ctid)]) return ret.stdout.split()[0] def _list_cmd( opts: list, args: Optional[list] = None, list_cmd: Optional[ListCmd] = None, ) -> tuple[ListCmd, list[str]]: """Deterines the cmd to run based on VZ version for get_cts() Args: opts: items to send into ``-o/--output`` args: optional params to send such as ``--all`` list_cmd (ListCmd): set this to ListCmd.VZLIST or ListCmd.PRLCTL to skip auto-detecting which command to use """ if list_cmd is None: if is_vz(): if not is_vz7() and 'ostemplate' in opts: # prlctl's ostemplate is broken and reports distro on vz6 # switch to vzlist; fix envid to veid if it was requested list_cmd = ListCmd.VZLIST else: list_cmd = ListCmd.PRLCTL else: # OpenVZ list_cmd = ListCmd.VZLIST if list_cmd == ListCmd.VZLIST: conv_opts = {x: ('veid' if x == 'envid' else x) for x in opts} else: # prctl refers to 'ctid' as 'name' conv_opts = {x: ('name' if x == 'ctid' else x) for x in opts} cmd = list_cmd.value.copy() if args is not None: cmd.extend(args) # forces opts's vals to be in the same order as args cmd_opts = ','.join([conv_opts[x] for x in opts]) cmd.extend(['-o', cmd_opts]) return list_cmd, cmd def _read_row( list_cmd: ListCmd, cmd: list[str], row: list[str], opts: list[str] ) -> dict[str, str]: # if number of rows matches requested options, return normally if len(row) == len(opts): return {x: row[i] for i, x in enumerate(opts)} # handle an edge case: prlctl can print missing ostemplates as '' while # vzlist prints it as '-', making the prlctl one harder to parse if ( list_cmd == ListCmd.PRLCTL and len(row) == len(opts) - 1 and 'ostemplate' in opts ): opts = opts.copy() opts.remove('ostemplate') ret = {x: row[i] for i, x in enumerate(opts)} ret['ostemplate'] = '-' return ret raise VZError( f'{shlex.join(cmd)} expected {len(opts)} columns,' f' but got {len(row)}: {row}' ) def get_cts( opts: Optional[list] = None, args: Optional[list] = None, list_cmd: Optional[ListCmd] = None, ) -> list[dict[str, str]]: """Returns containers according to platform as a list of dicts Args: opts: items to send into -o/--output (will default to ['ctid'] if None) args: optional params to send such as --all list_cmd (ListCmd): set this to ListCmd.VZLIST or ListCmd.PRLCTL to skip auto-detecting which command to use Raises: VZError: if the prlctl or vzlist command fails """ if not opts: opts = ['ctid'] ret = [] # process each line as a dict where keys are the arg and vals are the result list_cmd, cmd = _list_cmd(opts, args, list_cmd) for row in _exec(cmd).stdout.splitlines(): row = row.strip() if not row: continue # blank line ret.append(_read_row(list_cmd, cmd, row.split(), opts)) return ret