mirror of https://github.com/BOINC/boinc.git
167 lines
5.4 KiB
Plaintext
167 lines
5.4 KiB
Plaintext
|
#! /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]]()
|