def configure_chrony(ntp_servers, ntp_pool=None, fstore=None, sysstore=None, debug=False): """ This method only configures chrony client with ntp_servers or ntp_pool """ module = "chrony" if sysstore: sysstore.backup_state(module, "enabled", services.knownservices.chronyd.is_enabled()) aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD, loadpath=paths.USR_SHARE_IPA_DIR) try: logger.debug("Configuring chrony") chrony_conf = os.path.abspath(paths.CHRONY_CONF) aug.transform(module, chrony_conf) # loads chrony lens file aug.load() # loads augeas tree # augeas needs to prepend path with '/files' path = '/files{path}'.format(path=chrony_conf) # remove possible conflicting configuration of servers aug.remove('{}/server'.format(path)) aug.remove('{}/pool'.format(path)) aug.remove('{}/peer'.format(path)) if ntp_pool: logger.debug("Setting server pool:") logger.debug("'%s'", ntp_pool) aug.set('{}/pool[last()+1]'.format(path), ntp_pool) aug.set('{}/pool[last()]/iburst'.format(path), None) if ntp_servers: logger.debug("Setting time servers:") for server in ntp_servers: aug.set('{}/server[last()+1]'.format(path), server) aug.set('{}/server[last()]/iburst'.format(path), None) logger.debug("'%s'", server) # backup oginal conf file logger.debug("Backing up '%s'", chrony_conf) __backup_config(chrony_conf, fstore) logger.debug("Writing configuration to '%s'", chrony_conf) aug.save() logger.info('Configuration of chrony was changed by installer.') configured = True except IOError: logger.error("Augeas failed to configure file %s", chrony_conf) configured = False except RuntimeError as e: logger.error("Configuration failed with: %s", e) configured = False finally: aug.close() tasks.restore_context(chrony_conf) return configured
def remove(path): ''' Get matches for path expression CLI Example: .. code-block:: bash salt '*' augeas.remove /files/etc/sysctl.conf/net.ipv4.conf.all.log_martians ''' aug = Augeas() ret = {'retval': False} try: count = aug.remove(path) aug.save() if count == -1: ret['error'] = 'Invalid node' else: ret['retval'] = True except (RuntimeError, IOError) as err: ret['error'] = str(err) ret['count'] = count return ret
def remove(path): ''' Get matches for path expression CLI Example:: salt '*' augeas.remove /files/etc/sysctl.conf/net.ipv4.conf.all.log_martians ''' from augeas import Augeas aug = Augeas() ret = {'retval': False} try: count = aug.remove(path) aug.save() if count == -1: ret['error'] = 'Invalid node' else: ret['retval'] = True except (RuntimeError, IOError) as err: ret['error'] = str(err) ret['count'] = count return ret
def rm(self,entryPath,param='',hierarchy='/files'): """Delete a parameter (and all its children) in a config. file, with the help of Augeas, a configuration API (cf http://augeas.net)""" try: from augeas import Augeas aug=Augeas() except Exception, e: return str(e) path=(hierarchy+entryPath.rstrip('/')+'/'+param).rstrip('/') try: result=aug.remove(path) #aug.close() except Exception, e: return str(e) # Here is a little workaround for a bug in save for augeas. # In the future this should not be necessary anymore. try: aug.save() except: pass # End of workaround try: aug.save() except Exception, e: return str(e) if result == -1: msg = 'Invalid node' else: msg = repr(result)+' node(s) removed.' return msg
def remove(path): """ Get matches for path expression CLI Example:: salt '*' augeas.remove /files/etc/sysctl.conf/net.ipv4.conf.all.log_martians """ from augeas import Augeas aug = Augeas() ret = {"retval": False} try: count = aug.remove(path) aug.save() if count == -1: ret["error"] = "Invalid node" else: ret["retval"] = True except (RuntimeError, IOError) as err: ret["error"] = str(err) ret["count"] = count return ret
def remove(name, values): ret = {"name": name, "result": True, "changes": {}, "comment": ""} from augeas import Augeas if len(values) < 1: ret["comment"] = "No values given" ret["result"] = False return ret if __opts__["test"]: aug = Augeas(flags=Augeas.SAVE_NEWFILE) sfn = name dfn = "%s.augnew" % name else: aug = Augeas(flags=Augeas.SAVE_BACKUP) sfn = "%s.augsave" % name dfn = name if not os.path.isfile(name): ret["comment"] = "Unable to find file '%s'" % name ret["result"] = False return ret for value in values: try: path = "/files%s/%s" % (name, value) aug.remove(path) except TypeError as e: ret["comment"] = "Error removing, wrong type\n" "Expression was '%s'" % path ret["result"] = False return ret try: aug.save() except IOError as e: ret["comment"] = str(e) ret["result"] = False return ret ret.update(_resolve_changes(sfn, dfn)) return ret
def __disable_mod_ssl_ocsp(self): aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD) aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') aug.set('/augeas/load/Httpd/incl', paths.HTTPD_SSL_CONF) aug.load() path = '/files{}/VirtualHost'.format(paths.HTTPD_SSL_CONF) ocsp_path = '{}/directive[.="{}"]'.format(path, OCSP_DIRECTIVE) ocsp_arg = '{}/arg'.format(ocsp_path) ocsp_comment = '{}/#comment[.="{}"]'.format(path, OCSP_DIRECTIVE) ocsp_dir = aug.get(ocsp_path) # there is SSLOCSPEnable directive in nss.conf file, comment it # otherwise just do nothing if ocsp_dir is not None: ocsp_state = aug.get(ocsp_arg) aug.remove(ocsp_arg) aug.rename(ocsp_path, '#comment') aug.set(ocsp_comment, '{} {}'.format(OCSP_DIRECTIVE, ocsp_state)) aug.save()
class LVMConfig(object): def __init__(self, path="/etc/lvm/lvm.conf"): self.path = path # Augeas loads by default tons of unneeded lenses and configuration # files. On my test host, it fails to load, trying to read my 500 MiB # /etc/lvm/archive/. # # These are the standard LVM lens includes: # /augeas/load/LVM/incl[1] /etc/lvm/lvm.conf # /augeas/load/LVM/incl[2] /etc/lvm/backup/* # /augeas/load/LVM/incl[3] /etc/lvm/archive/*.vg # # We need only the first entry to work with lvm.conf. Using customized # load setup, as explained in # https://github.com/hercules-team/augeas/wiki/Loading-specific-files # # Removing the archive and backup entries, we can load augeas in 0.7 # seconds on my test vm. Removing all other lenses shorten the time to # 0.04 seconds. log.debug("Loading LVM configuration from %r", path) self.aug = Augeas(flags=Augeas.NO_MODL_AUTOLOAD | Augeas.SAVE_BACKUP) self.aug.add_transform("lvm.lns", [path]) self.aug.load() # Context manager interface def __enter__(self): return self def __exit__(self, t, v, tb): try: self.close() except Exception as e: # Caller succeeded, raise the close error. if t is None: raise # Caller has failed, do not hide the original error. log.exception("Error closing %s: %s" % (self, e)) # Accessing list of strings def getlist(self, section, option): pat = "/files%s/%s/dict/%s/list/*/str" % (self.path, section, option) matches = self.aug.match(pat) if not matches: return None # Cannot store/read empty list return [self.aug.get(m) for m in matches] def setlist(self, section, option, value): log.debug("Setting %s/%s to %s", section, option, value) opt_path = "/files%s/%s/dict/%s" % (self.path, section, option) self.aug.remove(opt_path) item_path = opt_path + "/list/%d/str" for i, item in enumerate(value, 1): self.aug.set(item_path % i, item) # Accessing flat values (int, string) def getint(self, section, option): val = self._get_flat(section, option, "int") return int(val) if val is not None else None def setint(self, section, option, value): self._set_flat(section, option, "int", str(value)) def getstr(self, section, option): return self._get_flat(section, option, "str") def setstr(self, section, option, value): self._set_flat(section, option, "str", value) def _get_flat(self, section, option, opt_type): path = self._flat_path(section, option, opt_type) return self.aug.get(path) def _set_flat(self, section, option, opt_type, value): log.debug("Setting %s/%s to %r", section, option, value) path = self._flat_path(section, option, opt_type) return self.aug.set(path, value) def _flat_path(self, section, option, opt_type): return "/files%s/%s/dict/%s/%s" % ( self.path, section, option, opt_type) # Removing options def remove(self, section, option): log.debug("Removing %s/%s", section, option) path = "/files%s/%s/dict/%s" % (self.path, section, option) self.aug.remove(path) # File operations def save(self): log.info("Saving new LVM configuration to %r, previous configuration " "saved to %r", self.path, self.path + ".augsave") self.aug.save() def close(self): log.debug("Closing LVM configuration %s", self.path) self.aug.close()
class HAProxyConfManager(object): conf_path = 'etc/haproxy/haproxy.cfg' def __init__(self, root_path=None): if root_path is None: root_path = '/' self.conf_path = root_path + self.conf_path self._conf_xpath = '/files' + self.conf_path + '/' self._augeas = Augeas(root=root_path, loadpath=HAPROXY_LENS_DIR) def load(self): LOG.debug('Loading haproxy.conf') self._augeas.load() def save(self): LOG.debug('Saving haproxy.conf') self._augeas.save() def get(self, xpath): """ Returns values of label at given xpath. If label is presented but has no value, returns True xpath is relative to haproxy.cfg file """ if self._augeas.match(self._conf_xpath + xpath) == []: return None value = self._augeas.get(self._conf_xpath + xpath) return value if value is not None else True def _find_xpath_gen(self, base_xpath, sublabel, value_pattern): section_xpaths = self._augeas.match(self._conf_xpath + base_xpath) for xpath in section_xpaths: match = re.search(value_pattern, self._augeas.get(xpath + '/' + sublabel)) if match != None: yield xpath.replace(self._conf_xpath, '') def find_all_xpaths(self, base_xpath, sublabel, value_pattern): """ Returns list of all labels from given base_xpath which sublabel matches `value_pattern` `value_pattern` is regexp This metod is useful when you need to find certain section from config that contains number of such sections (listen[1], listen[2]...) ..Example: cnf.get_matched_xpaths('listen', 'name', 'test*') this will find every listen whose name begins with 'test' """ return list(self._find_xpath_gen(base_xpath, sublabel, value_pattern)) def find_one_xpath(self, base_xpath, sublabel, value_pattern): """ Returns label xpath by given value_pattern of sublabel. Returns None if no label is found. This metod is useful when you need to find certain section from config that contains number of such sections (listen[1], listen[2]...) """ try: return self._find_xpath_gen(base_xpath, sublabel, value_pattern).next() except StopIteration: return None def get_all_xpaths(self, base_xpath): return [ x.replace(self._conf_xpath, '') for x in self._augeas.match(self._conf_xpath + base_xpath) ] def set(self, xpath, value=None, save_conf=True): """ Sets label at given xpath with given value. If there is no label - creates one. If there is - updates its value. `value` can be None/True to set label without actual value or string or iterable or dict to set number of sublabels at once. `xpath` is relative to haproxy.cfg file. """ LOG.debug('Setting %s with value: %s' % (xpath, value)) if isinstance(value, dict): self._augeas.set(self._conf_xpath + xpath, None) for k, v in value.items(): self.set(xpath + '/' + k, v, save_conf=False) elif hasattr(value, '__iter__'): for v in value: self.add(xpath, v, save_conf=False) else: if value == True: value = None elif value == False: return self.remove(xpath) elif value is not None: value = str(value) self._augeas.set(self._conf_xpath + xpath, value) if save_conf: self.save() def add(self, xpath, value=None, save_conf=True): """ Adds node at given xpath. New nodes are appended xpath is relative to haproxy.cfg file Returns xpath of created node """ nodes_qty = len(self._augeas.match(self._conf_xpath + xpath)) if nodes_qty != 0: xpath += '[%s]' % (nodes_qty + 1) self.set(xpath, value, save_conf) return xpath def insert(self, xpath, label, value=None, before=True): """ Inserts label before or after given in xpath xpath is relative to haproxy.cfg file """ xpath = self._conf_xpath + xpath self._augeas.insert(xpath, label, before) if value is not None: labels = self._augeas.match(os.path.dirname(xpath)) base_label = os.path.basename(xpath) inserted_xpath = None if label == base_label: if xpath.endswith(']'): inserted_xpath = xpath if before else labels[ labels.index(xpath) + 1] else: inserted_xpath += '[1]' if before else '[2]' else: index = labels.index(xpath) + (-1 if before else 1) inserted_xpath = labels[index] self.set(inserted_xpath.replace(self._conf_xpath, ''), value) def add_conf(self, conf, append=False): """ Append raw conf to the end of haproxy.conf file or insert at the beginning before everything """ LOG.debug('Adding raw conf part to haproxy.conf:\n%s' % conf) raw = None with open(self.conf_path, 'r') as conf_file: raw = conf_file.read() if not conf.endswith('\n'): conf += '\n' raw = '\n'.join((raw, conf) if append else (conf, raw)) with open(self.conf_path, 'w') as conf_file: conf_file.write(raw) self.load() def extend_section(self, conf, section_name): """ Appends raw conf to the section with given name """ LOG.debug( 'Adding raw conf part to section of haproxy.conf with name %s :\n%s' % (section_name, conf)) raw = None with open(self.conf_path, 'r') as conf_file: raw = conf_file.read() if conf.endswith('\n'): conf = conf[:-1] # reindenting conf conf = dedent(conf) conf = ' ' + conf.replace('\n', '\n ') raw = re.sub(section_name + r'\s*\n', '%s\n%s\n' % (section_name, conf), raw) with open(self.conf_path, 'w') as conf_file: conf_file.write(raw) self.load() def remove(self, xpath): LOG.debug('Removing %s' % xpath) return self._augeas.remove(self._conf_xpath + xpath)