def supports_vdo(): cmd = ['segtypes'] rc, out, err = call(cmd) if rc == 0: if "vdo" in out: log_debug("We have VDO support") return True return False
def refresh(self, log=True): """ Go out and query lvm for the latest data in as few trips as possible :param log Add debug log entry/exit messages :return: None """ self.num_refreshes += 1 if log: log_debug("lvmdb - refresh entry") # Grab everything first then parse it if self.json: # Do a single lvm retrieve for everything in json a = cmdhandler.lvm_full_report_json() _pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs_json(a) _vgs, _vgs_lookup = self._parse_vgs_json(a) _lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json( a) else: _raw_pvs = cmdhandler.pv_retrieve_with_segs() _raw_vgs = cmdhandler.vg_retrieve(None) _raw_lvs = cmdhandler.lv_retrieve_with_segments() _pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs) _vgs, _vgs_lookup = self._parse_vgs(_raw_vgs) _lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs( _raw_lvs) # Set all self.pvs = _pvs self.pv_path_to_uuid = _pvs_lookup self.vg_name_to_uuid = _vgs_lookup self.lv_full_name_to_uuid = _lvs_lookup self.vgs = _vgs self.lvs = _lvs self.lvs_in_vgs = _lvs_in_vgs self.pvs_in_vgs = _pvs_in_vgs self.lvs_hidden = _lvs_hidden # Create lookup table for which LV and segments are on each PV self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs() if log: log_debug("lvmdb - refresh exit")
def _read_until_prompt(self): stdout = "" report = "" stderr = "" # Try reading from all FDs to prevent one from filling up and causing # a hang. We are also assuming that we won't get the lvm prompt back # until we have already received all the output from stderr and the # report descriptor too. while not stdout.endswith(SHELL_PROMPT): try: rd_fd = [ self.lvm_shell.stdout.fileno(), self.report_r, self.lvm_shell.stderr.fileno() ] ready = select.select(rd_fd, [], [], 2) for r in ready[0]: if r == self.lvm_shell.stdout.fileno(): while True: tmp = self.lvm_shell.stdout.read() if tmp: stdout += tmp.decode("utf-8") else: break elif r == self.report_r: while True: tmp = os.read(self.report_r, 16384) if tmp: report += tmp.decode("utf-8") if len(tmp) != 16384: break elif r == self.lvm_shell.stderr.fileno(): while True: tmp = self.lvm_shell.stderr.read() if tmp: stderr += tmp.decode("utf-8") else: break except IOError as ioe: log_debug(str(ioe)) pass return stdout, report, stderr
def pv_retrieve_with_segs(device=None): d = [] err = "" out = "" rc = 0 columns = [ 'pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free', 'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free', 'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count', 'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name', 'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing' ] # Lvm has some issues where it returns failure when querying pvs when other # operations are in process, see: # https://bugzilla.redhat.com/show_bug.cgi?id=1274085 for i in range(0, 10): cmd = _dc('pvs', ['-o', ','.join(columns)]) if device: cmd.extend(device) rc, out, err = call(cmd) if rc == 0: d = parse_column_names(out, columns) break else: time.sleep(0.2) log_debug("LVM Bug workaround, retrying pvs command...") if rc != 0: msg = "We were unable to get pvs to return without error after " \ "trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \ (rc, err, out) log_error(msg) raise RuntimeError(msg) return d
def pv_retrieve_with_segs(device=None): d = [] err = "" out = "" rc = 0 columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free', 'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free', 'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count', 'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name', 'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing'] # Lvm has some issues where it returns failure when querying pvs when other # operations are in process, see: # https://bugzilla.redhat.com/show_bug.cgi?id=1274085 for i in range(0, 10): cmd = _dc('pvs', ['-o', ','.join(columns)]) if device: cmd.extend(device) rc, out, err = call(cmd) if rc == 0: d = parse_column_names(out, columns) break else: time.sleep(0.2) log_debug("LVM Bug workaround, retrying pvs command...") if rc != 0: msg = "We were unable to get pvs to return without error after " \ "trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \ (rc, err, out) log_error(msg) raise RuntimeError(msg) return d
def call_lvm(command, debug=False, line_cb=None, cb_data=None): """ Call an executable and return a tuple of exitcode, stdout, stderr :param command: Command to execute :param debug: Dump debug to stdout :param line_cb: Call the supplied function for each line read from stdin, CALL MUST EXECUTE QUICKLY and not *block* otherwise call_lvm function will fail to read stdin/stdout. Return value of call back is ignored :param cb_data: Supplied to callback to allow caller access to its own data # Callback signature def my_callback(my_context, line_read_stdin) pass """ # Prepend the full lvm executable so that we can run different versions # in different locations on the same box command.insert(0, cfg.LVM_CMD) command = add_no_notify(command) process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ) stdout_text = "" stderr_text = "" stdout_index = 0 make_non_block(process.stdout) make_non_block(process.stderr) while True: try: rd_fd = [process.stdout.fileno(), process.stderr.fileno()] ready = select.select(rd_fd, [], [], 2) for r in ready[0]: if r == process.stdout.fileno(): stdout_text += read_decoded(process.stdout) elif r == process.stderr.fileno(): stderr_text += read_decoded(process.stderr) if line_cb is not None: # Process the callback for each line read! while True: i = stdout_text.find("\n", stdout_index) if i != -1: try: line_cb(cb_data, stdout_text[stdout_index:i]) except: st = traceback.format_exc() log_error("call_lvm: line_cb exception: \n %s" % st) stdout_index = i + 1 else: break # Check to see if process has terminated, None when running if process.poll() is not None: break except IOError as ioe: log_debug("call_lvm:" + str(ioe)) pass if debug or process.returncode != 0: _debug_c(command, process.returncode, (stdout_text, stderr_text)) return process.returncode, stdout_text, stderr_text
def _read_until_prompt(self, no_output=False): stdout = "" report = "" stderr = "" keep_reading = True extra_passes = 3 report_json = {} prev_report_len = 0 # Try reading from all FDs to prevent one from filling up and causing # a hang. Keep reading until we get the prompt back and the report # FD does not contain valid JSON while keep_reading: try: rd_fd = [ self.lvm_shell.stdout.fileno(), self.report_stream.fileno(), self.lvm_shell.stderr.fileno()] ready = select.select(rd_fd, [], [], 2) for r in ready[0]: if r == self.lvm_shell.stdout.fileno(): stdout += LVMShellProxy._read(self.lvm_shell.stdout) elif r == self.report_stream.fileno(): report += LVMShellProxy._read(self.report_stream) elif r == self.lvm_shell.stderr.fileno(): stderr += LVMShellProxy._read(self.lvm_shell.stderr) # Check to see if the lvm process died on us if self.lvm_shell.poll(): raise Exception(self.lvm_shell.returncode, "%s" % stderr) if stdout.endswith(SHELL_PROMPT): if no_output: keep_reading = False else: cur_report_len = len(report) if cur_report_len != 0: # Only bother to parse if we have more data if prev_report_len != cur_report_len: prev_report_len = cur_report_len # Parse the JSON if it's good we are done, # if not we will try to read some more. try: report_json = json.loads(report) keep_reading = False except ValueError: pass if keep_reading: extra_passes -= 1 if extra_passes <= 0: if len(report): raise ValueError("Invalid json: %s" % report) else: raise ValueError( "lvm returned no JSON output!") except IOError as ioe: log_debug(str(ioe)) pass return stdout, report_json, stderr