def _systemctl_cmd_target(cmd, target): """ Run a systemctl cmd on a target. Returns True/False. """ retries = 5 delay = 2 # TODO: warn that target is null? if not target: return False cmd = "systemctl {} {}".format(cmd, target) # Try a _few_ times, with a small sleep. _rc, _stdout, _stderr = _run(cmd) while retries and _rc != 0: _rc, _stdout, _stderr = _run(cmd) retries -= 1 time.sleep(delay) if _rc != 0: log.error("Failed to {} target {}.".format(cmd, target)) return False return True
def _rchattr(op, path, attrs, rec, omit, rets): """ Yet another helper for the whole chattr story. Recursively applies op and attrs to paths which are not present in the omit list. Returns a dictionary of { path: True/False, ... } entries representing the succesful/not successful application of op and attrs. """ # Basic non recursive case. Set attrs for a given path, if it's not in the omit list. if not rec: if path not in omit: cmd = "chattr {} {}{} {}".format( '-d' if os.path.isdir(path) else '', op, attrs, path) _rc, _stdout, _stderr = _run(cmd) rets[path] = _rc == 0 return _rc == 0 else: log.warn(("Refusing to apply '{}' attrs to '{}' which is also in" "the omit list {}.".format(attrs, path, omit))) rets[path] = False return False # The fun case. else: # If our path is a directory, compute it's contents in an absolute form. if os.path.isdir(path): path_contents = ["{}/{}".format(path, e) for e in os.listdir(path)] # Leaf directory with no contents, and not to be omitted. if not path_contents and path not in omit: dir_opt = '-d' if os.path.isdir(path) else '' cmd = "chattr {} {}{} {}".format(dir_opt, op, attrs, path) _rc, _stdout, _stderr = _run(cmd) rets[path] = _rc == 0 # There are paths present in path_contents, process those. else: # For each path that is not in the omit list, recurse. for _pathname in path_contents: if _pathname not in omit: _rchattr(op, _pathname, attrs, rec, omit, rets) # Now process our non-leaf directory. # TODO: I have a feeling we should check this after the isdir() # and not process it or it's children. if path not in omit: # Finally add the path dir_opt = '-d' if os.path.isdir(path) else '' cmd = "chattr {} {}{} {}".format(dir_opt, op, attrs, path) _rc, _stdout, _stderr = _run(cmd) rets[path] = _rc == 0 # Path is a file. else: if path not in omit: dir_opt = '-d' if os.path.isdir(path) else '' cmd = "chattr {} {}{} {}".format(dir_opt, op, attrs, path) _rc, _stdout, _stderr = _run(cmd) rets[path] = _rc == 0
def btrfs_subvol_exists(subvol='', **kwargs): """ Determine if subvol, of the form @/foo/bar exists as a btrfs subvolume. The subvolume need not be mounted. Returns True/False. Returns False for empty subvolumes. """ if not subvol: return False # If the subvol is mounted somewhere, it obviously exists. if btrfs_get_mountpoints_of_subvol(subvol): return True # If it isn't mounted, we have no idea the mountpoint to use in the below # list, so just default to / cmd = "btrfs subvolume list /" _rc, _stdout, _stderr = _run(cmd) if _rc == 0 and _stdout: subvols = _stdout.split('\n') for subvol in subvols: if subvol.endswith("path {}".format(subvol)): return True # Haven't found it. return False
def _mount_osd(osd_dev, osd_mountpoint): """ Activate the OSD defined by osd_dev. Returns True/False """ _rc = 0 if get_mountpoint(osd_mountpoint) != osd_mountpoint: cmd = "mount {} {}".format(osd_dev, osd_mountpoint) _rc, _stdout, _stderr = _run(cmd) return _rc == 0
def _unmount_osd(osd_mountpoint): """ Unmount the OSD defined by osd_mountpoint. Returns True/False. """ _rc = 0 if get_mountpoint(osd_mountpoint) == osd_mountpoint: cmd = "umount {}".format(osd_mountpoint) _rc, _stdout, _stderr = _run(cmd) return _rc == 0
def ping_cmd(host): ''' Ping a host with 1 packet and return the result CLI Example: .. code-block:: bash sudo salt 'node' multi.ping_cmd <hostname>|<ip> ''' cmd = ["/usr/bin/ping", "-c1", "-q", "-W1", host] retcode, stdout, stderr = _run(cmd) return host, retcode, stdout, stderr
def users(realm='default', contains=None): """ Return the list of users for a realm. """ cmd = "radosgw-admin user list --rgw-realm={}".format(realm) retcode, stdout, _ = _run(cmd) if retcode != '0': if contains: return [item for item in json.loads(stdout) if contains in item] return json.loads(stdout) return []
def jumbo_ping_cmd(host): ''' Ping a host with 1 packet and return the result CLI Example: .. code-block:: bash sudo salt 'node' multi.ping_cmd <hostname>|<ip> ''' cmd = ["/usr/bin/ping", "-Mdo", "-s8972", "-c1", "-q", "-W1", host] log.debug('ping_cmd hostname={}'.format(host)) retcode, stdout, stderr = _run(cmd) return host, retcode, stdout, stderr
def btrfs_get_default_subvol(path='', **kwargs): """ Returns the default subvolume (in the form @/foo/bar) of a given path or None on error. """ cmd = "btrfs subvolume get-default {}".format(path) _rc, _stdout, _stderr = _run(cmd) if _rc == 0 and _stdout: # _stdout example: ID 259 gen 35248 top level 258 path @/.snapshots/1/snapshot # Return only the subvol return _stdout.split()[-1] return None
def _mv_contents(path, new_path): """ Try to move the contents of path to tmp_path. Return True/False. NOTE: Invoking `mv` as shutil.move() was not preserving ownership metadata. """ for entry in os.listdir(path): cmd = "mv {}/{} {}".format(path, entry, new_path) _rc, _stdout, _stderr = _run(cmd) if _rc != 0: return False return True
def _kernel_pkg(): """ Return the package of the running kernel """ kernel = open('/proc/cmdline').read() log.debug("/proc/cmdline: {}".format(kernel)) query = _query_command(_boot_image(kernel)) if query: log.debug("query: {}".format(query)) _, stdout, _ = _run(query) package = stdout log.info("package: {}".format(package)) return package return
def get_uuid(dev_path='', **kwargs): """ Determine the UUID of a given dev_path (ie. /dev/sdb2). Returns the UUID of dev, or None on error. NOTE: Simplified form of original found in osd.py """ pathname = "/dev/disk/by-uuid" cmd = "find -L {} -samefile {}".format(pathname, dev_path) _rc, _stdout, _stderr = _run(cmd) if _rc == 0 and _stdout: return os.path.basename(_stdout) else: log.error("Failed to determine uuid of '{}'.".format(dev_path)) return None
def iperf_client_cmd(server, cpu=0, port=5200): ''' Use iperf to test minion to server CLI Example: .. code-block:: bash salt 'node' multi.iperf_client_cmd <server_name/ip> cpu=<which_cpu_core default 0> port=<default 5200> ''' if IPERF_PATH is None or not server: if not server: return [LOCALHOST_NAME, 2, "0", "Server name is empty"] else: return [ LOCALHOST_NAME, 2, "0", "iperf3 not found in path, please install" ] iperf_cmd = [ "/usr/bin/iperf3", "-fm", "-A" + str(cpu), "-t10", "-c" + server, "-p" + str(port) ] log.debug('iperf_client_cmd: cmd {}'.format(iperf_cmd)) retcode, stdout, stderr = _run(iperf_cmd) return server, retcode, stdout, stderr
def get_attrs(path='', **kwargs): """ Obtains the raw output of `lsattr` on a given path. Returns the attrs string after having stripped off the path, or None on error or if path is empty. If path is a directory, it does not recursively follow all child paths. # TODO: Any use in adding a recursive flag and dumping output into a list? """ # TODO: Should we warn if the path doesn't exist, or quietly return None? if not os.path.exists(path): return None cmd = ("lsattr -d {}".format(path) if os.path.isdir(path) else "lsattr {}".format(path)) _rc, _stdout, _stderr = _run(cmd) if _rc == 0 and _stdout: return _stdout.split()[0] else: log.error("Failed to determine attrs for '{}': stderr: '{}'".format( path, _stderr)) return None
def btrfs_mount_subvol(subvol='', path='', **kwargs): """ Given a subvolume in the form "@/path/to/subvol", mount it atop of path. If path does not exist, log an error and abort. If path is already a mountpoint for for subvol, skip. If path is a mountpoint for something other than path, abort. Refuse to mount a subvol with a differing path (ie. refuse to mount @/var/lib/foo atop of /var/lib/bar). CAUTION: No checks are performed whether path contains existing data! NOTE: Does not touch /etc/fstab, for that, _add_fstab_entry(). Returns True/False. """ if not subvol or not path: log.error("Unable to mount subvolume '{}' onto '{}'.".format( subvol, path)) return False # Grab the mount info for path. mount_info = get_mount_info(path) if not mount_info: log.error(("Unable to mount subvolume '{}' onto '{}': no mount " "information obtained.".format(subvol, path))) return False # Grab device info to confirm this is a btrfs filesystem. dev_info = get_device_info(mount_info['mountpoint']) if not dev_info: log.error(("Unable to mount subvolume '{}' onto '{}': no filesystem " "information obtained.".format(subvol, path))) return False if dev_info['fstype'] != 'btrfs': log.error( "Unable to mount subvolume '{}' onto '{}': invalid filesystem type ({})." .format(subvol, path, dev_info['fstype'])) return False # Subvol should exist! if not btrfs_subvol_exists(subvol): log.error(("Unable to mount subvolume '{}' onto '{}': '{}' does not " "exist.".format(subvol, path, subvol))) return False # Path should exist! if not os.path.exists(path): log.error(("Unable to mount subvolume '{}' onto '{}': '{}' does not " "exist.".format(subvol, path, path))) return False # Begin mounting process. # If path == mountpoint, then we already have a subvolume mounted on this path. if path == mount_info['mountpoint']: # our path is a mountpoint, run some basic checks if path in btrfs_get_mountpoints_of_subvol(subvol): log.warn(("Subvolume '{}' is already mounted onto " "'{}'.".format(subvol, path))) return True else: # Another subvolume is mounted on path, output which log.error(("Unable to mount subvolume '{}' onto '{}': a different " "subvolume ({}) is already " "mounted.".format( subvol, path, _get_mount_opt('subvol', mount_info['opts'])))) return False else: # TODO: Should we prevent the same subvolume being mounted on multiple # different directories? btrfs is happy to mount the same subvolume # onto multiple directories, so let's not limit this behaviour. If # needed, we can always check the current subvol of the path, and if # it isn't the default subvol (via btrfs_get_default_subvol()), we # could assume a subvol is already mounted and log an error/return # False. pass # Finally mount! cmd = "mount '/dev/{}' '{}' -t btrfs -o subvol={}".format( dev_info['part_dev'], path, subvol) _rc, _stdout, _stderr = _run(cmd) if _rc != 0: log.error(("Failed to mount subvolume '{}' onto '{}': stderr: " "'{}'.".format(subvol, path, _stderr))) return False log.warn(("Successfully mounted subvolume '{}' onto " "'{}'.".format(subvol, path))) return True
def btrfs_create_subvol(subvol='', dev_info=None, **kwargs): """ Create a btrfs subvolume for the given subvol. Expected subvol to be of the form @/foo/bar. dev_info is either passed (when called directly) or queried by stripping off the '@' from the subvol in order to query the path. Return True/False. """ ret = True tmp_dir = None if not subvol: log.error("Unable to create subvolume '{}'.".format(subvol)) return False # Check if subvol already exists. if btrfs_subvol_exists(subvol): log.warn("Subvolume '{}' already exists.".format(subvol)) return True # If we didn't get dev_info (because we're being called directly from the command # line), we _assume_ that the subvol path will ultimately be mounted onto a matching # path, so _try_ to get the device information by converting subvol to it's corresponding # path (ie. by stripping the leading '@'). if not dev_info: dev_info = get_device_info(get_mountpoint(subvol[1:])) if not dev_info: log.error(("Unable to create subvolume '{}': failed to get device " "information for '{}'".format(subvol, subvol[1:]))) return False if dev_info['fstype'] != 'btrfs': log.error(("Unable to create subvolume '{}': invalid filesystem type " "({}).".format(subvol, dev_info['fstype']))) return False # Get the partition of the mountpoint of the path. part_path = "/dev/{}".format(dev_info['part_dev']) # Create a unique tmp directory. try: tmp_dir = tempfile.mkdtemp() # pylint: disable=bare-except except: log.error(("Unable to create subvolume '{}': failed to create " "temporary directory.".format(subvol))) return False # Mount tmpdir. cmd = "mount -t btrfs -o subvolid=0 '{}' '{}'".format(part_path, tmp_dir) _rc, _stdout, _stderr = _run(cmd) if _rc != 0: log.error("Failed to mount '{}' with subvolid=0 on '{}'.".format( part_path, tmp_dir)) ret = False if ret: # Create the subvol. cmd = "btrfs subvolume create '{}/{}'".format(tmp_dir, subvol) _rc, _stdout, _stderr = _run(cmd) if _rc != 0: log.error("Failed to create subvolume '{}' on '{}'.".format( subvol, part_path)) ret = False # Cleanup tmp_dir. Don't touch ret here, just log any errors. if os.path.exists(tmp_dir): cmd = "umount '{}'".format(tmp_dir) _rc, _stdout, _stderr = _run(cmd) if _rc != 0: log.error("Failed to unmount '{}'.".format(tmp_dir)) try: shutil.rmtree(tmp_dir) # pylint: disable=bare-except except: log.error("Failed to remove '{}'.".format(tmp_dir)) if not ret: # We failed somewhere, so take care of removing the subvolume, etc. # TODO: there is a bug with subvolume deletes # (https://bugzilla.opensuse.org/show_bug.cgi?id=957198) # so no more cleanup can be dont at this point. log.error("Failed to create subvolume '{}'.".format(subvol)) else: log.warn("Successfully created subvolume '{}'.".format(subvol)) return ret