diff options
Diffstat (limited to 'geo-replication/syncdaemon/configinterface.py')
-rw-r--r-- | geo-replication/syncdaemon/configinterface.py | 434 |
1 files changed, 0 insertions, 434 deletions
diff --git a/geo-replication/syncdaemon/configinterface.py b/geo-replication/syncdaemon/configinterface.py deleted file mode 100644 index a59dee7a4a..0000000000 --- a/geo-replication/syncdaemon/configinterface.py +++ /dev/null @@ -1,434 +0,0 @@ -# -# Copyright (c) 2011-2014 Red Hat, Inc. <http://www.redhat.com> -# This file is part of GlusterFS. - -# This file is licensed to you under your choice of the GNU Lesser -# General Public License, version 3 or any later version (LGPLv3 or -# later), or the GNU General Public License, version 2 (GPLv2), in all -# cases as published by the Free Software Foundation. -# - -try: - import ConfigParser -except ImportError: - # py 3 - import configparser as ConfigParser -import re -from string import Template -import os -import errno -import sys -from stat import ST_DEV, ST_INO, ST_MTIME -import tempfile -import shutil - -from syncdutils import escape, unescape, norm, update_file, GsyncdError -from conf import GLUSTERD_WORKDIR, LOCALSTATEDIR - -SECT_ORD = '__section_order__' -SECT_META = '__meta__' -config_version = 2.0 - -re_type = type(re.compile('')) - -TMPL_CONFIG_FILE = GLUSTERD_WORKDIR + "/geo-replication/gsyncd_template.conf" - -# (SECTION, OPTION, OLD VALUE, NEW VALUE) -CONFIGS = ( - ("peersrx . .", - "georep_session_working_dir", - "", - GLUSTERD_WORKDIR + "/geo-replication/${mastervol}_${remotehost}_" - "${slavevol}/"), - ("peersrx .", - "gluster_params", - "aux-gfid-mount xlator-option=\*-dht.assert-no-child-down=true", - "aux-gfid-mount"), - ("peersrx .", - "gluster_params", - "aux-gfid-mount", - "aux-gfid-mount acl"), - ("peersrx . .", - "ssh_command_tar", - "", - "ssh -oPasswordAuthentication=no -oStrictHostKeyChecking=no " - "-i " + GLUSTERD_WORKDIR + "/geo-replication/tar_ssh.pem"), - ("peersrx . .", - "changelog_log_file", - "", - "${iprefix}/log/glusterfs/geo-replication/${mastervol}" - "/${eSlave}${local_id}-changes.log"), - ("peersrx . .", - "working_dir", - LOCALSTATEDIR + "/run/gluster/${mastervol}/${eSlave}", - "${iprefix}/lib/misc/glusterfsd/${mastervol}/${eSlave}"), - ("peersrx . .", - "ignore_deletes", - "true", - "false"), - ("peersrx . .", - "pid-file", - GLUSTERD_WORKDIR + "/geo-replication/${mastervol}_${remotehost}_" - "${slavevol}/${eSlave}.pid", - GLUSTERD_WORKDIR + "/geo-replication/${mastervol}_${remotehost}_" - "${slavevol}/monitor.pid"), - ("peersrx . .", - "state-file", - GLUSTERD_WORKDIR + "/geo-replication/${mastervol}_${remotehost}_" - "${slavevol}/${eSlave}.status", - GLUSTERD_WORKDIR + "/geo-replication/${mastervol}_${remotehost}_" - "${slavevol}/monitor.status"), - ("peersrx .", - "log_file", - "${iprefix}/log/glusterfs/geo-replication-slaves/${session_owner}:${eSlave}.log", - "${iprefix}/log/glusterfs/geo-replication-slaves/${session_owner}:${local_node}${local_id}.${slavevol}.log"), - ("peersrx .", - "log_file_mbr", - "${iprefix}/log/glusterfs/geo-replication-slaves/mbr/${session_owner}:${eSlave}.log", - "${iprefix}/log/glusterfs/geo-replication-slaves/mbr/${session_owner}:${local_node}${local_id}.${slavevol}.log"), - ("peersrx .", - "gluster_log_file", - "${iprefix}/log/glusterfs/geo-replication-slaves/${session_owner}:${eSlave}.gluster.log", - "${iprefix}/log/glusterfs/geo-replication-slaves/${session_owner}:${local_node}${local_id}.${slavevol}.gluster.log") -) - - -def upgrade_config_file(path, confdata): - config_change = False - config = ConfigParser.RawConfigParser() - # If confdata.rx present then glusterd is adding config values, - # it will create config file if not exists. config.read is fine in - # this case since any other error will be raised during write. - if getattr(confdata, "rx", False): - config.read(path) - else: - with open(path) as fp: - config.readfp(fp) - - for sec, opt, oldval, newval in CONFIGS: - try: - val = config.get(sec, opt) - except ConfigParser.NoOptionError: - # if new config opt not exists - config_change = True - config.set(sec, opt, newval) - continue - except ConfigParser.Error: - """ - When gsyncd invoked at the time of create, config file - will not be their. Ignore any ConfigParser errors - """ - continue - - if val == newval: - # value is same as new val - continue - - if val == oldval: - # config value needs update - config_change = True - config.set(sec, opt, newval) - - # To convert from old peers section format to new peers section format. - # Old format: peers gluster://<master ip>:<master vol> \ - # ssh://root@<slave ip>:gluster://<master ip>:<slave vol> - # New format: peers <master vol name> <slave vol name> - for old_sect in config.sections(): - if old_sect.startswith("peers "): - peers_data = old_sect.split(" ") - mvol = peers_data[1].split("%3A")[-1] - svol = peers_data[2].split("%3A")[-1] - new_sect = "peers {0} {1}".format(mvol, svol) - - if old_sect == new_sect: - # Already in new format "peers mastervol slavevol" - continue - - # Create new section if not exists - try: - config.add_section(new_sect) - except ConfigParser.DuplicateSectionError: - pass - - config_change = True - # Add all the items of old_sect to new_sect - for key, val in config.items(old_sect): - config.set(new_sect, key, val) - - # Delete old section - config.remove_section(old_sect) - - if config_change: - tempConfigFile = tempfile.NamedTemporaryFile(mode="wb", delete=False) - with open(tempConfigFile.name, 'wb') as configFile: - config.write(configFile) - - # If src and dst are two different file system, then os.rename - # fails, In this case if temp file created in /tmp and if /tmp is - # separate fs then os.rename gives following error, so use shutil - # OSError: [Errno 18] Invalid cross-device link - # mail.python.org/pipermail/python-list/2005-February/342893.html - shutil.move(tempConfigFile.name, path) - - -class MultiDict(object): - - """a virtual dict-like class which functions as the union - of underlying dicts""" - - def __init__(self, *dd): - self.dicts = dd - - def __getitem__(self, key): - val = None - for d in self.dicts: - if d.get(key) is not None: - val = d[key] - if val is None: - raise KeyError(key) - return val - - -class GConffile(object): - - """A high-level interface to ConfigParser which flattens the two-tiered - config layout by implenting automatic section dispatch based on initial - parameters. - - Also ensure section ordering in terms of their time of addition -- a compat - hack for Python < 2.7. - """ - - def _normconfig(self): - """normalize config keys by s/-/_/g""" - for n, s in self.config._sections.items(): - if n.find('__') == 0: - continue - s2 = type(s)() - for k, v in s.items(): - if k.find('__') != 0: - k = norm(k) - s2[k] = v - self.config._sections[n] = s2 - - def __init__(self, path, peers, confdata, *dd): - """ - - .path: location of config file - - .config: underlying ConfigParser instance - - .peers: on behalf of whom we flatten .config - (master, or master-slave url pair) - - .auxdicts: template subtituents - """ - self.peers = peers - self.path = path - self.auxdicts = dd - self.config = ConfigParser.RawConfigParser() - if getattr(confdata, "rx", False): - self.config.read(path) - else: - with open(path) as fp: - self.config.readfp(fp) - - self.dev, self.ino, self.mtime = -1, -1, -1 - self._normconfig() - - def _load(self): - try: - sres = os.stat(self.path) - self.dev = sres[ST_DEV] - self.ino = sres[ST_INO] - self.mtime = sres[ST_MTIME] - except (OSError, IOError): - if sys.exc_info()[1].errno == errno.ENOENT: - sres = None - - self.config = ConfigParser.RawConfigParser() - with open(self.path) as fp: - self.config.readfp(fp) - self._normconfig() - - def get_realtime(self, opt, default_value=None): - try: - sres = os.stat(self.path) - except (OSError, IOError): - if sys.exc_info()[1].errno == errno.ENOENT: - sres = None - else: - raise - - # compare file system stat with that of our stream file handle - if not sres or sres[ST_DEV] != self.dev or \ - sres[ST_INO] != self.ino or self.mtime != sres[ST_MTIME]: - self._load() - - return self.get(opt, printValue=False, default_value=default_value) - - def section(self, rx=False): - """get the section name of the section representing .peers - in .config""" - peers = self.peers - if not peers: - peers = ['.', '.'] - rx = True - if rx: - return ' '.join(['peersrx'] + [escape(u) for u in peers]) - else: - return ' '.join(['peers'] + [u.split(':')[-1] for u in peers]) - - @staticmethod - def parse_section(section): - """retrieve peers sequence encoded by section name - (as urls or regexen, depending on section type) - """ - sl = section.split() - st = sl.pop(0) - sl = [unescape(u) for u in sl] - if st == 'peersrx': - sl = [re.compile(u) for u in sl] - return sl - - def ord_sections(self): - """Return an ordered list of sections. - - Ordering happens based on the auxiliary - SECT_ORD section storing indices for each - section added through the config API. - - To not to go corrupt in case of manually - written config files, we take care to append - also those sections which are not registered - in SECT_ORD. - - Needed for python 2.{4,5,6} where ConfigParser - cannot yet order sections/options internally. - """ - so = {} - if self.config.has_section(SECT_ORD): - so = self.config._sections[SECT_ORD] - so2 = {} - for k, v in so.items(): - if k != '__name__': - so2[k] = int(v) - tv = 0 - if so2: - tv = max(so2.values()) + 1 - ss = [s for s in self.config.sections() if s.find('__') != 0] - for s in ss: - if s in so.keys(): - continue - so2[s] = tv - tv += 1 - - def scmp(x, y): - return cmp(*(so2[s] for s in (x, y))) - ss.sort(scmp) - return ss - - def update_to(self, dct, allow_unresolved=False): - """update @dct from key/values of ours. - - key/values are collected from .config by filtering the regexp sections - according to match, and from .section. The values are treated as - templates, which are substituted from .auxdicts and (in case of regexp - sections) match groups. - """ - if not self.peers: - raise GsyncdError('no peers given, cannot select matching options') - - def update_from_sect(sect, mud): - for k, v in self.config._sections[sect].items(): - # Template expects String to be passed - # if any config value is not string then it - # fails with ValueError - v = "{0}".format(v) - - if k == '__name__': - continue - if allow_unresolved: - dct[k] = Template(v).safe_substitute(mud) - else: - dct[k] = Template(v).substitute(mud) - - for sect in self.ord_sections(): - sp = self.parse_section(sect) - if isinstance(sp[0], re_type) and len(sp) == len(self.peers): - match = True - mad = {} - for i in range(len(sp)): - m = sp[i].search(self.peers[i]) - if not m: - match = False - break - for j in range(len(m.groups())): - mad['match%d_%d' % (i + 1, j + 1)] = m.groups()[j] - if match: - update_from_sect(sect, MultiDict(dct, mad, *self.auxdicts)) - if self.config.has_section(self.section()): - update_from_sect(self.section(), MultiDict(dct, *self.auxdicts)) - - def get(self, opt=None, printValue=True, default_value=None): - """print the matching key/value pairs from .config, - or if @opt given, the value for @opt (according to the - logic described in .update_to) - """ - d = {} - self.update_to(d, allow_unresolved=True) - if opt: - opt = norm(opt) - v = d.get(opt, default_value) - - if printValue: - if v is not None: - print(v) - else: - return v - else: - for k, v in d.iteritems(): - if k == '__name__': - continue - print("%s: %s" % (k, v)) - - def write(self, trfn, opt, *a, **kw): - """update on-disk config transactionally - - @trfn is the transaction function - """ - def mergeconf(f): - self.config = ConfigParser.RawConfigParser() - self.config.readfp(f) - self._normconfig() - if not self.config.has_section(SECT_META): - self.config.add_section(SECT_META) - self.config.set(SECT_META, 'version', config_version) - return trfn(norm(opt), *a, **kw) - - def updateconf(f): - self.config.write(f) - update_file(self.path, updateconf, mergeconf) - - def _set(self, opt, val, rx=False): - """set @opt to @val in .section""" - sect = self.section(rx) - if not self.config.has_section(sect): - self.config.add_section(sect) - # regarding SECT_ORD, cf. ord_sections - if not self.config.has_section(SECT_ORD): - self.config.add_section(SECT_ORD) - self.config.set( - SECT_ORD, sect, len(self.config._sections[SECT_ORD])) - self.config.set(sect, opt, val) - return True - - def set(self, opt, *a, **kw): - """perform ._set transactionally""" - self.write(self._set, opt, *a, **kw) - - def _delete(self, opt, rx=False): - """delete @opt from .section""" - sect = self.section(rx) - if self.config.has_section(sect): - return self.config.remove_option(sect, opt) - - def delete(self, opt, *a, **kw): - """perform ._delete transactionally""" - self.write(self._delete, opt, *a, **kw) |