diff options
Diffstat (limited to 'tools')
25 files changed, 379 insertions, 840 deletions
diff --git a/tools/README b/tools/README index 5505573c8..3c705b660 100644 --- a/tools/README +++ b/tools/README @@ -3,9 +3,6 @@ This directory contains repository maintenance tools. basebuilder.py <image directory> - builds v2 base.xml from bcfg1 repo -batchadd.py <filename> - - Add records to Hostbase - bcfg2-completion.bash - Bash tab completion for bcfg2-admin @@ -20,9 +17,6 @@ bcfg2_local.py - Perform a full Bcfg2 run against a local repository instead of against a remote server -bcfg2-profile-templates.py [<template>] - - Benchmark template rendering times - bcfg2_svnlog.py - Send intelligent log messages about changes made to your Bcfg2 repository from SVN postcommit @@ -61,15 +55,6 @@ generate-manpages.bash git_commit.py - Trigger script to commit local changes back to a git repository -hostbasepush.py - - Call the Hostbase.rebuildState XML-RPC method - -hostbase.py {-l|-c} <hostname> - - Display or create host information for Hostbase - -hostinfo.py {-q <query>|--showfields} - - Query the hostbase databse - pkgmgr_gen.py - Generate Pkgmgr XML files from a list of directories that contain RPMS diff --git a/tools/batchadd.py b/tools/batchadd.py deleted file mode 100755 index e8008b330..000000000 --- a/tools/batchadd.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/python - -from datetime import date -import os -import sys - -os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.Server.Hostbase.settings' -from Bcfg2.Server.Hostbase.hostbase.models import * -from Bcfg2.Server.Hostbase.settings import DEFAULT_MX, PRIORITY -import Bcfg2.Server.Hostbase.regex - -host_attribs = ['administrator', - 'comments', - 'csi', - 'expiration_date', - 'hostname', - 'location', - 'netgroup', - 'outbound_smtp', - 'primary_user', - 'printq', - 'security_class', - 'support', - 'whatami'] - - -def handle_error(field): - if '-f' in sys.argv: - return - print("Error: %s is already defined in hostbase" % field) - if '-s' in sys.argv: - sys.exit(1) - - -def checkformat(values, indices): - """Ensures file contains all necessary attributes in order """ - filelist = [pair[0] for pair in values] - - # lines = len(filelist) - - filelist = filelist[indices[0]:] - - for index in indices: - if filelist[0:13] != host_attribs: - # figure out what to do here - return False - else: - # process rest of host attributes - try: - next = filelist[1:].index('hostname') - remaining = filelist[13:next + 1] - filelist = filelist[next + 1:] - except: - remaining = filelist[13:] - needfields = ['mac_addr', 'hdwr_type', 'ip_addr'] - if [item for item in needfields if item not in remaining]: - return False - return True - - -if __name__ == '__main__': - - # argument handling for batchadd - try: - fd = open(sys.argv[1], 'r') - except (IndexError, IOError): - print("\nUsage: batchadd.py filename\n") - sys.exit() - - lines = fd.readlines() - # splits and strips lines into (attribute, value) - info = [[item.strip() for item in line.split("->")] for line in lines - if line.lstrip(' ')[0] != '#' and line != '\n'] - - if info[0][0] == 'mx' and info[1][0] == 'priority': - mx, created = MX.objects.get_or_create(mx=info[0][1], - priority=info[1][1]) - info = info[2:] - else: - mx, created = MX.objects.get_or_create(mx=DEFAULT_MX, - priority=PRIORITY) - if created: - mx.save() - - hostindices = [num for num in range(0, len(info)) - if info[num][0] == 'hostname'] - - if not checkformat(info, hostindices): - print("Error: file format") - sys.exit() - -################# - - for host in hostindices: - try: - host = Host.objects.get(hostname=info[host][1]) - handle_error(info[host][1]) - except: - # do something here - pass - - macindices = [num for num in range(0, len(info)) - if info[num][0] == 'mac_addr'] - for mac_addr in macindices: - try: - host = Interface.objects.get(mac_addr=info[mac_addr][1]) - handle_error(info[mac_addr][1]) - except: - # do something here - pass - - for host in hostindices: - blank = Host() - for attrib in host_attribs: - pair = info.pop(0) - if pair[0] == 'outbound_smtp': - if pair[1] == 'y': - blank.__dict__[pair[0]] = 1 - else: - blank.__dict__[pair[0]] = 0 - elif pair[0] == 'expiration_date': - (year, month, day) = pair[1].split("-") - blank.expiration_date = date(int(year), - int(month), - int(day)) - else: - blank.__dict__[pair[0]] = pair[1] - blank.status = 'active' - blank.save() - newhostname = blank.hostname.split(".")[0] - newdomain = blank.hostname.split(".", 1)[1] - while info and info[0][0] != 'hostname': - if info[0][0] == 'mac_addr': - pair = info.pop(0) - inter = Interface.objects.create(host=blank, - mac_addr=pair[1], - hdwr_type='eth') - if not pair[1]: - inter.dhcp = False - inter.save() - elif info[0][0] == 'hdwr_type': - pair = info.pop(0) - inter.hdwr_type = pair[1] - inter.save() - elif info[0][0] == 'ip_addr': - pair = info.pop(0) - ip = IP.objects.create(interface=inter, ip_addr=pair[1]) - hostnamenode = Name(ip=ip, - name=blank.hostname, - dns_view='global', - only=False) - hostnamenode.save() - namenode = Name(ip=ip, - name=".".join([newhostname + "-" + inter.hdwr_type, - newdomain]), - dns_view="global", only=False) - namenode.save() - subnetnode = Name(ip=ip, name=newhostname + "-" + - ip.ip_addr.split(".")[2] + "." + - newdomain, dns_view="global", only=False) - subnetnode.save() - hostnamenode.mxs.add(mx) - namenode.mxs.add(mx) - subnetnode.mxs.add(mx) - elif info[0][0] == 'cname': - pair = info.pop(0) - cname = CName.objects.create(name=hostnamenode, cname=pair[1]) - cname.save() diff --git a/tools/bcfg2-completion.bash b/tools/bcfg2-completion.bash index 99cfb695b..b9e799cf8 100644 --- a/tools/bcfg2-completion.bash +++ b/tools/bcfg2-completion.bash @@ -1,14 +1,13 @@ # TODO: Add completion for each admin mode _bcfg2-admin() { - local cur prev sedcmd possibles + local cur prev possibles COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - sedcmd='sed -n -e s/^[[:space:]][[:space:]][[:space:]]\([[:alpha:]]\+\)[[:space:]]\+.*$/\1/p' if [[ ${COMP_CWORD} -eq 1 ]] || [[ -n "${prev}" && ${prev} == -* ]] then - possibles="$(bcfg2-admin help | ${sedcmd})" + possibles="$(bcfg2-admin help | awk '{print $1}')" #elif bcfg2-admin ${prev} help &>/dev/null ; then # possibles=$(bcfg2-admin ${prev} help | ${sedcmd}) fi @@ -18,4 +17,21 @@ _bcfg2-admin() { return 0 } +_bcfg2-info() { + local cur prev possibles + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + if [[ ${COMP_CWORD} -eq 1 ]] || [[ -n "${prev}" && ${prev} == -* ]] + then + possibles="$(bcfg2-info help | awk '{print $1}')" + fi + + [[ -n "${possibles}" ]] && \ + COMPREPLY=( $(compgen -W "${possibles}" -- ${cur}) ) + + return 0 +} complete -F _bcfg2-admin bcfg2-admin +complete -F _bcfg2-info bcfg2-info diff --git a/tools/bcfg2-import-config b/tools/bcfg2-import-config index d6273f0c6..fec007e7e 100755 --- a/tools/bcfg2-import-config +++ b/tools/bcfg2-import-config @@ -11,7 +11,6 @@ usage() { echo "$0: tool to import files in to bcfg2-server repository" echo " -s Copy SSH Key files" - echo " -p Create :info files with current file permissions" echo " -n No suffix. Generate global files" echo " --debian Run debsums to detect changed configuration files" echo " ** debsums is only able to detect part of changes!" @@ -28,7 +27,6 @@ eval set -- "$TEMP" ## Start Defaults NEEDSSH=0 -NEEDPERM=0 DEBSUMS=0 NOSUFFIX=0 # End Defaults @@ -37,7 +35,6 @@ NOSUFFIX=0 while true ; do case "$1" in -s) NEEDSSH=1; shift ;; - -p) NEEDPERM=1; shift ;; --debian) DEBSUMS=1; shift ;; -n) NOSUFFIX=1; shift ;; -h|--help) @@ -102,11 +99,6 @@ get_files() { FILE=$(basename $i) mkdir -p $CFGREPO/$i cp $i $CFGREPO/$i/${FILE}${SUFFIX} - if [ $NEEDPERM -ne 0 ]; then - # Get permissions for the file - echo -n "(permissions) " - find $i -printf "owner:%u\ngroup:%g\nperms:%#m\n" > "$CFGREPO/$i/:info" - fi echo "OK" else echo "$i: Not a file" @@ -126,7 +118,7 @@ get_debsums() { } ## End Functions -if [ $(($NEEDPERM + $NEEDSSH + $DEBSUMS)) -eq 0 -a -z "$FILES" ]; then usage ; exit 0; fi +if [ $(($NEEDSSH + $DEBSUMS)) -eq 0 -a -z "$FILES" ]; then usage ; exit 0; fi init_temp_repo get_debsums diff --git a/tools/bcfg2-profile-templates.py b/tools/bcfg2-profile-templates.py deleted file mode 100755 index 2b0ca6d63..000000000 --- a/tools/bcfg2-profile-templates.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/python -Ott -# -*- coding: utf-8 -*- -""" Benchmark template rendering times """ - -import sys -import time -import math -import signal -import logging -import operator -import Bcfg2.Logger -import Bcfg2.Options -import Bcfg2.Server.Core - - -def stdev(nums): - mean = float(sum(nums)) / len(nums) - return math.sqrt(sum((n - mean)**2 for n in nums) / float(len(nums))) - - -def get_sigint_handler(core): - """ Get a function that handles SIGINT/Ctrl-C by shutting down the - core and exiting properly.""" - - def hdlr(sig, frame): # pylint: disable=W0613 - """ Handle SIGINT/Ctrl-C by shutting down the core and exiting - properly. """ - core.shutdown() - os._exit(1) # pylint: disable=W0212 - - return hdlr - - -def main(): - optinfo = dict( - client=Bcfg2.Options.Option("Benchmark templates for one client", - cmd="--client", - odesc="<client>", - long_arg=True, - default=None), - runs=Bcfg2.Options.Option("Number of rendering passes per template", - cmd="--runs", - odesc="<runs>", - long_arg=True, - default=5, - cook=int)) - optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) - optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) - - if setup['debug']: - level = logging.DEBUG - elif setup['verbose']: - level = logging.INFO - else: - level = logging.WARNING - Bcfg2.Logger.setup_logging("bcfg2-test", - to_console=setup['verbose'] or setup['debug'], - to_syslog=False, - to_file=setup['logging'], - level=level) - logger = logging.getLogger(sys.argv[0]) - - core = Bcfg2.Server.Core.BaseCore(setup) - signal.signal(signal.SIGINT, get_sigint_handler(core)) - logger.info("Bcfg2 server core loaded") - core.load_plugins() - logger.debug("Plugins loaded") - core.block_for_fam_events(handle_events=True) - logger.debug("Repository events processed") - - if setup['args']: - templates = setup['args'] - else: - templates = [] - - if setup['client'] is None: - clients = [core.build_metadata(c) for c in core.metadata.clients] - else: - clients = [core.build_metadata(setup['client'])] - - times = dict() - client_count = 0 - for metadata in clients: - client_count += 1 - logger.info("Rendering templates for client %s (%s/%s)" % - (metadata.hostname, client_count, len(clients))) - structs = core.GetStructures(metadata) - struct_count = 0 - for struct in structs: - struct_count += 1 - logger.info("Rendering templates from structure %s:%s (%s/%s)" % - (struct.tag, struct.get("name"), struct_count, - len(structs))) - entries = struct.xpath("//Path") - entry_count = 0 - for entry in entries: - entry_count += 1 - if templates and entry.get("name") not in templates: - continue - logger.info("Rendering Path:%s (%s/%s)..." % - (entry.get("name"), entry_count, len(entries))) - ptimes = times.setdefault(entry.get("name"), []) - for i in range(setup['runs']): - start = time.time() - try: - core.Bind(entry, metadata) - ptimes.append(time.time() - start) - except: - break - if ptimes: - avg = sum(ptimes) / len(ptimes) - if avg: - logger.debug(" %s: %.02f sec" % - (metadata.hostname, avg)) - - # print out per-file results - tmpltimes = [] - for tmpl, ptimes in times.items(): - try: - mean = float(sum(ptimes)) / len(ptimes) - except ZeroDivisionError: - continue - ptimes.sort() - median = ptimes[len(ptimes) / 2] - std = stdev(ptimes) - if mean > 0.01 or median > 0.01 or std > 1 or templates: - tmpltimes.append((tmpl, mean, median, std)) - print("%-50s %-9s %-11s %6s" % - ("Template", "Mean Time", "Median Time", "σ")) - for info in reversed(sorted(tmpltimes, key=operator.itemgetter(1))): - print("%-50s %9.02f %11.02f %6.02f" % info) - core.shutdown() - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/bcfg2_local.py b/tools/bcfg2_local.py index 78a46ba5c..5e5bca777 100755 --- a/tools/bcfg2_local.py +++ b/tools/bcfg2_local.py @@ -6,19 +6,19 @@ the server core, then uses that to get probes, run them, and so on.""" import sys import socket import Bcfg2.Options -from Bcfg2.Client.Client import Client -from Bcfg2.Server.Core import BaseCore +from Bcfg2.Client import Client +from Bcfg2.Server.Core import Core -class LocalCore(BaseCore): +class LocalCore(Core): """ Local server core similar to the one started by bcfg2-info """ - def __init__(self, setup): - saved = (setup['syslog'], setup['logging']) - setup['syslog'] = False - setup['logging'] = None - Bcfg2.Server.Core.BaseCore.__init__(self, setup=setup) - setup['syslog'], setup['logging'] = saved + def __init__(self): + #saved = (setup['syslog'], setup['logging']) + #setup['syslog'] = False + #setup['logging'] = None + Bcfg2.Server.Core.BaseCore.__init__(self) + #setup['syslog'], setup['logging'] = saved self.load_plugins() self.block_for_fam_events(handle_events=True) @@ -60,26 +60,22 @@ class LocalClient(Client): """ A version of the Client class that uses LocalProxy instead of an XML-RPC proxy to make its calls """ - def __init__(self, setup, proxy): - Client.__init__(self, setup) + def __init__(self, proxy): + Client.__init__(self) self._proxy = proxy def main(): - optinfo = Bcfg2.Options.CLIENT_COMMON_OPTIONS - optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - if 'bundle_quick' in optinfo: - # CLIENT_BUNDLEQUICK option uses -Q, just like the server repo - # option. the server repo is more important for this - # application. - optinfo['bundle_quick'] = Bcfg2.Options.Option('bundlequick', - default=False) - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) - - core = LocalCore(setup) + parser = Bcfg2.Options.Parser( + description="Run a Bcfg2 client against a local repository without a " + "server", + conflict_handler="resolve", + components=[LocalCore, LocalProxy, LocalClient]) + parser.parse() + + core = LocalCore() try: - LocalClient(setup, LocalProxy(core)).run() + LocalClient(LocalProxy(core)).run() finally: core.shutdown() diff --git a/tools/export.py b/tools/export.py index 6b0238bbb..df3c810d5 100755 --- a/tools/export.py +++ b/tools/export.py @@ -257,13 +257,11 @@ E.G. 1.2.0pre1 is a valid version. startswith=True, dryrun=options.dryrun) find_and_replace('misc/bcfg2.spec', 'BuildRoot', - 'BuildRoot: %%{_tmppath}/%%{name}-%%{version}%s-%%{release}-root-%%(%%{__id_u} -n)\n' % - version_info['build'], + 'BuildRoot: %{_tmppath}/%{name}-%{version}%{?_pre_rc}-%{release}-root-%(%{__id_u} -n)\n', startswith=True, dryrun=options.dryrun) find_and_replace('misc/bcfg2-selinux.spec', 'BuildRoot', - 'BuildRoot: %%{_tmppath}/%%{name}-%%{version}%s-%%{release}-root-%%(%%{__id_u} -n)\n' % - version_info['build'], + 'BuildRoot: %{_tmppath}/%{name}-%{version}%{?_pre_rc}-%{release}-root-%(%{__id_u} -n)\n', startswith=True, dryrun=options.dryrun) # fix pre problem noted in diff --git a/tools/hostbase.py b/tools/hostbase.py deleted file mode 100755 index 7474e68b7..000000000 --- a/tools/hostbase.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/python -import os -from getopt import getopt, GetoptError -from re import split -import sys - -os.environ['DJANGO_SETTINGS_MODULE'] = 'Hostbase.settings' -from Hostbase.hostbase.models import Host - -attribs = ['administrator', - 'comments', - 'csi', - 'dhcp', - 'expiration_date', - 'hostname', - 'last', - 'location', - 'netgroup', - 'outbound_smtp', - 'primary_user', - 'printq', - 'security_class', - 'support', - 'status', - 'whatami'] - -already_exists = None -#here's my attempt at making the command line idiot proof -#you must supply and arugument and hostname for hostbase.py to run -try: - (opts, args) = getopt(sys.argv[1:], 'l:c:') - sys.argv[1] - if len(split("\.", opts[0][1])) == 1: - hosttouse = opts[0][1] + ".mcs.anl.gov" - else: - hosttouse = opts[0][1] -except (GetoptError, IndexError): - print("\nUsage: hostbase.py -flag (hostname)\n") - print("Flags:") - print("\t-l look (hostname)\n") -# print("\t-c copy (hostname)\n") - sys.exit() - -try: - host = Host.objects.get(hostname=hosttouse) -except: - print("Error: host %s not in hostbase" % hosttouse) - sys.exit(1) -interfaces = [] -for interface in host.interface_set.all(): - interfaces.append([interface, interface.ip_set.all()]) -hostinfo = "\n" -for attrib in attribs: - if not (opts[0][0] == '-c' and attrib in ['status', 'last']): - if attrib == 'dhcp' or attrib == 'outbound_smtp': - if host.__dict__[attrib]: - hostinfo += "%-32s-> %s\n" % (attrib, 'y') - else: - hostinfo += "%-32s-> %s\n" % (attrib, 'n') - else: - hostinfo += "%-32s-> %s\n" % (attrib, host.__dict__[attrib]) -for interface in interfaces: - hostinfo += "\n%-32s-> %s\n" % ('mac_addr', interface[0].mac_addr) - hostinfo += "%-32s-> %s\n" % ('hdwr_type', interface[0].hdwr_type) - for ip in interface[1]: - hostinfo += "%-32s-> %s\n" % ('ip_addr', ip.ip_addr) - -if opts[0][0] == '-l': - """Displays general host information""" - print(hostinfo) - -if opts[0][0] == '-c': - """Provides pre-filled template to copy a host record""" - fd = open('/tmp/hostbase.%s.tmp' % host.id, 'w') - fd.write(hostinfo) - fd.close() - os.system('vi + /tmp/hostbase.%s.tmp' % host.id) - os.system('batchadd.py /tmp/hostbase.%s.tmp' % host.id) - os.system('rm /tmp/hostbase.%s.tmp' % host.id) diff --git a/tools/hostbasepush.py b/tools/hostbasepush.py deleted file mode 100755 index 02b7a582f..000000000 --- a/tools/hostbasepush.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python - -import os -import Bcfg2.Client.Proxy - -if not os.getuid() == 0: - print("this command must be run as root") - raise SystemExit - -proxy = Bcfg2.Client.Proxy.bcfg2() -print("building files...") -proxy.run_method('Hostbase.rebuildState', ()) -print("running bcfg...") -os.system('bcfg2 -q -d -v') diff --git a/tools/hostinfo.py b/tools/hostinfo.py deleted file mode 100755 index 8ae5c4df6..000000000 --- a/tools/hostinfo.py +++ /dev/null @@ -1,197 +0,0 @@ -#!/usr/bin/python -"""Hostinfo queries the hostbase database according to user-defined data""" - -from os import system, environ -environ['DJANGO_SETTINGS_MODULE'] = 'Hostbase.settings' -from getopt import gnu_getopt, GetoptError -from django.db import connection -import sys - -logic_ops = ["and", "or"] -host_attribs = ["hostname", "whatami", "netgroup", "security_class", - "support", "csi", "memory", "printq", "dhcp", "outbound_smtp", - "primary_user", "administrator", "location", - "comments", "last", "expiration_date"] -dispatch = {'mac_addr': ' i.', - 'hdwr_type': ' i.', - 'ip_addr': ' p.', - 'name': ' n.', - 'dns_view': ' n.', - 'cname': ' c.', - 'mx': ' m.', - 'priority': ' m.'} - - -def pinger(hosts): - """Function that uses fping to ping multiple hosts in parallel""" - hostnames = "" - for each in hosts: - hostnames += each[0] + " " - system("fping -r 1" + hostnames) - sys.exit() - - -def get_query(arguments): - """Parses the command line options and returns the necessary - data for an SQL query""" - logic = None - resultset = [] - querystring = '' - while 1: - notflag = False - if arguments[0] == 'not': - notflag = True - querypos = 1 - elif arguments[0] in logic_ops: - logic = arguments[0] - if arguments[1] == 'not': - notflag = True - querypos = 2 - else: - querypos = 1 - else: - querypos = 0 - if len(arguments[querypos].split("==")) > 1: - operator = "=" - if notflag: - operator = "<>" - querysplit = arguments[querypos].split("==") - if querysplit[0] in host_attribs: - querystring = " h.%s%s\'%s\'" % (querysplit[0], - operator, - querysplit[1]) - elif querysplit[0] in dispatch: - querystring = dispatch[querysplit[0]] - querystring += "%s%s\'%s\'" % (querysplit[0], - operator, - querysplit[1]) - elif len(arguments[querypos].split("=")) > 1: - notstring = '' - if notflag: - notstring = 'NOT ' - querysplit = arguments[querypos].split("=") - if querysplit[0] in host_attribs: - querystring = " h.%s %sLIKE \'%%%%%s%%%%\'" % (querysplit[0], - notstring, - querysplit[1]) - elif querysplit[0] in dispatch: - querystring = dispatch[querysplit[0]] - querystring += "%s %sLIKE \'%%%%%s%%%%\'" % (querysplit[0], - notstring, - querysplit[1]) - else: - print("ERROR: bad query format") - sys.exit() - if not querystring: - print("ERROR: bad query format") - sys.exit() - resultset.append((querystring, logic)) - arguments = arguments[querypos + 1:] - if arguments == [] or arguments[0] not in logic_ops: - break - return resultset - -try: - (opts, args) = gnu_getopt(sys.argv[1:], - 'q:', ['showfields', 'fields', 'ping', 'summary']) - cursor = connection.cursor() - if ('--showfields', '') in opts: - print("\nhost fields:\n") - for field in host_attribs: - print(field) - for field in dispatch: - print(field) - print("") - sys.exit() - if opts[0][0] == '-q': - results = get_query(sys.argv[2:]) - queryoptions = "" - for result in results: - if result[1] == 'and': - queryoptions += " AND " + result[0] - elif result[1] == 'or': - queryoptions += " OR " + result[0] - else: - queryoptions += result[0] - if ('--summary', '') in opts: - fields = "h.hostname, h.whatami, h.location, h.primary_user" - query = """SELECT DISTINCT %s FROM (((((hostbase_host h - INNER JOIN hostbase_interface i ON h.id = i.host_id) - INNER JOIN hostbase_ip p ON i.id = p.interface_id) - INNER JOIN hostbase_name n ON p.id = n.ip_id) - INNER JOIN hostbase_name_mxs x ON x.name_id = n.id) - INNER JOIN hostbase_mx m ON m.id = x.mx_id) - LEFT JOIN hostbase_cname c ON n.id = c.name_id - WHERE %s ORDER BY h.hostname - """ % (fields, queryoptions) - cursor.execute(query) - results = cursor.fetchall() - if not results: - print("No matches were found for your query") - sys.exit() - print("\n%-32s %-10s %-10s %-10s" % ('Hostname', 'Type', 'Location', 'User')) - print("================================ ========== ========== ==========") - for host in results: - print("%-32s %-10s %-10s %-10s" % (host)) - print("") - elif ('--fields', '') in opts: - tolook = [arg for arg in args if arg in host_attribs or arg in dispatch] - fields = "" - fields = ", ".join(tolook) - if not fields: - print("No valid fields were entered. exiting...") - sys.exit() - query = """SELECT DISTINCT %s FROM (((((hostbase_host h - INNER JOIN hostbase_interface i ON h.id = i.host_id) - INNER JOIN hostbase_ip p ON i.id = p.interface_id) - INNER JOIN hostbase_name n ON p.id = n.ip_id) - INNER JOIN hostbase_name_mxs x ON x.name_id = n.id) - INNER JOIN hostbase_mx m ON m.id = x.mx_id) - LEFT JOIN hostbase_cname c ON n.id = c.name_id - WHERE %s ORDER BY h.hostname - """ % (fields, queryoptions) - - cursor.execute(query) - results = cursor.fetchall() - - last = results[0] - for field in results[0]: - print(repr(field) + "\t") - for host in results: - if not host == last: - for field in host: - print(repr(field) + "\t") - last = host - print("") - else: - basequery = """SELECT DISTINCT h.hostname FROM (((((hostbase_host h - INNER JOIN hostbase_interface i ON h.id = i.host_id) - INNER JOIN hostbase_ip p ON i.id = p.interface_id) - INNER JOIN hostbase_name n ON p.id = n.ip_id) - INNER JOIN hostbase_name_mxs x ON x.name_id = n.id) - INNER JOIN hostbase_mx m ON m.id = x.mx_id) - LEFT JOIN hostbase_cname c ON n.id = c.name_id - WHERE - """ - cursor.execute(basequery + queryoptions + " ORDER BY h.hostname") - results = cursor.fetchall() - - if not results: - print("No matches were found for your query") - sys.exit() - - if ("--ping", '') in opts: - pinger(results) - - for host in results: - print(host[0]) - - -except (GetoptError, IndexError): - print("\nUsage: hostinfo.py -q <field>=[=]<value> [and/or <field>=<value> [--long option]]") - print(" hostinfo.py --showfields\tshows all data fields") - print("\n long options:") - print("\t --fields f1 f2 ...\tspecifies the fields displayed from the queried hosts") - print("\t --summary\t\tprints out a predetermined set of fields") - print("\t --ping\t\t\tuses fping to ping all queried hosts\n") - sys.exit() diff --git a/tools/posixusers_baseline.py b/tools/posixusers_baseline.py index 4c78a757e..06925beed 100755 --- a/tools/posixusers_baseline.py +++ b/tools/posixusers_baseline.py @@ -5,74 +5,51 @@ import sys import logging import lxml.etree import Bcfg2.Logger +import Bcfg2.Options from Bcfg2.Client.Tools.POSIXUsers import POSIXUsers -from Bcfg2.Options import OptionParser, Option, get_bool, CLIENT_COMMON_OPTIONS -def get_setup(): - optinfo = CLIENT_COMMON_OPTIONS - optinfo['nouids'] = Option("Do not include UID numbers for users", - default=False, - cmd='--no-uids', - long_arg=True, - cook=get_bool) - optinfo['nogids'] = Option("Do not include GID numbers for groups", - default=False, - cmd='--no-gids', - long_arg=True, - cook=get_bool) - setup = OptionParser(optinfo) - setup.parse(sys.argv[1:]) +class CLI(object): + options = [ + Bcfg2.Options.BooleanOption( + "--no-uids", help="Do not include UID numbers for users"), + Bcfg2.Options.BooleanOption( + "--no-gids", help="Do not include GID numbers for groups")] - if setup['args']: - print("posixuser_[baseline.py takes no arguments, only options") - print(setup.buildHelpMessage()) - raise SystemExit(1) - level = 30 - if setup['verbose']: - level = 20 - if setup['debug']: - level = 0 - Bcfg2.Logger.setup_logging('posixusers_baseline.py', - to_syslog=False, - level=level, - to_file=setup['logging']) - return setup - - -def main(): - setup = get_setup() - if setup['file']: - config = lxml.etree.parse(setup['file']).getroot() - else: + def __init__(self): + Bcfg2.Options.get_parser( + description="Generate a bundle with a baseline of POSIX users and " + "groups", + components=[self, POSIXUsers]).parse() config = lxml.etree.Element("Configuration") - logger = logging.getLogger('posixusers_baseline.py') - users = POSIXUsers(logger, setup, config) - - baseline = lxml.etree.Element("Bundle", name="posixusers_baseline") - for entry in users.FindExtra(): - data = users.existing[entry.tag][entry.get("name")] - for attr, idx in users.attr_mapping[entry.tag].items(): - if (entry.get(attr) or - (attr == 'uid' and setup['nouids']) or - (attr == 'gid' and setup['nogids'])): - continue - entry.set(attr, str(data[idx])) - if entry.tag == 'POSIXUser': - try: - entry.set("group", grp.getgrgid(data[3])[0]) - except KeyError: - logger.warning("User %s is a member of nonexistent group %s" % - (entry.get("name"), data[3])) - entry.set("group", str(data[3])) - for group in users.user_supplementary_groups(entry): - memberof = lxml.etree.SubElement(entry, "MemberOf", - group=group[0]) - - entry.tag = "Bound" + entry.tag - baseline.append(entry) - - print(lxml.etree.tostring(baseline, pretty_print=True)) + self.users = POSIXUsers(config) + self.logger = logging.getLogger('posixusers_baseline.py') + + def run(self): + baseline = lxml.etree.Element("Bundle", name="posixusers_baseline") + for entry in self.users.FindExtra(): + data = self.users.existing[entry.tag][entry.get("name")] + for attr, idx in self.users.attr_mapping[entry.tag].items(): + if (entry.get(attr) or + (attr == 'uid' and Bcfg2.Options.setup.no_uids) or + (attr == 'gid' and Bcfg2.Options.setup.no_gids)): + continue + entry.set(attr, str(data[idx])) + if entry.tag == 'POSIXUser': + try: + entry.set("group", grp.getgrgid(data[3])[0]) + except KeyError: + self.logger.warning( + "User %s is a member of nonexistent group %s" % + (entry.get("name"), data[3])) + entry.set("group", str(data[3])) + for group in self.users.user_supplementary_groups(entry): + lxml.etree.SubElement(entry, "MemberOf", group=group[0]) + + entry.tag = "Bound" + entry.tag + baseline.append(entry) + + print(lxml.etree.tostring(baseline, pretty_print=True)) if __name__ == "__main__": - sys.exit(main()) + sys.exit(CLI().run()) diff --git a/tools/selinux_baseline.py b/tools/selinux_baseline.py index 507a16f43..ad2a40426 100755 --- a/tools/selinux_baseline.py +++ b/tools/selinux_baseline.py @@ -1,41 +1,18 @@ #!/usr/bin/env python import sys -import logging import lxml.etree - import Bcfg2.Logger import Bcfg2.Options -from Bcfg2.Client.Tools.SELinux import * - -LOGGER = None - -def get_setup(): - global LOGGER - optinfo = Bcfg2.Options.CLIENT_COMMON_OPTIONS - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) +from Bcfg2.Client.Tools.SELinux import SELinux - if setup['args']: - print("selinux_baseline.py takes no arguments, only options") - print(setup.buildHelpMessage()) - raise SystemExit(1) - level = 30 - if setup['verbose']: - level = 20 - if setup['debug']: - level = 0 - Bcfg2.Logger.setup_logging('selinux_base', - to_syslog=False, - level=level, - to_file=setup['logging']) - LOGGER = logging.getLogger('bcfg2') - return setup def main(): - setup = get_setup() + Bcfg2.Options.get_parser( + description="Get a baseline bundle of SELinux entries", + components=[SELinux]).parse() config = lxml.etree.Element("Configuration") - selinux = SELinux(LOGGER, setup, config) + selinux = SELinux(config) baseline = lxml.etree.Element("Bundle", name="selinux_baseline") for etype, handler in selinux.handlers.items(): diff --git a/tools/upgrade/1.1/posixunified.py b/tools/upgrade/1.1/posixunified.py index 8eb4ed734..b6ce7bc90 100644..100755 --- a/tools/upgrade/1.1/posixunified.py +++ b/tools/upgrade/1.1/posixunified.py @@ -17,12 +17,13 @@ NOTE: This script takes a conservative approach when it comes to """ if __name__ == '__main__': - opts = { - 'repo': Bcfg2.Options.SERVER_REPOSITORY, - } - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) - repo = setup['repo'] + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.0-style POSIX entries to 1.1-style " + "unified Path entries") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + + repo = Bcfg2.Options.setup.repository unifiedposixrules = "%s/Rules/unified-rules.xml" % repo rulesroot = lxml.etree.Element("Rules") diff --git a/tools/upgrade/1.2/nagiosgen-convert.py b/tools/upgrade/1.2/nagiosgen-convert.py index 2c2142735..eb10cd4ea 100755 --- a/tools/upgrade/1.2/nagiosgen-convert.py +++ b/tools/upgrade/1.2/nagiosgen-convert.py @@ -7,10 +7,13 @@ import lxml.etree import Bcfg2.Options def main(): - opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY} - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) - repo = setup['repo'] + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.1-style Properties-based NagiosGen " + "configuration to standalone 1.2-style") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + + repo = Bcfg2.Options.setup.repository oldconfigfile = os.path.join(repo, 'Properties', 'NagiosGen.xml') newconfigpath = os.path.join(repo, 'NagiosGen') newconfigfile = os.path.join(newconfigpath, 'config.xml') @@ -32,11 +35,11 @@ def main(): if host.tag == lxml.etree.Comment: # skip comments continue - + if host.tag == 'default': print("default tag will not be converted; use a suitable Group tag instead") continue - + newhost = lxml.etree.Element("Client", name=host.tag) for opt in host: newopt = lxml.etree.Element("Option", name=opt.tag) diff --git a/tools/upgrade/1.2/packages-convert.py b/tools/upgrade/1.2/packages-convert.py index d65ce90a2..eb1f2f7de 100755 --- a/tools/upgrade/1.2/packages-convert.py +++ b/tools/upgrade/1.2/packages-convert.py @@ -30,10 +30,13 @@ def place_source(xdata, source, groups): return xdata def main(): - opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY} - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) - repo = setup['repo'] + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.1-style Packages configuration to " + "1.2-style") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + + repo = Bcfg2.Options.setup.repository configpath = os.path.join(repo, 'Packages') oldconfigfile = os.path.join(configpath, 'config.xml') newconfigfile = os.path.join(configpath, 'packages.conf') @@ -78,7 +81,7 @@ def main(): if el.tag == lxml.etree.Comment or el.tag == 'Config': # skip comments and Config continue - + if el.tag == XI + 'include': oldsources.append(os.path.join(configpath, el.get('href'))) newsource.append(el) @@ -98,7 +101,7 @@ def main(): newel.set(tag.lower(), el.find(tag).text) except AttributeError: pass - + for child in el.getchildren(): if child.tag in ['Component', 'Blacklist', 'Whitelist', 'Arch']: newel.append(child) diff --git a/tools/upgrade/1.3/migrate_configs.py b/tools/upgrade/1.3/migrate_configs.py index 76b2392e7..547ce61e4 100755 --- a/tools/upgrade/1.3/migrate_configs.py +++ b/tools/upgrade/1.3/migrate_configs.py @@ -5,6 +5,7 @@ import sys from Bcfg2.Compat import ConfigParser import Bcfg2.Options + def copy_section(src_file, tgt_cfg, section, newsection=None): if newsection is None: newsection = section @@ -16,13 +17,13 @@ def copy_section(src_file, tgt_cfg, section, newsection=None): tgt_cfg.add_section(newsection) except ConfigParser.DuplicateSectionError: print("[%s] section already exists in %s, adding options" % - (newsection, setup['configfile'])) + (newsection, Bcfg2.Options.setup.config)) for opt in cfg.options(section): val = cfg.get(section, opt) if tgt_cfg.has_option(newsection, opt): print("%s in [%s] already populated in %s, skipping" % - (opt, newsection, setup['configfile'])) - print(" %s: %s" % (setup['configfile'], + (opt, newsection, Bcfg2.Options.setup.config)) + print(" %s: %s" % (Bcfg2.Options.setup.config, tgt_cfg.get(newsection, opt))) print(" %s: %s" % (src_file, val)) else: @@ -30,47 +31,50 @@ def copy_section(src_file, tgt_cfg, section, newsection=None): tgt_cfg.set(newsection, opt, val) def main(): - opts = dict(repo=Bcfg2.Options.SERVER_REPOSITORY, - configfile=Bcfg2.Options.CFILE) - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.2 per-plugin config files to 1.3 " + "unified config file") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + repo = Bcfg2.Options.setup.repository + cfp = ConfigParser.ConfigParser() + cfp.read(Bcfg2.Options.setup.config) # files that you should remove manually remove = [] # move rules config out of rules.conf and into bcfg2.conf - rules_conf = os.path.join(setup['repo'], 'Rules', 'rules.conf') + rules_conf = os.path.join(repo, 'Rules', 'rules.conf') if os.path.exists(rules_conf): remove.append(rules_conf) - copy_section(rules_conf, setup.cfp, "rules") + copy_section(rules_conf, cfp, "rules") # move packages config out of packages.conf and into bcfg2.conf - pkgs_conf = os.path.join(setup['repo'], 'Packages', 'packages.conf') + pkgs_conf = os.path.join(repo, 'Packages', 'packages.conf') if os.path.exists(pkgs_conf): remove.append(pkgs_conf) - copy_section(pkgs_conf, setup.cfp, "global", newsection="packages") + copy_section(pkgs_conf, cfp, "global", newsection="packages") for section in ["apt", "yum", "pulp"]: - copy_section(pkgs_conf, setup.cfp, section, + copy_section(pkgs_conf, cfp, section, newsection="packages:" + section) # move reports database config into [database] section - if setup.cfp.has_section("statistics"): - if not setup.cfp.has_section("database"): - setup.cfp.add_section("database") - for opt in setup.cfp.options("statistics"): + if cfp.has_section("statistics"): + if not cfp.has_section("database"): + cfp.add_section("database") + for opt in cfp.options("statistics"): if opt.startswith("database_"): newopt = opt[9:] - if setup.cfp.has_option("database", newopt): + if cfp.has_option("database", newopt): print("%s in [database] already populated, skipping" % newopt) else: - setup.cfp.set("database", newopt, - setup.cfp.get("statistics", opt)) - setup.cfp.remove_option("statistics", opt) + cfp.set("database", newopt, cfp.get("statistics", opt)) + cfp.remove_option("statistics", opt) - print("Writing %s" % setup['configfile']) + print("Writing %s" % Bcfg2.Options.setup.config) try: - setup.cfp.write(open(setup['configfile'], "w")) + cfp.write(open(Bcfg2.Options.setup.config, "w")) if len(remove): print("Settings were migrated, but you must remove these files " "manually:") @@ -78,7 +82,7 @@ def main(): print(" %s" % path) except IOError: err = sys.exc_info()[1] - print("Could not write %s: %s" % (setup['configfile'], err)) + print("Could not write %s: %s" % (Bcfg2.Options.setup.config, err)) if __name__ == '__main__': sys.exit(main()) diff --git a/tools/upgrade/1.3/migrate_dbstats.py b/tools/upgrade/1.3/migrate_dbstats.py index 34430e3df..de8aef973 100755 --- a/tools/upgrade/1.3/migrate_dbstats.py +++ b/tools/upgrade/1.3/migrate_dbstats.py @@ -2,17 +2,14 @@ import os os.environ['BCFG2_LEGACY_MODELS'] = '1' -os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings' import sys import logging import time import Bcfg2.Logger import Bcfg2.Options -from django.core.cache import cache -from django.db import connection, backend - -from Bcfg2.Server.Admin.Reports import Reports +from django.db import connection, transaction, backend +from Bcfg2.Server.Admin import UpdateReports from Bcfg2.Reporting import models as new_models from Bcfg2.Reporting.utils import BatchFetch from Bcfg2.Reporting.Compat import transaction @@ -282,17 +279,10 @@ def _restructure(): if __name__ == '__main__': - Bcfg2.Logger.setup_logging('bcfg2-report-collector', - to_console=logging.INFO, - level=logging.INFO) - - optinfo = dict() - optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) - optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) - - #sync! - Reports(setup).__call__(['update']) + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.2 DBStats plugin to 1.3 Reporting " + "subsystem", + components=[UpdateReports]) + UpdateReports().run(Bcfg2.Options.setup) _restructure() diff --git a/tools/upgrade/1.3/migrate_info.py b/tools/upgrade/1.3/migrate_info.py index 3ccbf0285..7f3bb9a29 100755 --- a/tools/upgrade/1.3/migrate_info.py +++ b/tools/upgrade/1.3/migrate_info.py @@ -5,7 +5,16 @@ import re import sys import lxml.etree import Bcfg2.Options -from Bcfg2.Server.Plugin import INFO_REGEX + +INFO_REGEX = re.compile(r'owner:\s*(?P<owner>\S+)|' + + r'group:\s*(?P<group>\S+)|' + + r'mode:\s*(?P<mode>\w+)|' + + r'secontext:\s*(?P<secontext>\S+)|' + + r'paranoid:\s*(?P<paranoid>\S+)|' + + r'sensitive:\s*(?P<sensitive>\S+)|' + + r'encoding:\s*(?P<encoding>\S+)|' + + r'important:\s*(?P<important>\S+)|' + + r'mtime:\s*(?P<mtime>\w+)') PERMS_REGEX = re.compile(r'perms:\s*(?P<perms>\w+)') @@ -32,16 +41,17 @@ def convert(info_file): def main(): - opts = dict(repo=Bcfg2.Options.SERVER_REPOSITORY, - configfile=Bcfg2.Options.CFILE, - plugins=Bcfg2.Options.SERVER_PLUGINS) - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.2 info/:info files to 1.3 info.xml") + parser.add_options([Bcfg2.Options.Common.repository, + Bcfg2.Options.Common.plugins]) + parser.parse() - for plugin in setup['plugins']: + for plugin in Bcfg2.Options.setup.plugins: if plugin not in ['SSLCA', 'Cfg', 'TGenshi', 'TCheetah', 'SSHbase']: continue - for root, dirs, files in os.walk(os.path.join(setup['repo'], plugin)): + datastore = os.path.join(Bcfg2.Options.setup.repository, plugin) + for root, dirs, files in os.walk(datastore): for fname in files: if fname in [":info", "info"]: convert(os.path.join(root, fname)) diff --git a/tools/upgrade/1.3/migrate_perms_to_mode.py b/tools/upgrade/1.3/migrate_perms_to_mode.py index ee440bc8e..2dfb70388 100755 --- a/tools/upgrade/1.3/migrate_perms_to_mode.py +++ b/tools/upgrade/1.3/migrate_perms_to_mode.py @@ -4,13 +4,14 @@ import lxml.etree import os import sys from fnmatch import fnmatch -from Bcfg2.Compat import any +from Bcfg2.Compat import any # pylint: disable=W0622 +from Bcfg2.Server.FileMonitor import FileMonitor import Bcfg2.Options def setmodeattr(elem): """Set the mode attribute for a given element.""" - if elem.attrib.has_key('perms'): + if 'perms' in elem.attrib: elem.set('mode', elem.get('perms')) del elem.attrib['perms'] return True @@ -54,33 +55,34 @@ def convertstructure(structfile): writefile(structfile, xdata) -def skip_path(path, setup): +def skip_path(path): return any(fnmatch(path, p) or fnmatch(os.path.basename(path), p) - for p in setup['ignore']) + for p in Bcfg2.Options.setup.ignore_files) def main(): - opts = dict(repo=Bcfg2.Options.SERVER_REPOSITORY, - configfile=Bcfg2.Options.CFILE, - ignore=Bcfg2.Options.SERVER_FAM_IGNORE, - plugins=Bcfg2.Options.SERVER_PLUGINS) - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) - repo = setup['repo'] + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.2 'perms' attribute to 1.3 'mode' " + "attribute", + components=FileMonitor) + parser.add_options([Bcfg2.Options.Common.repository, + Bcfg2.Options.Common.plugins]) + parser.parse() + repo = Bcfg2.Options.setup.repository - for plugin in setup['plugins']: + for plugin in Bcfg2.Options.setup.plugins: if plugin in ['Base', 'Bundler', 'Rules']: - for root, dirs, files in os.walk(os.path.join(repo, plugin)): - if skip_path(root, setup): + for root, _, files in os.walk(os.path.join(repo, plugin)): + if skip_path(root): continue for fname in files: - if skip_path(fname, setup): + if skip_path(fname): continue convertstructure(os.path.join(root, fname)) if plugin not in ['Cfg', 'TGenshi', 'TCheetah', 'SSHbase', 'SSLCA']: continue for root, dirs, files in os.walk(os.path.join(repo, plugin)): - if skip_path(root, setup): + if skip_path(root): continue for fname in files: if fname == 'info.xml': diff --git a/tools/upgrade/1.3/migrate_probe_groups_to_db.py b/tools/upgrade/1.3/migrate_probe_groups_to_db.py index 73339e787..f9abbf982 100755 --- a/tools/upgrade/1.3/migrate_probe_groups_to_db.py +++ b/tools/upgrade/1.3/migrate_probe_groups_to_db.py @@ -4,16 +4,13 @@ and Probe plugins. Does not migrate individual probe return data. Assumes migration to BOTH Metadata and Probe to database backends. """ import os -os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings' - -import lxml.etree import sys +import lxml.etree import Bcfg2.Options +import Bcfg2.DBSettings -from Bcfg2.Server.Plugins.Metadata import MetadataClientModel -from Bcfg2.Server.Plugins.Probes import ProbesGroupsModel -def migrate(xclient): +def migrate(xclient, MetadataClientModel, ProbesGroupsModel): """ Helper to do the migration given a <Client/> XML element """ client_name = xclient.get('name') try: @@ -32,9 +29,11 @@ def migrate(xclient): group_name = xgroup.get('name') cgroups.append(group_name) try: - group = ProbesGroupsModel.objects.get(hostname=client_name, group=group_name) + group = ProbesGroupsModel.objects.get(hostname=client_name, + group=group_name) except ProbesGroupsModel.DoesNotExist: - group = ProbesGroupsModel(hostname=client_name, group=group_name) + group = ProbesGroupsModel(hostname=client_name, + group=group_name) group.save() ProbesGroupsModel.objects.filter( @@ -46,6 +45,7 @@ def migrate(xclient): return False return True + def main(): """ Main """ opts = dict(repo=Bcfg2.Options.SERVER_REPOSITORY) @@ -59,10 +59,15 @@ def main(): except lxml.etree.XMLSyntaxError: err = sys.exc_info()[1] print("Could not parse %s, skipping: %s" % (probefile, err)) - + + # these must be loaded after option parsing is complete + from Bcfg2.Server.Plugins.Metadata import MetadataClientModel + from Bcfg2.Server.Plugins.Probes import ProbesGroupsModel + for xclient in xdata.findall('Client'): - print "Migrating Metadata and Probe groups for %s" % xclient.get('name') - migrate(xclient) + print("Migrating Metadata and Probe groups for %s" % + xclient.get('name')) + migrate(xclient, MetadataClientModel, ProbesGroupsModel) if __name__ == '__main__': sys.exit(main()) diff --git a/tools/upgrade/1.3/service_modes.py b/tools/upgrade/1.3/service_modes.py index 0c458c3a9..d8e3c9e6f 100755 --- a/tools/upgrade/1.3/service_modes.py +++ b/tools/upgrade/1.3/service_modes.py @@ -6,14 +6,18 @@ import glob import lxml.etree import Bcfg2.Options + def main(): - opts = dict(repo=Bcfg2.Options.SERVER_REPOSITORY) - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.2 Service modes to 1.3-style " + "granular Service specification") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() files = [] for plugin in ['Bundler', 'Rules', 'Default']: - files.extend(glob.glob(os.path.join(setup['repo'], plugin, "*"))) + files.extend(glob.glob(os.path.join(Bcfg2.Options.setup.repository, + plugin, "*"))) for bfile in files: bdata = lxml.etree.parse(bfile) diff --git a/tools/upgrade/1.4/README b/tools/upgrade/1.4/README new file mode 100644 index 000000000..b03cb9b74 --- /dev/null +++ b/tools/upgrade/1.4/README @@ -0,0 +1,14 @@ +This directory contains scripts to help with upgrading from Bcfg2 1.3 +to 1.4. + +migrate_decisions.py + - Convert old group- and host-specific whitelist and blacklist + files into structured XML + +convert_bundles.py + - Remove deprecated explicit bundle names, rename .genshi bundles + to .xml + +migrate_sslca.py + - Migrate from the standalone SSLCA plugin to the built-in SSL + certificate generation abilities of the Cfg plugin
\ No newline at end of file diff --git a/tools/upgrade/1.4/convert_bundles.py b/tools/upgrade/1.4/convert_bundles.py new file mode 100755 index 000000000..b9cb483f2 --- /dev/null +++ b/tools/upgrade/1.4/convert_bundles.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +import os +import sys +import lxml.etree +import Bcfg2.Options + + +def main(): + parser = Bcfg2.Options.get_parser("Tool to remove bundle names") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + + bundler_dir = os.path.join(Bcfg2.Options.setup.repository, "Bundler") + if os.path.exists(bundler_dir): + for root, _, files in os.walk(bundler_dir): + for fname in files: + bpath = os.path.join(root, fname) + newpath = bpath + if newpath.endswith(".genshi"): + newpath = newpath[:-6] + "xml" + print("Converting %s to %s" % (bpath, newpath)) + else: + print("Converting %s" % bpath) + xroot = lxml.etree.parse(bpath) + xdata = xroot.getroot() + if 'name' in xdata.attrib: + del xdata.attrib['name'] + xroot.write(bpath) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/upgrade/1.4/migrate_decisions.py b/tools/upgrade/1.4/migrate_decisions.py new file mode 100755 index 000000000..d0915f202 --- /dev/null +++ b/tools/upgrade/1.4/migrate_decisions.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +import os +import re +import sys +import glob +import lxml.etree +import Bcfg2.Options + + +SPECIFIC = re.compile(r'.*\/(white|black)list' + r'(\.(H_(?P<host>.*)|G\d+_(?P<group>.*)))?$') + + +def convert(files, xdata): + hosts = [] + groups = [] + for oldfile in files: + spec = SPECIFIC.match(oldfile) + if spec and spec.group('host'): + hosts.append(spec.group('host')) + elif spec and spec.group('group'): + groups.append(spec.group('group')) + + for oldfile in files: + print("Converting %s" % oldfile) + spec = SPECIFIC.match(oldfile) + if not spec: + print("Skipping unknown file %s" % oldfile) + continue + + parent = xdata + if spec.group('host'): + for host in hosts: + if host != spec.group('host'): + parent = lxml.etree.SubElement(parent, "Client", + name=host, negate="true") + parent = lxml.etree.SubElement(parent, "Client", + name=spec.group('host')) + elif spec.group('group'): + for host in hosts: + parent = lxml.etree.SubElement(parent, "Client", + name=host, negate="true") + for group in groups: + if group != spec.group('group'): + parent = lxml.etree.SubElement(parent, "Group", + name=group, negate="true") + parent = lxml.etree.SubElement(parent, "Group", + name=spec.group('group')) + parent.append(lxml.etree.Comment("Converted from %s" % oldfile)) + olddata = lxml.etree.parse(oldfile, parser=Bcfg2.Server.XMLParser) + for decision in olddata.xpath('//Decision'): + parent.append(decision) + return xdata + + +def main(): + parser = Bcfg2.Options.get_parser( + description="Migrate from Bcfg2 1.3 Decisions list format to 1.4 " + "format") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + + datadir = os.path.join(Bcfg2.Options.setup.repository, 'Decisions') + whitelist = lxml.etree.Element("Decisions") + blacklist = lxml.etree.Element("Decisions") + if os.path.exists(datadir): + convert(glob.glob(os.path.join(datadir, 'whitelist*')), + whitelist) + convert(glob.glob(os.path.join(datadir, 'blacklist*')), + blacklist) + + print("Writing %s" % os.path.join(datadir, "whitelist.xml")) + open(os.path.join(datadir, "whitelist.xml"), + 'w').write(lxml.etree.tostring(whitelist, pretty_print=True)) + print("Writing %s" % os.path.join(datadir, "blacklist.xml")) + open(os.path.join(datadir, "blacklist.xml"), + 'w').write(lxml.etree.tostring(blacklist, pretty_print=True)) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/upgrade/1.4/migrate_sslca.py b/tools/upgrade/1.4/migrate_sslca.py new file mode 100755 index 000000000..958228c86 --- /dev/null +++ b/tools/upgrade/1.4/migrate_sslca.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +import os +import sys +import shutil +import Bcfg2.Options + + +def main(): + parser = Bcfg2.Options.get_parser( + description="Migrate from the SSLCA plugin to built-in Cfg SSL cert " + "generation") + parser.add_options([Bcfg2.Options.Common.repository]) + parser.parse() + + sslcadir = os.path.join(Bcfg2.Options.setup.repository, 'SSLCA') + cfgdir = os.path.join(Bcfg2.Options.setup.repository, 'Cfg') + for root, _, files in os.walk(sslcadir): + if not files: + continue + newpath = cfgdir + root[len(sslcadir):] + if not os.path.exists(newpath): + print("Creating %s and copying contents from %s" % (newpath, root)) + shutil.copytree(root, newpath) + else: + print("Copying contents from %s to %s" % (root, newpath)) + for fname in files: + newfpath = os.path.exists(os.path.join(newpath, fname)) + if newfpath: + print("%s already exists, skipping" % newfpath) + else: + shutil.copy(os.path.join(root, fname), newpath) + cert = os.path.join(newpath, "cert.xml") + newcert = os.path.join(newpath, "sslcert.xml") + key = os.path.join(newpath, "key.xml") + newkey = os.path.join(newpath, "sslkey.xml") + if os.path.exists(cert): + os.rename(cert, newcert) + if os.path.exists(key): + os.rename(key, newkey) + + +if __name__ == '__main__': + sys.exit(main()) |