#! /usr/bin/env python """ DC-API deployement script """ import os, re, shutil, tempfile, uuid from optparse import OptionParser from ConfigParser import RawConfigParser class Replacement: def __init__(self, name, value): self.name = name self.value = value self.re = re.compile("\s*" + name + "\s*=") self.found = False def subst(self, string): if self.re.match(string): self.found = True pos = string.find('=') return string[:pos] + "= " + self.value + "\n" else: return string def modify_config(values, section = "Master"): """Modify the DC-API configuration. We can't use the write() method of RawConfigParser() since that does not preserve comments.""" subst = [] for k, v in values.iteritems(): r = Replacement(k, v) subst.append(r) input = open(options.config, "r") input_lines = input.readlines() input.close() output_lines = [] section_found = False section_match = re.compile("[[]" + section + "[]]") other_section = re.compile("[[]") for line in input_lines: if not section_found: if section_match.match(line): section_found = True output_lines.append(line) else: if other_section.match(line): section_found = False for s in subst: if s.found: continue output_lines.append(s.name + " = " + s.value + "\n") for s in subst: line = s.subst(line) output_lines.append(line) handle, name = tempfile.mkstemp(prefix = ".dcapi.", dir = os.path.dirname(options.config)) try: output = os.fdopen(handle, "w") output.writelines(output_lines) output.close() shutil.copymode(options.config, name) os.rename(name, options.config) except: os.unlink(name) raise def deploy(): if not backend: parser.error("The backend must be specified") defaults = backend.master_defaults() defaults["InstanceUUID"] = str(uuid.uuid4()) defaults["WorkingDirectory"] = options.workdir modify_config(defaults) def check(): if not backend: parser.error("The backend must be specified") config = RawConfigParser() config.readfp(open(options.config)) if not config.has_section('Master'): raise SystemExit("The [Master] section is missing") # The [Master] section may contain either master keys or defaults for client # keys keys = config.options('Master') seen = dict([(x, False) for x in keys]) for name, required in backend.get_master_keys(): name = name.lower() if name in seen: seen[name] = True elif required: raise SystemExit("Required option '" + name + "' is missing in the [Master] section") for name, required in backend.get_client_keys(): name = name.lower() if name in seen: seen[name] = True for name, found in seen.iteritems(): if not found: print "Option '" + name + "' in the [Master] section seems unused" # Now check the client sections for section in config.sections(): if section == "Master": continue if not section.startswith("Client-"): print "Unexpected section name: " + section continue keys = config.options(section) seen = dict([(x, False) for x in keys]) for name, required in backend.get_client_keys(): name = name.lower() if name in seen: seen[name] = True elif required: if not config.has_option("Master", name): raise SystemExit("Required option '" + name + "' is missing " "in the [" + section + "] section") for name, found in seen.iteritems(): if not found: print "Option '" + name + "' in the [" + section + "] section seems unused" command_table = {'deploy': deploy, 'check' : check} parser = OptionParser(usage = "%prog [options] ") parser.add_option("--config", "-c", metavar = "FILE", help = "specify the location of the config file. The default " "is dc-api.conf in the current directory") parser.add_option("--backend", "-b", metavar = "NAME", help = "the backend implementation to use") parser.add_option("--workdir", "-w", metavar = "NAME", help = "the work directory of DC-API. Defaults to the " "directory where the config file lives") options, args = parser.parse_args() if len(args) != 1: parser.error("Wrong number of arguments") if not args[0] in command_table: parser.error("Unknown command " + args[0]) if options.backend is None: parser.error("The backend name must be specified") if options.config is None: options.config = "dc-api.conf" if options.workdir is None: options.workdir = os.path.dirname(os.path.abspath(options.config)) # Load the backend module module = __import__("DCAPI." + options.backend) cl = getattr(module, options.backend + "_Backend") backend = getattr(cl, options.backend + "_Backend")() command_table[args[0]]()