""" pushtoolslib.py Vladimir Diaz September 2012. See LICENSE for licensing information. Provide a central location for functions and data useful to multiple 'tuf.pushtools' modules. A 'read_config_file' function is currently provided that returns correctly formatted configuration dictionaries needed by the 'push.py' and 'receive.py' scripts. """ import ConfigParser import os import tuf.formats PUSH_CONFIG = 'push.cfg' RECEIVE_CONFIG = 'receive.cfg' TRANSFER_MODULES = ['scp'] CONFIG_TYPES = ['push', 'receive'] def read_config_file(filename, config_type): """ Return a dictionary where the keys are section names and the values dictionaries of the keys/values in that section. The returned dict should be correctly formatted, contain the required data according to its config type, and be valid (i.e., a correctly named file and available). Example config: config_dict = {'general': {'transfer_module': 'scp', ...}, 'scp': {'host': 'localhost', 'user': 'McFly', ...}} filename: The filepath to the configuration file. config_type: A string identifying the type of config file expected. Supported config types: 'push' and 'receive'. tuf.FormatError, if the arguments are improperly formatted. tuf.Error, if there is an error processing the config contents. The contents of 'filename' are read and stored. A dictionary containing the data loaded from the configuration file. """ # Do the arguments have the correct format? # Raise 'tuf.FormatError' if there is a mismatch. tuf.formats.PATH_SCHEMA.check_match(filename) tuf.formats.NAME_SCHEMA.check_match(config_type) # RawConfigParser is used because unlike ConfigParser, # it does not provide magical interpolation/expansion # of variables (e.g., '%(option)s' would be ignored). config = ConfigParser.RawConfigParser() try: config.read(filename) except ConfigParser.MissingSectionHeaderError, error: raise tuf.Error(error) if config.sections() is None: raise tuf.Error('Could not read '+repr(filename)) # Extract the relevant information from the config and build the # 'config_dict' dictionary. config_dict = {} for section in config.sections(): config_dict[section] = {} for key, value in config.items(section): # Split comma-separated entries and store them in a list. # 'pushroots' is the only entry that currently accepts # multiple values. if key in ['pushroots']: value = value.split(',') config_dict[section][key] = value # Before returning a 'push' config dict, check the config is properly # formatted, valid, and contains the required data. if config_type == 'push': # Ensure 'filename' is an appropriately named push config file. if os.path.basename(filename) != PUSH_CONFIG: message = repr(filename)+' is not a valid push config file.'+\ ' The push config file should be named: '+repr(PUSH_CONFIG) raise tuf.Error(message) # Retrieve the transfer module from the push config. The caller # expects a valid config dict containing the required keys/values. try: transfer_module = config_dict['general']['transfer_module'] except KeyError, e: message = 'The push config file did not contain the required '+\ '"transfer_module" entry under "[general]".' raise tuf.Error(message) # Determine the transfer module and ensure the config file is properly # formatted for an "scp configuration file". Raise 'tuf.FormatError' # if there is mismatch. if transfer_module == 'scp': try: tuf.formats.SCPCONFIG_SCHEMA.check_match(config_dict) except tuf.FormatError, e: message = repr(PUSH_CONFIG)+' rejected. '+str(e) raise tuf.FormatError(message) # A supported transfer module was not found. Raise 'tuf.Error'. else: message = 'The config file contains an invalid "transfer_module" entry '+\ 'Supported transfer modules: '+repr(TRANSFER_MODULES) raise tuf.Error(message) # Before returning a 'receive' config dict, check the config is properly # formatted, valid, and contains the required data. elif config_type == 'receive': # Ensure 'filename' is an appropriately named receive config file. if os.path.basename(filename) != RECEIVE_CONFIG: message = repr(filename)+' is not a valid receive config file.'+\ ' The receive config file should be named: '+repr(RECEIVE_CONFIG) raise tuf.Error(message) # Determine if the config file is properly formatted for a "receive # configuration file". Raise 'tuf.FormatError' if there is a # mismatch. try: tuf.formats.RECEIVECONFIG_SCHEMA.check_match(config_dict) except tuf.FormatError, e: message = repr(RECEIVE_CONFIG)+' rejected. '+str(e) raise tuf.FormatError(message) # Invalid 'config_type' requested. else: message = 'Invalid "config_type" argument. Supported: '+repr(CONFIG_TYPES) raise tuf.Error(message) return config_dict