boinc/dcapi/dcapi-deploy

167 lines
5.4 KiB
Python
Executable File

#! /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] <command>")
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]]()