Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
def get_configured_ifaces():
    aug = Augeas(flags=Augeas.NO_MODL_AUTOLOAD)
    aug.add_transform('interfaces', '/etc/network/interfaces')
    aug.load()
    base = '/files/etc/network/interfaces'
    for m in aug.match('%s/iface' % base):
        yield aug.get(m)
    aug.close()
Esempio n. 4
0
def _augeas_init():
    if not _directories_inited:
        init_directories()

    global augeas
    augeas = Augeas(loadpath=get_config_path(),
            flags=Augeas.SAVE_BACKUP | Augeas.NO_MODL_AUTOLOAD)

    augeas.set("/augeas/load/Agocontrol/lens", "agocontrol.lns");
    augeas.set("/augeas/load/Agocontrol/incl[1]", get_config_path("conf.d") + "/*.conf");
    augeas.load()
Esempio n. 5
0
 def get_augeas(self, entry):
     """ Get an augeas object for the given entry. """
     if entry.get("name") not in self._augeas:
         aug = Augeas()
         if entry.get("lens"):
             self.logger.debug("Augeas: Adding %s to include path for %s" %
                               (entry.get("name"), entry.get("lens")))
             incl = "/augeas/load/%s/incl" % entry.get("lens")
             ilen = len(aug.match(incl))
             if ilen == 0:
                 self.logger.error("Augeas: Lens %s does not exist" %
                                   entry.get("lens"))
             else:
                 aug.set("%s[%s]" % (incl, ilen + 1), entry.get("name"))
                 aug.load()
         self._augeas[entry.get("name")] = aug
     return self._augeas[entry.get("name")]
Esempio n. 6
0
 def get_augeas(self, entry):
     """ Get an augeas object for the given entry. """
     if entry.get("name") not in self._augeas:
         aug = Augeas()
         if entry.get("lens"):
             self.logger.debug("Augeas: Adding %s to include path for %s" %
                               (entry.get("name"), entry.get("lens")))
             incl = "/augeas/load/%s/incl" % entry.get("lens")
             ilen = len(aug.match(incl))
             if ilen == 0:
                 self.logger.error("Augeas: Lens %s does not exist" %
                                   entry.get("lens"))
             else:
                 aug.set("%s[%s]" % (incl, ilen + 1), entry.get("name"))
                 aug.load()
         self._augeas[entry.get("name")] = aug
     return self._augeas[entry.get("name")]
Esempio n. 7
0
    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()
Esempio n. 8
0
    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()
Esempio n. 9
0
class AugeasWrapper(object):
    """python-augeas higher-level wrapper.

    Load single augeas lens and configuration file.
    Exposes configuration file as AugeasNode object with dict-like interface.

    AugeasWrapper can be used in with statement in the same way as file does.
    """
    def __init__(self,
                 confpath,
                 lens,
                 root=None,
                 loadpath=None,
                 flags=Augeas.NO_MODL_AUTOLOAD | Augeas.NO_LOAD
                 | Augeas.ENABLE_SPAN):
        """Parse configuration file using given lens.

        Params:
            confpath (str): Absolute path to the configuration file
            lens (str): Name of module containing Augeas lens
            root: passed down to original Augeas
            flags: passed down to original Augeas
            loadpath: passed down to original Augeas
            flags: passed down to original Augeas
        """
        log.debug('loadpath: %s', loadpath)
        log.debug('confpath: %s', confpath)
        self._aug = Augeas(root=root, loadpath=loadpath, flags=flags)

        # /augeas/load/{lens}
        aug_load_path = join(AUGEAS_LOAD_PATH, lens)
        # /augeas/load/{lens}/lens = {lens}.lns
        self._aug.set(join(aug_load_path, 'lens'), '%s.lns' % lens)
        # /augeas/load/{lens}/incl[0] = {confpath}
        self._aug.set(join(aug_load_path, 'incl[0]'), confpath)
        self._aug.load()

        errors = self._aug.match(AUGEAS_ERROR_PATH)
        if errors:
            err_msg = '\n'.join(
                ["{}: {}".format(e, self._aug.get(e)) for e in errors])
            raise RuntimeError(err_msg)

        path = join(AUGEAS_FILES_PATH, confpath)
        paths = self._aug.match(path)
        if len(paths) != 1:
            raise ValueError('path %s did not match exactly once' % path)
        self.tree = AugeasNode(self._aug, path)
        self._loaded = True

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.save()
        self.close()

    def save(self):
        """Save Augeas tree to its original file."""
        assert self._loaded
        try:
            self._aug.save()
        except IOError as exc:
            log.exception(exc)
            for err_path in self._aug.match('//error'):
                log.error('%s: %s', err_path,
                          self._aug.get(os.path.join(err_path, 'message')))
            raise

    def close(self):
        """
        close Augeas library

        After calling close() the object must not be used anymore.
        """
        assert self._loaded
        self._aug.close()
        del self._aug
        self._loaded = False

    def match(self, path):
        """Yield AugeasNodes matching given expression."""
        assert self._loaded
        assert path
        log.debug('tree match %s', path)
        for matched_path in self._aug.match(path):
            yield AugeasNode(self._aug, matched_path)
Esempio n. 10
0
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()
Esempio n. 11
0
class AugeasWrap(object):
    _transform = 'interfaces'
    _file = None
    _attrs = []
    _map = {}
    _match = None

    __aug = None

    @property
    def _aug(self):
        if not self.__aug:
            self.__aug = Augeas(flags=Augeas.NO_MODL_AUTOLOAD)
            self.__aug.add_transform(self._transform, self._file)
            self.__aug.load()
        return self.__aug

    _debug = False

    def exists(self):
        return bool(self.get())

    def _abspath(self, path):
        if not path or not (path.startswith('/augeas') or path.startswith('/files') or path.startswith('$')):
            path = '%s%s' % (self._match, path or '')
        return path or ''

    def get(self, path=None):
        ret = self._aug.get(self._abspath(path))
        if self._debug:
            logger.debug('get path=%s value=%s', self._abspath(path), ret)
        return ret

    def set(self, value, path=None):
        value = str(value)
        if self._debug:
            logger.debug('set path=%s value=%s', self._abspath(path), value)
        return self._aug.set(self._abspath(path), value)

    def match(self, path=None):
        if self._debug:
            logger.debug('match path=%s', self._abspath(path))
        return self._aug.match(self._abspath(path))

    def remove(self, path=None):
        if self._debug:
            logger.debug('remove path=%s', self._abspath(path))
        return self._aug.remove(self._abspath(path))

    def insert(self, value, path=None, before=True):
        value = str(value)
        if self._debug:
            logger.debug('insert path=%s value=%s', self._abspath(path), value)
        return self._aug.insert(self._abspath(path), value, before=before)

    def _print(self, path=None):
        path = self._abspath(path)
        get = self.get(path)
        logger.info("[%s] = '%s'", path, get)
        try:
            for match in self.match('%s//*' % path):
                logger.info("[%s] = '%s'", match, self._aug.get(match))
        except RuntimeError:
            pass

    def _all_attrs(self):
        return self._attrs + self._map.keys()
Esempio n. 12
0
class TestNode(unittest.TestCase):
    """Tests the Node class"""

    def setUp(self):
        self.tmp = tempfile.mkdtemp()
        self.root = "%s/root" % self.tmp
        shutil.copytree("%s/fakeroot" % os.path.dirname(__file__), self.root)

        self.aug = Augeas(root=self.root, flags=Augeas.NO_MODL_AUTOLOAD)
        self.aug.add_transform("Nsswitch.lns", "/etc/nsswitch.conf")
        self.aug.load()

        class FakeParent:
            def setpath(self):
                return "/files/etc/nsswitch.conf"
        self.parent = FakeParent()

    def tearDown(self):
        shutil.rmtree(self.tmp)
        self.aug.close()

    def test_setpath_self(self):
        """Test setpath generates path for '.' (itself)"""
        n = aug2cmds.Node(self.aug, self.parent, uniqpaths=["."],
                          path="/files/etc/nsswitch.conf/database[1]")
        self.assertEqual(n.setpath(),
                         "/files/etc/nsswitch.conf/database[.='passwd']")

    def test_setpath_subnode(self):
        """Test setpath generates path for a subnode"""
        n = aug2cmds.Node(self.aug, self.parent, uniqpaths=["service"],
                          path="/files/etc/nsswitch.conf/database[1]")
        self.assertEqual(n.setpath(),
                         "/files/etc/nsswitch.conf/database[service='files']")

    def test_setpath_and(self):
        """Test setpath generates path for multiple subpaths"""
        n = aug2cmds.Node(self.aug, self.parent, uniqpaths=[".", "service"],
                          path="/files/etc/nsswitch.conf/database[1]")
        self.assertEqual(n.setpath(),
          "/files/etc/nsswitch.conf/database[.='passwd' and service='files']")

    def test_basename(self):
        """Test basename understands Augeas paths"""
        self.assertEqual(aug2cmds.Node.basename("/files"), "files")
        self.assertEqual(aug2cmds.Node.basename("/files/test"), "test")
        self.assertEqual(aug2cmds.Node.basename("/files/test[foo]"), "test")
        self.assertEqual(aug2cmds.Node.basename(
                           "/files/test[foo/bar]"), "test")

    def test_dirname(self):
        """Test dirname understands Augeas paths"""
        self.assertEqual(aug2cmds.Node.dirname("/files"), "/")
        self.assertEqual(aug2cmds.Node.dirname("/files/test"), "/files")
        self.assertEqual(aug2cmds.Node.dirname("/files/test[foo]"), "/files")
        self.assertEqual(aug2cmds.Node.dirname(
                           "/files/test[foo/bar]"), "/files")

    def test_children_none(self):
        """Test when there are no children"""
        n = aug2cmds.Node(self.aug, self.parent,
                          "/files/etc/nsswitch.conf/#comment[1]", ["."])
        self.assertRaises(StopIteration, next, n.children())

    def test_children(self):
        """Test new Node objects are created for children"""
        n = aug2cmds.Node(self.aug, self.parent,
                          "/files/etc/nsswitch.conf/database[15]", ["."])
        c = n.children()
        sn = c.next()
        self.assertEqual(sn.path,
          "/files/etc/nsswitch.conf/database[15]/service[1]")
        self.assertEqual(sn.setpath(),
          "/files/etc/nsswitch.conf/database[.='aliases']/service[.='files']")

        sn = c.next()
        self.assertEqual(sn.path,
          "/files/etc/nsswitch.conf/database[15]/service[2]")
        self.assertEqual(sn.setpath(),
          "/files/etc/nsswitch.conf/database[.='aliases']/service[.='nisplus']")

        self.assertRaises(StopIteration, next, c)

    def test_value(self):
        """Test value is retrieved"""
        n = aug2cmds.Node(self.aug, self.parent, uniqpaths=["."],
                          path="/files/etc/nsswitch.conf/database[1]")
        self.assertEqual(n.value(), "passwd")

    def test_value_none(self):
        """Test when no value is set"""
        n = aug2cmds.Node(self.aug, self.parent, uniqpaths=["."],
                          path="/files/etc/nsswitch.conf")
        self.assertEqual(n.value(), None)
Esempio n. 13
0
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)