>From 4d420d8582d7624a1453f17d10f77b539ca42541 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 18 Nov 2009 16:04:38 +0100 Subject: [PATCH 1/2] Convert SSSDConfig API to ipachangeconf --- server/config/SSSDConfig.py | 114 ++++++++++++++------------ server/config/SSSDConfigTest.py | 12 ++- server/config/etc/sssd.api.d/sssd-local.conf | 3 +- server/config/ipachangeconf.py | 60 +++++++++++++- server/config/upgrade_config.py | 16 +--- 5 files changed, 130 insertions(+), 75 deletions(-) diff --git a/server/config/SSSDConfig.py b/server/config/SSSDConfig.py index 162354b..daf04c7 100644 --- a/server/config/SSSDConfig.py +++ b/server/config/SSSDConfig.py @@ -7,7 +7,7 @@ Created on Sep 18, 2009 import os import gettext import exceptions -from ConfigParser import RawConfigParser, NoSectionError +from ipachangeconf import SSSDChangeConf # Exceptions class SSSDConfigException(Exception): pass @@ -144,15 +144,15 @@ option_strings = { 'proxy_pam_target' : _('PAM stack to use') } -class SSSDConfigSchema(RawConfigParser): +class SSSDConfigSchema(SSSDChangeConf): def __init__(self, schemafile, schemaplugindir): + SSSDChangeConf.__init__(self) #TODO: get these from a global setting if not schemafile: schemafile = '/etc/sssd/sssd.api.conf' if not schemaplugindir: schemaplugindir = '/etc/sssd/sssd.api.d' - RawConfigParser.__init__(self, None, dict) try: #Read the primary config file fd = open(schemafile, 'r') @@ -165,7 +165,7 @@ class SSSDConfigSchema(RawConfigParser): fd.close() except IOError: raise - except: + except SyntaxError: # can be raised with readfp raise ParsingError # Set up lookup table for types @@ -200,43 +200,43 @@ class SSSDConfigSchema(RawConfigParser): # Parse values parsed_options = {} - for option in options: - unparsed_option = self.get(section, option) + for option in self.strip_comments_empty(options): + unparsed_option = option['value'] split_option = self._striplist(unparsed_option.split(',')) optionlen = len(split_option) primarytype = self.type_lookup[split_option[PRIMARY_TYPE]] subtype = self.type_lookup[split_option[SUBTYPE]] - if option_strings.has_key(option): - desc = option_strings[option] + if option_strings.has_key(option['name']): + desc = option_strings[option['name']] else: desc = None if optionlen == 2: # This option has no defaults - parsed_options[option] = \ + parsed_options[option['name']] = \ (primarytype, subtype, desc, None) elif optionlen == 3: if type(split_option[DEFAULT]) == primarytype: - parsed_options[option] = \ + parsed_options[option['name']] = \ (primarytype, subtype, desc, split_option[DEFAULT]) elif primarytype == list: if (type(split_option[DEFAULT]) == subtype): - parsed_options[option] = \ + parsed_options[option['name']] = \ (primarytype, subtype, desc, [split_option[DEFAULT]]) else: try: - parsed_options[option] = \ + parsed_options[option['name']] = \ (primarytype, subtype, desc, @@ -245,7 +245,7 @@ class SSSDConfigSchema(RawConfigParser): raise ParsingError else: try: - parsed_options[option] = \ + parsed_options[option['name']] = \ (primarytype, subtype, desc, @@ -265,7 +265,7 @@ class SSSDConfigSchema(RawConfigParser): raise ParsingError else: fixed_options.extend([x]) - parsed_options[option] = \ + parsed_options[option['name']] = \ (primarytype, subtype, desc, @@ -297,16 +297,16 @@ class SSSDConfigSchema(RawConfigParser): return defaults def get_services(self): - service_list = [x for x in self.sections() - if x != 'service' and - not x.startswith('domain') and - not x.startswith('provider')] + service_list = [x['name'] for x in self.sections() + if x['name'] != 'service' and + not x['name'].startswith('domain') and + not x['name'].startswith('provider')] return service_list def get_providers(self): providers = {} - for section in self._sections: - splitsection = section.split('/') + for section in self.sections(): + splitsection = section['name'].split('/') if (splitsection[0] == 'provider'): if(len(splitsection) == 3): if not providers.has_key(splitsection[1]): @@ -862,7 +862,7 @@ class SSSDDomain: self.providers.remove((provider,provider_type)) -class SSSDConfig(RawConfigParser): +class SSSDConfig(SSSDChangeConf): """ class SSSDConfig Primary class for operating on SSSD configurations @@ -891,7 +891,7 @@ class SSSDConfig(RawConfigParser): The main schema file or one of those in the plugin directory could not be parsed. """ - RawConfigParser.__init__(self, None, dict) + SSSDChangeConf.__init__(self) self.schema = SSSDConfigSchema(schemafile, schemaplugindir) self.configfile = None self.initialized = False @@ -995,8 +995,9 @@ class SSSDConfig(RawConfigParser): outputfile = self.configfile # open() will raise IOError if it fails - of = open(outputfile, 'w') - RawConfigParser.write(self, of) + of = open(outputfile, "wb") + output = self.dump(self.opts) + of.write(output) of.close() def list_services(self): @@ -1014,8 +1015,8 @@ class SSSDConfig(RawConfigParser): if not self.initialized: raise NotInitializedError - service_list = [x for x in self.sections() - if not x.startswith('domain')] + service_list = [x['name'] for x in self.sections() + if not x['name'].startswith('domain') ] return service_list def get_service(self, name): @@ -1042,8 +1043,8 @@ class SSSDConfig(RawConfigParser): raise NoServiceError service = SSSDService(name, self.schema) - [service.set_option(option, value) - for (option,value) in self.items(name)] + [service.set_option(opt['name'], opt['value']) + for opt in self.strip_comments_empty(self.options(name)) ] return service @@ -1093,7 +1094,7 @@ class SSSDConfig(RawConfigParser): """ if not self.initialized: raise NotInitializedError - self.remove_section(name) + self.delete_option('section', name) def save_service(self, service): """ @@ -1121,17 +1122,19 @@ class SSSDConfig(RawConfigParser): # Ensure that the existing section is removed # This way we ensure that we are getting a # complete copy of the service. - # remove_section() is a noop if the section + # delete_option() is a noop if the section # does not exist. - self.remove_section(name) - self.add_section(name) - option_dict = service.get_all_options() - for option in option_dict.keys(): - value = option_dict[option] + index = self.delete_option('section', name) + + addkw = [] + for option,value in service.get_all_options().items(): if (type(value) == list): value = ', '.join(value) + addkw.append( { 'type' : 'option', + 'name' : option, + 'value' : str(value) } ) - self.set(name, option, value) + self.add_section(name, addkw, index) def _striplist(self, l): """ @@ -1201,7 +1204,7 @@ class SSSDConfig(RawConfigParser): """ if not self.initialized: raise NotInitializedError - domains = [x[7:] for x in self.sections() if x.startswith('domain/')] + domains = [x['name'][7:] for x in self.sections() if x['name'].startswith('domain/')] return domains def get_domain(self, name): @@ -1231,14 +1234,14 @@ class SSSDConfig(RawConfigParser): # Read in the providers first or we may have type # errors trying to read in their options - providers = [x for x in self.items('domain/%s' % name) - if x[0].rfind('_provider') > 0] + providers = [ (x['name'],x['value']) for x in self.strip_comments_empty(self.options('domain/%s' % name)) + if x['name'].rfind('_provider') > 0] [domain.set_option(option, value) for (option, value) in providers] - [domain.set_option(option, value) - for (option,value) in self.items('domain/%s' % name) - if (option,value) not in providers] + [domain.set_option(opt['name'], opt['value']) + for opt in self.strip_comments_empty(self.options('domain/%s' % name)) + if opt not in providers] return domain @@ -1284,7 +1287,7 @@ class SSSDConfig(RawConfigParser): """ if not self.initialized: raise NotInitializedError - self.remove_section('domain/%s' % name) + self.delete_option('section', 'domain/%s' % name) def save_domain(self, domain): """ @@ -1315,20 +1318,23 @@ class SSSDConfig(RawConfigParser): # Ensure that the existing section is removed # This way we ensure that we are getting a # complete copy of the service. - # remove_section() is a noop if the section + # delete_option() is a noop if the section # does not exist. - self.remove_section(sectionname) - self.add_section(sectionname) - option_dict = domain.get_all_options() - [self.set(sectionname, option, option_dict[option]) - for option in option_dict.keys()] + index = self.delete_option('section', sectionname) + addkw = [] + for option,value in domain.get_all_options().items(): + if (type(value) == list): + value = ', '.join(value) + addkw.append( { 'type' : 'option', + 'name' : option, + 'value' : str(value) } ) + self.add_section(sectionname, addkw, index) if domain.active: if domain.get_name not in self.list_active_domains(): # Add it to the list of active domains - if (self.has_option('sssd','domains')): - active_domains = self.get('sssd', 'domains') - active_domains += ", %s" % domain.get_name() + item = self.get_option_index('sssd', 'domains')[1] + if item: + item['value'] += ", %s" % domain.get_name() else: - active_domains = domain.get_name() - self.set('sssd', 'domains', active_domains) + self.set('sssd', 'domains', domain.get_name()) diff --git a/server/config/SSSDConfigTest.py b/server/config/SSSDConfigTest.py index 944f86f..954d24d 100644 --- a/server/config/SSSDConfigTest.py +++ b/server/config/SSSDConfigTest.py @@ -879,7 +879,7 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): "Section [%s] missing" % section) for section in sssdconfig.sections(): - self.assertTrue(section in control_list) + self.assertTrue(section['name'] in control_list) # Verify that all options were imported for a section control_list = [ @@ -893,7 +893,9 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): "Option [%s] missing from [sssd]" % option) for option in sssdconfig.options('sssd'): - self.assertTrue(option in control_list, + if option['type'] in ('empty', 'comment'): + continue + self.assertTrue(option['name'] in control_list, "Option [%s] unexpectedly found" % option) @@ -966,7 +968,7 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): "Section [%s] missing" % section) for section in sssdconfig.sections(): - self.assertTrue(section in control_list) + self.assertTrue(section['name'] in control_list) control_list = [ 'config_file_version', @@ -978,7 +980,9 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): "Option [%s] missing from [sssd]" % option) for option in sssdconfig.options('sssd'): - self.assertTrue(option in control_list, + if option['type'] in ('empty', 'comment'): + continue + self.assertTrue(option['name'] in control_list, "Option [%s] unexpectedly found" % option) diff --git a/server/config/etc/sssd.api.d/sssd-local.conf b/server/config/etc/sssd.api.d/sssd-local.conf index 48ffae2..97994ca 100644 --- a/server/config/etc/sssd.api.d/sssd-local.conf +++ b/server/config/etc/sssd.api.d/sssd-local.conf @@ -8,4 +8,5 @@ base_directory = str, None, /home [provider/local/access] -[provider/local/chpass] \ No newline at end of file +[provider/local/chpass] + diff --git a/server/config/ipachangeconf.py b/server/config/ipachangeconf.py index ddad680..240e6d4 100644 --- a/server/config/ipachangeconf.py +++ b/server/config/ipachangeconf.py @@ -466,23 +466,75 @@ class SSSDChangeConf(IPAChangeConf): self.backup_suffix = ".bak" self.opts = [] - def readfd(self, fd): + def readfp(self, fd): self.opts.extend(self.parse(fd)) def read(self, filename): fd = open(filename, 'r') - self.readfd(fd) + self.readfp(fd) fd.close() + def get(self, section, name): + index, item = self.get_option_index(section, name) + if item: + return item['value'] + + def set(self, section, name, value): + modkw = { 'type' : 'section', + 'name' : section, + 'value' : [{ + 'type' : 'option', + 'name' : 'domains', + 'value' : value, + 'action': 'set', + }], + 'action': 'set', + } + self.mergeNew(self.opts, [ modkw ]) + + def add_section(self, name, optkw, index=0): + optkw.append({'type':'empty', 'value':'empty'}) + addkw = { 'type' : 'section', + 'name' : name, + 'value' : optkw, + } + self.opts.insert(index, addkw) + + def delete_section(self, name): + self.delete_option('section', name) + def sections(self): return [ o for o in self.opts if o['type'] == 'section' ] + def has_section(self, section): + return len([ o for o in self.opts if o['type'] == 'section' if o['name'] == section ]) > 0 + + def options(self, section): + for opt in self.opts: + if opt['type'] == 'section' and opt['name'] == section: + return opt['value'] + def delete_option(self, type, name, exclude_sections=False): index, item = self.findOpts(self.opts, type, name, exclude_sections) if item: del self.opts[index] + return index + + def has_option(self, section, name): + index, item = self.get_option_index(section, name) + if index != -1 and item != None: + return True + return False + + def strip_comments_empty(self, optlist): + retlist = [] + for opt in optlist: + if opt['type'] in ('comment', 'empty'): + continue + retlist.append(opt) + return retlist - def get_option(self, parent_name, name, type='option'): + def get_option_index(self, parent_name, name, type='option'): subtree = None if parent_name: pindex, pdata = self.findOpts(self.opts, 'section', parent_name) @@ -495,7 +547,7 @@ class SSSDChangeConf(IPAChangeConf): def rename_opts(self, parent_name, rename_kw, type='option'): for new_name, old_name in rename_kw.items(): - index, item = self.get_option(parent_name, old_name, type) + index, item = self.get_option_index(parent_name, old_name, type) if item: item['name'] = new_name diff --git a/server/config/upgrade_config.py b/server/config/upgrade_config.py index c973ad2..3d732ad 100644 --- a/server/config/upgrade_config.py +++ b/server/config/upgrade_config.py @@ -45,7 +45,7 @@ class SSSDConfigFile(SSSDChangeConf): os.chmod(file_name + self.backup_suffix, 0600) def get_version(self): - ver = self.get_option('sssd', 'config_file_version')[1] + ver = self.get_option_index('sssd', 'config_file_version')[1] if not ver: return 1 try: @@ -55,7 +55,7 @@ class SSSDConfigFile(SSSDChangeConf): def _do_v2_changes(self): # remove Data Provider - srvlist = self.get_option('sssd', 'services')[1] + srvlist = self.get_option_index('sssd', 'services')[1] if srvlist: services = [ srv.strip() for srv in srvlist['value'].split(',') ] if 'dp' in services: @@ -82,14 +82,6 @@ class SSSDConfigFile(SSSDChangeConf): if not updated: vals.insert(0, { 'name' : o['name'], 'type' : o['type'], 'value' : o['value'] }) - def _add_section(self, name, optkw, index=0): - optkw.append({'type':'empty', 'value':'empty'}) - addkw = { 'type' : 'section', - 'name' : name, - 'value' : optkw, - } - self.opts.insert(index, addkw) - def _migrate_enumerate(self, domain): " Enumerate was special as it turned into bool from (0,1,2,3) enum " enum = self.findOpts(domain, 'option', 'enumerate')[1] @@ -206,7 +198,7 @@ class SSSDConfigFile(SSSDChangeConf): self._migrate_domain(domain) def _update_if_exists(self, opt, to_name, from_section, from_name): - index, item = self.get_option(from_section, from_name) + index, item = self.get_option_index(from_section, from_name) if item: item['name'] = to_name opt.append(item) @@ -245,7 +237,7 @@ class SSSDConfigFile(SSSDChangeConf): 'names', 're-expression') self._update_if_exists(sssd_kw, 're_expression', 'names', 'full-name-format') - self._add_section('sssd', sssd_kw) + self.add_section('sssd', sssd_kw) # update from general services section and monitor self._update_option('sssd', 'services', service_kw.values()) self._update_option('sssd', 'services/monitor', service_kw.values()) -- 1.6.2.5