summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/lib/Bcfg2/Client/Frame.py418
-rw-r--r--build/lib/Bcfg2/Client/Tools/APT.py218
-rw-r--r--build/lib/Bcfg2/Client/Tools/Action.py83
-rw-r--r--build/lib/Bcfg2/Client/Tools/Blast.py34
-rw-r--r--build/lib/Bcfg2/Client/Tools/Chkconfig.py101
-rw-r--r--build/lib/Bcfg2/Client/Tools/DebInit.py117
-rw-r--r--build/lib/Bcfg2/Client/Tools/Encap.py55
-rw-r--r--build/lib/Bcfg2/Client/Tools/FreeBSDInit.py27
-rw-r--r--build/lib/Bcfg2/Client/Tools/FreeBSDPackage.py47
-rw-r--r--build/lib/Bcfg2/Client/Tools/IPS.py61
-rw-r--r--build/lib/Bcfg2/Client/Tools/MacPorts.py60
-rw-r--r--build/lib/Bcfg2/Client/Tools/POSIX.py766
-rw-r--r--build/lib/Bcfg2/Client/Tools/Pacman.py82
-rw-r--r--build/lib/Bcfg2/Client/Tools/Portage.py71
-rw-r--r--build/lib/Bcfg2/Client/Tools/RPMng.py1034
-rw-r--r--build/lib/Bcfg2/Client/Tools/RcUpdate.py93
-rw-r--r--build/lib/Bcfg2/Client/Tools/SMF.py132
-rw-r--r--build/lib/Bcfg2/Client/Tools/SYSV.py107
-rw-r--r--build/lib/Bcfg2/Client/Tools/Upstart.py78
-rw-r--r--build/lib/Bcfg2/Client/Tools/YUMng.py848
-rw-r--r--build/lib/Bcfg2/Client/Tools/__init__.py370
-rw-r--r--build/lib/Bcfg2/Client/Tools/launchd.py131
-rw-r--r--build/lib/Bcfg2/Client/Tools/rpmtools.py1115
-rw-r--r--build/lib/Bcfg2/Client/XML.py37
-rw-r--r--build/lib/Bcfg2/Client/__init__.py4
-rw-r--r--build/lib/Bcfg2/Component.py277
-rw-r--r--build/lib/Bcfg2/Logger.py233
-rw-r--r--build/lib/Bcfg2/Options.py334
-rw-r--r--build/lib/Bcfg2/Proxy.py316
-rw-r--r--build/lib/Bcfg2/SSLServer.py416
-rw-r--r--build/lib/Bcfg2/Server/Admin/Backup.py33
-rw-r--r--build/lib/Bcfg2/Server/Admin/Bundle.py100
-rw-r--r--build/lib/Bcfg2/Server/Admin/Client.py64
-rw-r--r--build/lib/Bcfg2/Server/Admin/Compare.py137
-rw-r--r--build/lib/Bcfg2/Server/Admin/Examples.py71
-rw-r--r--build/lib/Bcfg2/Server/Admin/Group.py66
-rw-r--r--build/lib/Bcfg2/Server/Admin/Init.py280
-rw-r--r--build/lib/Bcfg2/Server/Admin/Minestruct.py69
-rw-r--r--build/lib/Bcfg2/Server/Admin/Perf.py37
-rw-r--r--build/lib/Bcfg2/Server/Admin/Pull.py138
-rw-r--r--build/lib/Bcfg2/Server/Admin/Query.py78
-rw-r--r--build/lib/Bcfg2/Server/Admin/Reports.py357
-rw-r--r--build/lib/Bcfg2/Server/Admin/Snapshots.py163
-rw-r--r--build/lib/Bcfg2/Server/Admin/Tidy.py66
-rw-r--r--build/lib/Bcfg2/Server/Admin/Viz.py101
-rw-r--r--build/lib/Bcfg2/Server/Admin/Web.py79
-rw-r--r--build/lib/Bcfg2/Server/Admin/Xcmd.py49
-rw-r--r--build/lib/Bcfg2/Server/Admin/__init__.py114
-rw-r--r--build/lib/Bcfg2/Server/Admin/test.py73
-rw-r--r--build/lib/Bcfg2/Server/Core.py439
-rw-r--r--build/lib/Bcfg2/Server/FileMonitor.py307
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/__init__.py0
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/backends.py68
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py0
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/hostbase/admin.py15
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/hostbase/models.py210
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/hostbase/urls.py68
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/hostbase/views.py972
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/ldapauth.py172
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/manage.py11
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/nisauth.py42
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/regex.py6
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/settings.py142
-rw-r--r--build/lib/Bcfg2/Server/Hostbase/urls.py27
-rw-r--r--build/lib/Bcfg2/Server/Plugin.py886
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Account.py93
-rw-r--r--build/lib/Bcfg2/Server/Plugins/BB.py84
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Base.py38
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Bundler.py76
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Bzr.py36
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Cfg.py165
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Cvs.py47
-rw-r--r--build/lib/Bcfg2/Server/Plugins/DBStats.py110
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Darcs.py49
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Decisions.py64
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Deps.py103
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Editor.py73
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Fossil.py52
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Git.py45
-rw-r--r--build/lib/Bcfg2/Server/Plugins/GroupPatterns.py117
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Guppy.py63
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Hg.py47
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Hostbase.py585
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Metadata.py809
-rw-r--r--build/lib/Bcfg2/Server/Plugins/NagiosGen.py114
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Ohai.py79
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Packages.py869
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Pkgmgr.py155
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Probes.py150
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Properties.py37
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Rules.py11
-rw-r--r--build/lib/Bcfg2/Server/Plugins/SGenshi.py76
-rw-r--r--build/lib/Bcfg2/Server/Plugins/SSHbase.py279
-rw-r--r--build/lib/Bcfg2/Server/Plugins/SSLCA.py239
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Snapshots.py130
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Statistics.py161
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Svcmgr.py12
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Svn.py46
-rw-r--r--build/lib/Bcfg2/Server/Plugins/TCheetah.py78
-rw-r--r--build/lib/Bcfg2/Server/Plugins/TGenshi.py126
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Trigger.py37
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Web.py47
-rw-r--r--build/lib/Bcfg2/Server/Plugins/__Web.py47
-rw-r--r--build/lib/Bcfg2/Server/Plugins/__init__.py35
-rw-r--r--build/lib/Bcfg2/Server/Reports/__init__.py1
-rw-r--r--build/lib/Bcfg2/Server/Reports/backends.py35
-rw-r--r--build/lib/Bcfg2/Server/Reports/importscript.py270
-rw-r--r--build/lib/Bcfg2/Server/Reports/manage.py11
-rw-r--r--build/lib/Bcfg2/Server/Reports/nisauth.py43
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/__init__.py1
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/fixtures/initial_version.xml35
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/models.py328
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/404.html8
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/base-timeview.html25
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/base.html95
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/clients/detail.html127
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html46
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/clients/history.html20
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html34
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/clients/manage.html45
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html109
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/config_items/listing.html33
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/displays/summary.html42
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/displays/timing.html38
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/widgets/filter_bar.html13
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc38
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templates/widgets/page_bar.html23
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templatetags/__init__.py0
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py274
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/templatetags/syntax_coloring.py41
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/urls.py55
-rw-r--r--build/lib/Bcfg2/Server/Reports/reports/views.py379
-rw-r--r--build/lib/Bcfg2/Server/Reports/settings.py144
-rw-r--r--build/lib/Bcfg2/Server/Reports/updatefix.py184
-rw-r--r--build/lib/Bcfg2/Server/Reports/urls.py14
-rw-r--r--build/lib/Bcfg2/Server/Reports/utils.py116
-rw-r--r--build/lib/Bcfg2/Server/Snapshots/__init__.py30
-rw-r--r--build/lib/Bcfg2/Server/Snapshots/model.py278
-rw-r--r--build/lib/Bcfg2/Server/__init__.py6
-rw-r--r--build/lib/Bcfg2/Statistics.py32
-rw-r--r--build/lib/Bcfg2/__init__.py4
-rwxr-xr-xbuild/scripts-2.7/bcfg2313
-rwxr-xr-xbuild/scripts-2.7/bcfg2-admin80
-rwxr-xr-xbuild/scripts-2.7/bcfg2-build-reports319
-rwxr-xr-xbuild/scripts-2.7/bcfg2-info468
-rwxr-xr-xbuild/scripts-2.7/bcfg2-ping-sweep71
-rwxr-xr-xbuild/scripts-2.7/bcfg2-repo-validate227
-rwxr-xr-xbuild/scripts-2.7/bcfg2-reports282
-rwxr-xr-xbuild/scripts-2.7/bcfg2-server79
149 files changed, 0 insertions, 23305 deletions
diff --git a/build/lib/Bcfg2/Client/Frame.py b/build/lib/Bcfg2/Client/Frame.py
deleted file mode 100644
index 545d4b584..000000000
--- a/build/lib/Bcfg2/Client/Frame.py
+++ /dev/null
@@ -1,418 +0,0 @@
-"""
-Frame is the Client Framework that verifies and
-installs entries, and generates statistics.
-"""
-__revision__ = '$Revision$'
-
-import logging
-import time
-import Bcfg2.Client.Tools
-
-def cmpent(ent1, ent2):
- """Sort entries."""
- if ent1.tag != ent2.tag:
- return cmp(ent1.tag, ent2.tag)
- else:
- return cmp(ent1.get('name'), ent2.get('name'))
-
-def promptFilter(prompt, entries):
- """Filter a supplied list based on user input."""
- ret = []
- entries.sort(cmpent)
- for entry in entries[:]:
- if 'qtext' in entry.attrib:
- iprompt = entry.get('qtext')
- else:
- iprompt = prompt % (entry.tag, entry.get('name'))
- try:
- if raw_input(iprompt) in ['y', 'Y']:
- ret.append(entry)
- except EOFError:
- # python 2.4.3 on CentOS doesn't like ^C for some reason
- break
- except:
- print("Error while reading input")
- continue
- return ret
-
-def matches_entry(entryspec, entry):
- # both are (tag, name)
- if entryspec == entry:
- return True
- else:
- for i in [0, 1]:
- if entryspec[i] == entry[i]:
- continue
- elif entryspec[i] == '*':
- continue
- elif '*' in entryspec[i]:
- starpt = entryspec[i].index('*')
- if entry[i].startswith(entryspec[i][:starpt]):
- continue
- return False
- return True
-
-def matches_white_list(entry, whitelist):
- return True in [matches_entry(we, (entry.tag, entry.get('name'))) for we in whitelist]
-
-def passes_black_list(entry, blacklist):
- return True not in [matches_entry(be, (entry.tag, entry.get('name'))) for be in blacklist]
-
-class Frame:
- """Frame is the container for all Tool objects and state information."""
- def __init__(self, config, setup, times, drivers, dryrun):
- self.config = config
- self.times = times
- self.dryrun = dryrun
- self.times['initialization'] = time.time()
- self.setup = setup
- self.tools = []
- self.states = {}
- self.whitelist = []
- self.blacklist = []
- self.removal = []
- self.logger = logging.getLogger("Bcfg2.Client.Frame")
- for driver in drivers[:]:
- if driver not in Bcfg2.Client.Tools.drivers and \
- isinstance(driver, str):
- self.logger.error("Tool driver %s is not available" % driver)
- drivers.remove(driver)
-
- tclass = {}
- for tool in drivers:
- if not isinstance(tool, str):
- tclass[time.time()] = tool
- tool_class = "Bcfg2.Client.Tools.%s" % tool
- try:
- tclass[tool] = getattr(__import__(tool_class, globals(),
- locals(), ['*']),
- tool)
- except ImportError:
- continue
- except:
- self.logger.error("Tool %s unexpectedly failed to load" % tool,
- exc_info=1)
-
- for tool in list(tclass.values()):
- try:
- self.tools.append(tool(self.logger, setup, config))
- except Bcfg2.Client.Tools.toolInstantiationError:
- continue
- except:
- self.logger.error("Failed to instantiate tool %s" % \
- (tool), exc_info=1)
-
- for tool in self.tools[:]:
- for conflict in getattr(tool, 'conflicts', []):
- [self.tools.remove(item) for item in self.tools \
- if item.name == conflict]
-
- self.logger.info("Loaded tool drivers:")
- self.logger.info([tool.name for tool in self.tools])
- if not self.dryrun and not self.setup['bundle']:
- for cfile in [cfl for cfl in config.findall(".//Path") \
- if cfl.get('name') in self.__important__ and \
- cfl.get('type') == 'file']:
- tl = [t for t in self.tools if t.handlesEntry(cfile) \
- and t.canVerify(cfile)]
- if tl:
- if not tl[0].VerifyPath(cfile, []):
- if self.setup['interactive'] and not \
- promptFilter("Install %s: %s? (y/N):", [cfile]):
- continue
- try:
- self.states[cfile] = tl[0].InstallPath(cfile)
- except:
- self.logger.error("Unexpected tool failure",
- exc_info=1)
- # find entries not handled by any tools
- problems = [entry for struct in config for \
- entry in struct if entry not in self.handled]
-
- if problems:
- self.logger.error("The following entries are not handled by any tool:")
- self.logger.error(["%s:%s:%s" % (entry.tag, entry.get('type'), \
- entry.get('name')) for entry in problems])
- self.logger.error("")
- entries = [(entry.tag, entry.get('name')) for struct in config for entry in struct]
- pkgs = [(entry.get('name'), entry.get('origin')) for struct in config for entry in struct if entry.tag == 'Package']
- multi = []
- for entry in entries[:]:
- if entries.count(entry) > 1:
- multi.append(entry)
- entries.remove(entry)
- if multi:
- self.logger.debug("The following entries are included multiple times:")
- self.logger.debug(["%s:%s" % entry for entry in multi])
- self.logger.debug("")
- if pkgs:
- self.logger.debug("The following packages are specified in bcfg2:")
- self.logger.debug([pkg[0] for pkg in pkgs if pkg[1] == None])
- self.logger.debug("The following packages are prereqs added by Packages:")
- self.logger.debug([pkg[0] for pkg in pkgs if pkg[1] == 'Packages'])
-
-
- def __getattr__(self, name):
- if name in ['extra', 'handled', 'modified', '__important__']:
- ret = []
- for tool in self.tools:
- ret += getattr(tool, name)
- return ret
- elif name in self.__dict__:
- return self.__dict__[name]
- raise AttributeError(name)
-
- def Inventory(self):
- """
- Verify all entries,
- find extra entries,
- and build up workqueues
-
- """
- # initialize all states
- for struct in self.config.getchildren():
- for entry in struct.getchildren():
- self.states[entry] = False
- for tool in self.tools:
- try:
- tool.Inventory(self.states)
- except:
- self.logger.error("%s.Inventory() call failed:" % tool.name, exc_info=1)
-
- def Decide(self):
- """Set self.whitelist based on user interaction."""
- prompt = "Install %s: %s? (y/N): "
- rprompt = "Remove %s: %s? (y/N): "
- if self.setup['remove']:
- if self.setup['remove'] == 'all':
- self.removal = self.extra
- elif self.setup['remove'] == 'services':
- self.removal = [entry for entry in self.extra \
- if entry.tag == 'Service']
- elif self.setup['remove'] == 'packages':
- self.removal = [entry for entry in self.extra \
- if entry.tag == 'Package']
-
- candidates = [entry for entry in self.states \
- if not self.states[entry]]
- self.whitelist = [entry for entry in self.states \
- if not self.states[entry]]
- # Need to process decision stuff early so that dryrun mode works with it
- if self.setup['decision'] == 'whitelist':
- dwl = self.setup['decision_list']
- w_to_rem = [e for e in self.whitelist \
- if not matches_white_list(e, dwl)]
- if w_to_rem:
- self.logger.info("In whitelist mode: suppressing installation of:")
- self.logger.info(["%s:%s" % (e.tag, e.get('name')) for e in w_to_rem])
- self.whitelist = [x for x in self.whitelist \
- if x not in w_to_rem]
-
- elif self.setup['decision'] == 'blacklist':
- b_to_rem = [e for e in self.whitelist \
- if not passes_black_list(e, self.setup['decision_list'])]
- if b_to_rem:
- self.logger.info("In blacklist mode: suppressing installation of:")
- self.logger.info(["%s:%s" % (e.tag, e.get('name')) for e in b_to_rem])
- self.whitelist = [x for x in self.whitelist if x not in b_to_rem]
-
- if self.dryrun:
- if self.whitelist:
- self.logger.info("In dryrun mode: suppressing entry installation for:")
- self.logger.info(["%s:%s" % (entry.tag, entry.get('name')) for entry \
- in self.whitelist])
- self.whitelist = []
- if self.removal:
- self.logger.info("In dryrun mode: suppressing entry removal for:")
- self.logger.info(["%s:%s" % (entry.tag, entry.get('name')) for entry \
- in self.removal])
- self.removal = []
- return
- # Here is where most of the work goes
- # first perform bundle filtering
- if self.setup['bundle']:
- all_bundle_names = [b.get('name') for b in
- self.config.findall('./Bundle')]
- # warn if non-existent bundle given
- for bundle in self.setup['bundle']:
- if bundle not in all_bundle_names:
- self.logger.info("Warning: Bundle %s not found" % bundle)
- bundles = [b for b in self.config.findall('./Bundle') \
- if b.get('name') in self.setup['bundle']]
- self.whitelist = [e for e in self.whitelist if \
- True in [e in b for b in bundles]]
- elif self.setup['indep']:
- bundles = [nb for nb in self.config.getchildren() if nb.tag != \
- 'Bundle']
- else:
- bundles = self.config.getchildren()
-
- # first process prereq actions
- for bundle in bundles[:]:
- if bundle.tag != 'Bundle':
- continue
- actions = [a for a in bundle.findall('./Action') \
- if a.get('timing') != 'post']
- # now we process all "always actions"
- bmodified = len([item for item in bundle if item in self.whitelist])
- for action in actions:
- if bmodified or action.get('when') == 'always':
- self.DispatchInstallCalls([action])
- # need to test to fail entries in whitelist
- if False in [self.states[a] for a in actions]:
- # then display bundles forced off with entries
- self.logger.info("Bundle %s failed prerequisite action" % \
- (bundle.get('name')))
- bundles.remove(bundle)
- b_to_remv = [ent for ent in self.whitelist if ent in bundle]
- if b_to_remv:
- self.logger.info("Not installing entries from Bundle %s" % \
- (bundle.get('name')))
- self.logger.info(["%s:%s" % (e.tag, e.get('name')) for e in b_to_remv])
- [self.whitelist.remove(ent) for ent in b_to_remv]
-
- if self.setup['interactive']:
- self.whitelist = promptFilter(prompt, self.whitelist)
- self.removal = promptFilter(rprompt, self.removal)
-
- for entry in candidates:
- if entry not in self.whitelist:
- self.blacklist.append(entry)
-
- def DispatchInstallCalls(self, entries):
- """Dispatch install calls to underlying tools."""
- for tool in self.tools:
- handled = [entry for entry in entries if tool.canInstall(entry)]
- if not handled:
- continue
- try:
- tool.Install(handled, self.states)
- except:
- self.logger.error("%s.Install() call failed:" % tool.name, exc_info=1)
-
- def Install(self):
- """Install all entries."""
- self.DispatchInstallCalls(self.whitelist)
- mods = self.modified
- mbundles = [struct for struct in self.config.findall('Bundle') if \
- [mod for mod in mods if mod in struct]]
-
- if self.modified:
- # Handle Bundle interdeps
- if mbundles:
- self.logger.info("The Following Bundles have been modified:")
- self.logger.info([mbun.get('name') for mbun in mbundles])
- self.logger.info("")
- tbm = [(t, b) for t in self.tools for b in mbundles]
- for tool, bundle in tbm:
- try:
- tool.Inventory(self.states, [bundle])
- except:
- self.logger.error("%s.Inventory() call failed:" % tool.name, exc_info=1)
- clobbered = [entry for bundle in mbundles for entry in bundle \
- if not self.states[entry] and entry not in self.blacklist]
- if clobbered:
- self.logger.debug("Found clobbered entries:")
- self.logger.debug(["%s:%s" % (entry.tag, entry.get('name')) \
- for entry in clobbered])
- if not self.setup['interactive']:
- self.DispatchInstallCalls(clobbered)
-
- for bundle in self.config.findall('.//Bundle'):
- if self.setup['bundle'] and \
- bundle.get('name') not in self.setup['bundle']:
- # prune out unspecified bundles when running with -b
- continue
- for tool in self.tools:
- try:
- if bundle in mbundles:
- tool.BundleUpdated(bundle, self.states)
- else:
- tool.BundleNotUpdated(bundle, self.states)
- except:
- self.logger.error("%s.BundleNotUpdated() call failed:" % \
- (tool.name), exc_info=1)
-
- def Remove(self):
- """Remove extra entries."""
- for tool in self.tools:
- extras = [entry for entry in self.removal if tool.handlesEntry(entry)]
- if extras:
- try:
- tool.Remove(extras)
- except:
- self.logger.error("%s.Remove() failed" % tool.name, exc_info=1)
-
- def CondDisplayState(self, phase):
- """Conditionally print tracing information."""
- self.logger.info('\nPhase: %s' % phase)
- self.logger.info('Correct entries:\t%d' % list(self.states.values()).count(True))
- self.logger.info('Incorrect entries:\t%d' % list(self.states.values()).count(False))
- if phase == 'final' and list(self.states.values()).count(False):
- self.logger.info(["%s:%s" % (entry.tag, entry.get('name')) for \
- entry in self.states if not self.states[entry]])
- self.logger.info('Total managed entries:\t%d' % len(list(self.states.values())))
- self.logger.info('Unmanaged entries:\t%d' % len(self.extra))
- if phase == 'final' and self.setup['extra']:
- self.logger.info(["%s:%s" % (entry.tag, entry.get('name')) \
- for entry in self.extra])
-
- self.logger.info("")
-
- if ((list(self.states.values()).count(False) == 0) and not self.extra):
- self.logger.info('All entries correct.')
-
- def ReInventory(self):
- """Recheck everything."""
- if not self.dryrun and self.setup['kevlar']:
- self.logger.info("Rechecking system inventory")
- self.Inventory()
-
- def Execute(self):
- """Run all methods."""
- self.Inventory()
- self.times['inventory'] = time.time()
- self.CondDisplayState('initial')
- self.Decide()
- self.Install()
- self.times['install'] = time.time()
- self.Remove()
- self.times['remove'] = time.time()
- if self.modified:
- self.ReInventory()
- self.times['reinventory'] = time.time()
- self.times['finished'] = time.time()
- self.CondDisplayState('final')
-
- def GenerateStats(self):
- """Generate XML summary of execution statistics."""
- feedback = Bcfg2.Client.XML.Element("upload-statistics")
- stats = Bcfg2.Client.XML.SubElement(feedback,
- 'Statistics',
- total=str(len(self.states)),
- client_version=__revision__,
- version='2.0',
- revision=self.config.get('revision', '-1'))
- good = len([key for key, val in list(self.states.items()) if val])
- stats.set('good', str(good))
- if len([key for key, val in list(self.states.items()) if not val]) == 0:
- stats.set('state', 'clean')
- else:
- stats.set('state', 'dirty')
-
- # List bad elements of the configuration
- for (data, ename) in [(self.modified, 'Modified'), (self.extra, "Extra"), \
- ([entry for entry in self.states if not \
- self.states[entry]], "Bad")]:
- container = Bcfg2.Client.XML.SubElement(stats, ename)
- for item in data:
- item.set('qtext', '')
- container.append(item)
- item.text = None
-
- timeinfo = Bcfg2.Client.XML.Element("OpStamps")
- feedback.append(stats)
- for (event, timestamp) in list(self.times.items()):
- timeinfo.set(event, str(timestamp))
- stats.append(timeinfo)
- return feedback
diff --git a/build/lib/Bcfg2/Client/Tools/APT.py b/build/lib/Bcfg2/Client/Tools/APT.py
deleted file mode 100644
index 2afe2eab7..000000000
--- a/build/lib/Bcfg2/Client/Tools/APT.py
+++ /dev/null
@@ -1,218 +0,0 @@
-"""This is the bcfg2 support for apt-get"""
-__revision__ = '$Revision$'
-
-# suppress apt API warnings
-import warnings
-warnings.filterwarnings("ignore", "apt API not stable yet",
- FutureWarning)
-warnings.filterwarnings("ignore", "Accessed deprecated property Package.installedVersion, please see the Version class for alternatives.", DeprecationWarning)
-warnings.filterwarnings("ignore", "Accessed deprecated property Package.candidateVersion, please see the Version class for alternatives.", DeprecationWarning)
-warnings.filterwarnings("ignore", "Deprecated, please use 'is_installed' instead", DeprecationWarning)
-warnings.filterwarnings("ignore", "Attribute 'IsUpgradable' of the 'apt_pkg.DepCache' object is deprecated, use 'is_upgradable' instead.", DeprecationWarning)
-import apt.cache
-import os
-
-import Bcfg2.Client.Tools
-import Bcfg2.Options
-
-# Options for tool locations
-opts = {'install_path': Bcfg2.Options.CLIENT_APT_TOOLS_INSTALL_PATH,
- 'var_path': Bcfg2.Options.CLIENT_APT_TOOLS_VAR_PATH,
- 'etc_path': Bcfg2.Options.CLIENT_SYSTEM_ETC_PATH}
-setup = Bcfg2.Options.OptionParser(opts)
-setup.parse([])
-install_path = setup['install_path']
-var_path = setup['var_path']
-etc_path = setup['etc_path']
-DEBSUMS = '%s/bin/debsums' % install_path
-APTGET = '%s/bin/apt-get' % install_path
-DPKG = '%s/bin/dpkg' % install_path
-
-class APT(Bcfg2.Client.Tools.Tool):
- """The Debian toolset implements package and service operations and inherits
- the rest from Toolset.Toolset.
-
- """
- name = 'APT'
- __execs__ = [DEBSUMS, APTGET, DPKG]
- __handles__ = [('Package', 'deb')]
- __req__ = {'Package': ['name', 'version']}
- pkgcmd = '%s ' % APTGET + \
- '-o DPkg::Options::=--force-overwrite ' + \
- '-o DPkg::Options::=--force-confold ' + \
- '-o DPkg::Options::=--force-confmiss ' + \
- '--reinstall ' + \
- '-q=2 ' + \
- '--force-yes ' + \
- '-y install %s'
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.Tool.__init__(self, logger, setup, config)
- self.__important__ = self.__important__ + \
- ["%s/cache/debconf/config.dat" % var_path,
- "%s/cache/debconf/templates.dat" % var_path,
- '/etc/passwd', '/etc/group',
- '%s/apt/apt.conf' % etc_path,
- '%s/dpkg/dpkg.cfg' % etc_path] + \
- [entry.get('name') for struct in config for entry in struct \
- if entry.tag == 'Path' and \
- entry.get('name').startswith('%s/apt/sources.list' % etc_path)]
- self.nonexistent = [entry.get('name') for struct in config for entry in struct \
- if entry.tag == 'Path' and entry.get('type') == 'nonexistent']
- os.environ["DEBIAN_FRONTEND"] = 'noninteractive'
- self.actions = {}
- if self.setup['kevlar'] and not self.setup['dryrun']:
- self.cmd.run("%s --force-confold --configure --pending" % DPKG)
- self.cmd.run("%s clean" % APTGET)
- self.pkg_cache = apt.cache.Cache()
- self.pkg_cache.update()
- self.pkg_cache = apt.cache.Cache()
-
- def FindExtra(self):
- """Find extra packages."""
- packages = [entry.get('name') for entry in self.getSupportedEntries()]
- extras = [(p.name, p.installedVersion) for p in self.pkg_cache
- if p.isInstalled and p.name not in packages]
- return [Bcfg2.Client.XML.Element('Package', name=name, \
- type='deb', version=version) \
- for (name, version) in extras]
-
- def VerifyDebsums(self, entry, modlist):
- output = self.cmd.run("%s -as %s" % (DEBSUMS, entry.get('name')))[1]
- if len(output) == 1 and "no md5sums for" in output[0]:
- self.logger.info("Package %s has no md5sums. Cannot verify" % \
- entry.get('name'))
- entry.set('qtext', "Reinstall Package %s-%s to setup md5sums? (y/N) " \
- % (entry.get('name'), entry.get('version')))
- return False
- files = []
- for item in output:
- if "checksum mismatch" in item:
- files.append(item.split()[-1])
- elif "changed file" in item:
- files.append(item.split()[3])
- elif "can't open" in item:
- if item.split()[5] not in self.nonexistent:
- files.append(item.split()[5])
- elif "missing file" in item and \
- item.split()[3] in self.nonexistent:
- # these files should not exist
- continue
- elif "is not installed" in item or "missing file" in item:
- self.logger.error("Package %s is not fully installed" \
- % entry.get('name'))
- else:
- self.logger.error("Got Unsupported pattern %s from debsums" \
- % item)
- files.append(item)
- # We check if there is file in the checksum to do
- if files:
- # if files are found there we try to be sure our modlist is sane
- # with erroneous symlinks
- modlist = [os.path.realpath(filename) for filename in modlist]
- bad = [filename for filename in files if filename not in modlist]
- if bad:
- self.logger.info("Package %s failed validation. Bad files are:" % \
- entry.get('name'))
- self.logger.info(bad)
- entry.set('qtext',
- "Reinstall Package %s-%s to fix failing files? (y/N) " % \
- (entry.get('name'), entry.get('version')))
- return False
- return True
-
- def VerifyPackage(self, entry, modlist, checksums=True):
- """Verify package for entry."""
- if not 'version' in entry.attrib:
- self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
- return False
- pkgname = entry.get('name')
- if not self.pkg_cache.has_key(pkgname) \
- or not self.pkg_cache[pkgname].isInstalled:
- self.logger.info("Package %s not installed" % (entry.get('name')))
- entry.set('current_exists', 'false')
- return False
-
- pkg = self.pkg_cache[pkgname]
- if entry.get('version') == 'auto':
- if self.pkg_cache._depcache.IsUpgradable(pkg._pkg):
- desiredVersion = pkg.candidateVersion
- else:
- desiredVersion = pkg.installedVersion
- elif entry.get('version') == 'any':
- desiredVersion = pkg.installedVersion
- else:
- desiredVersion = entry.get('version')
- if desiredVersion != pkg.installedVersion:
- entry.set('current_version', pkg.installedVersion)
- entry.set('qtext', "Modify Package %s (%s -> %s)? (y/N) " % \
- (entry.get('name'), entry.get('current_version'),
- desiredVersion))
- return False
- else:
- # version matches
- if not self.setup['quick'] and entry.get('verify', 'true') == 'true' \
- and checksums:
- pkgsums = self.VerifyDebsums(entry, modlist)
- return pkgsums
- return True
-
- def Remove(self, packages):
- """Deal with extra configuration detected."""
- pkgnames = " ".join([pkg.get('name') for pkg in packages])
- self.pkg_cache = apt.cache.Cache()
- if len(packages) > 0:
- self.logger.info('Removing packages:')
- self.logger.info(pkgnames)
- for pkg in pkgnames.split(" "):
- try:
- self.pkg_cache[pkg].markDelete(purge=True)
- except:
- self.pkg_cache[pkg].markDelete()
- try:
- self.pkg_cache.commit()
- except SystemExit:
- # thank you python-apt 0.6
- pass
- self.pkg_cache = apt.cache.Cache()
- self.modified += packages
- self.extra = self.FindExtra()
-
- def Install(self, packages, states):
- # it looks like you can't install arbitrary versions of software
- # out of the pkg cache, we will still need to call apt-get
- ipkgs = []
- bad_pkgs = []
- for pkg in packages:
- if not self.pkg_cache.has_key(pkg.get('name')):
- self.logger.error("APT has no information about package %s" % (pkg.get('name')))
- continue
- if pkg.get('version') in ['auto', 'any']:
- ipkgs.append("%s=%s" % (pkg.get('name'),
- self.pkg_cache[pkg.get('name')].candidateVersion))
- continue
- avail_vers = [x.VerStr for x in \
- self.pkg_cache[pkg.get('name')]._pkg.VersionList]
- if pkg.get('version') in avail_vers:
- ipkgs.append("%s=%s" % (pkg.get('name'), pkg.get('version')))
- continue
- else:
- self.logger.error("Package %s: desired version %s not in %s" \
- % (pkg.get('name'), pkg.get('version'),
- avail_vers))
- bad_pkgs.append(pkg.get('name'))
- if bad_pkgs:
- self.logger.error("Cannot find correct versions of packages:")
- self.logger.error(bad_pkgs)
- if not ipkgs:
- return
- rc = self.cmd.run(self.pkgcmd % (" ".join(ipkgs)))[0]
- if rc:
- self.logger.error("APT command failed")
- self.pkg_cache = apt.cache.Cache()
- self.extra = self.FindExtra()
- for package in packages:
- states[package] = self.VerifyPackage(package, [], checksums=False)
- if states[package]:
- self.modified.append(package)
diff --git a/build/lib/Bcfg2/Client/Tools/Action.py b/build/lib/Bcfg2/Client/Tools/Action.py
deleted file mode 100644
index 452788f94..000000000
--- a/build/lib/Bcfg2/Client/Tools/Action.py
+++ /dev/null
@@ -1,83 +0,0 @@
-"""Action driver"""
-__revision__ = '$Revision$'
-
-import Bcfg2.Client.Tools
-
-"""
-<Action timing='pre|post|both'
- name='name'
- command='cmd text'
- when='always|modified'
- status='ignore|check'/>
-<PostInstall name='foo'/>
- => <Action timing='post'
- when='modified'
- name='n'
- command='foo'
- status='ignore'/>
-"""
-
-
-class Action(Bcfg2.Client.Tools.Tool):
- """Implement Actions"""
- name = 'Action'
- __handles__ = [('PostInstall', None), ('Action', None)]
- __req__ = {'PostInstall': ['name'],
- 'Action': ['name', 'timing', 'when', 'command', 'status']}
-
- def RunAction(self, entry):
- """This method handles command execution and status return."""
- if not self.setup['dryrun']:
- if self.setup['interactive']:
- prompt = ('Run Action %s, %s: (y/N): ' %
- (entry.get('name'), entry.get('command')))
- if raw_input(prompt) not in ['y', 'Y']:
- return False
- if self.setup['servicemode'] == 'build':
- if entry.get('build', 'true') == 'false':
- self.logger.debug("Action: Deferring execution of %s due to build mode" % (entry.get('command')))
- return False
- self.logger.debug("Running Action %s" % (entry.get('name')))
- rc = self.cmd.run(entry.get('command'))[0]
- self.logger.debug("Action: %s got rc %s" % (entry.get('command'), rc))
- entry.set('rc', str(rc))
- if entry.get('status', 'check') == 'ignore':
- return True
- else:
- return rc == 0
- else:
- self.logger.debug("In dryrun mode: not running action:\n %s" %
- (entry.get('name')))
- return False
-
- def VerifyAction(self, dummy, _):
- """Actions always verify true."""
- return True
-
- def VerifyPostInstall(self, dummy, _):
- """Actions always verify true."""
- return True
-
- def InstallAction(self, entry):
- """Run actions as pre-checks for bundle installation."""
- if entry.get('timing') != 'post':
- return self.RunAction(entry)
- return True
-
- def InstallPostInstall(self, entry):
- return self.InstallAction(self, entry)
-
- def BundleUpdated(self, bundle, states):
- """Run postinstalls when bundles have been updated."""
- for postinst in bundle.findall("PostInstall"):
- self.cmd.run(postinst.get('name'))
- for action in bundle.findall("Action"):
- if action.get('timing') in ['post', 'both']:
- states[action] = self.RunAction(action)
-
- def BundleNotUpdated(self, bundle, states):
- """Run Actions when bundles have not been updated."""
- for action in bundle.findall("Action"):
- if action.get('timing') in ['post', 'both'] and \
- action.get('when') != 'modified':
- states[action] = self.RunAction(action)
diff --git a/build/lib/Bcfg2/Client/Tools/Blast.py b/build/lib/Bcfg2/Client/Tools/Blast.py
deleted file mode 100644
index 4f2891fd6..000000000
--- a/build/lib/Bcfg2/Client/Tools/Blast.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This is the bcfg2 support for blastwave packages (pkg-get)
-"""This provides bcfg2 support for blastwave"""
-__revision__ = '$Revision$'
-
-import tempfile
-import Bcfg2.Client.Tools.SYSV
-
-
-class Blast(Bcfg2.Client.Tools.SYSV.SYSV):
- """Support for Blastwave packages"""
- pkgtype = 'blast'
- pkgtool = ("/opt/csw/bin/pkg-get install %s", ("%s", ["bname"]))
- name = 'Blast'
- __execs__ = ['/opt/csw/bin/pkg-get', "/usr/bin/pkginfo"]
- __handles__ = [('Package', 'blast')]
- __ireq__ = {'Package': ['name', 'version', 'bname']}
-
- def __init__(self, logger, setup, config):
- # dont use the sysv constructor
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- noaskfile = tempfile.NamedTemporaryFile()
- self.noaskname = noaskfile.name
- try:
- noaskfile.write(Bcfg2.Client.Tools.SYSV.noask)
- except:
- pass
-
- # VerifyPackage comes from Bcfg2.Client.Tools.SYSV
- # Install comes from Bcfg2.Client.Tools.PkgTool
- # Extra comes from Bcfg2.Client.Tools.Tool
- # Remove comes from Bcfg2.Client.Tools.SYSV
- def FindExtraPackages(self):
- """Pass through to null FindExtra call."""
- return []
diff --git a/build/lib/Bcfg2/Client/Tools/Chkconfig.py b/build/lib/Bcfg2/Client/Tools/Chkconfig.py
deleted file mode 100644
index b7227ec3d..000000000
--- a/build/lib/Bcfg2/Client/Tools/Chkconfig.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# This is the bcfg2 support for chkconfig
-# $Id$
-
-"""This is chkconfig support."""
-__revision__ = '$Revision$'
-
-import Bcfg2.Client.Tools
-import Bcfg2.Client.XML
-
-
-class Chkconfig(Bcfg2.Client.Tools.SvcTool):
- """Chkconfig support for Bcfg2."""
- name = 'Chkconfig'
- __execs__ = ['/sbin/chkconfig']
- __handles__ = [('Service', 'chkconfig')]
- __req__ = {'Service': ['name', 'status']}
-
- def get_svc_command(self, service, action):
- return "/sbin/service %s %s" % (service.get('name'), action)
-
- def VerifyService(self, entry, _):
- """Verify Service status for entry."""
- try:
- cmd = "/sbin/chkconfig --list %s " % (entry.get('name'))
- raw = self.cmd.run(cmd)[1]
- patterns = ["error reading information", "unknown service"]
- srvdata = [line.split() for line in raw for pattern in patterns \
- if pattern not in line][0]
- except IndexError:
- # Ocurrs when no lines are returned (service not installed)
- entry.set('current_status', 'off')
- return False
- if len(srvdata) == 2:
- # This is an xinetd service
- if entry.get('status') == srvdata[1]:
- return True
- else:
- entry.set('current_status', srvdata[1])
- return False
-
- try:
- onlevels = [level.split(':')[0] for level in srvdata[1:] \
- if level.split(':')[1] == 'on']
- except IndexError:
- onlevels = []
-
- if entry.get('status') == 'on':
- status = (len(onlevels) > 0)
- command = 'start'
- else:
- status = (len(onlevels) == 0)
- command = 'stop'
-
- if entry.get('mode', 'default') == 'supervised':
- # turn on or off the service in supervised mode
- pstatus = self.cmd.run('/sbin/service %s status' % \
- entry.get('name'))[0]
- needs_modification = ((command == 'start' and pstatus) or \
- (command == 'stop' and not pstatus))
- if not(self.setup.get('dryrun')) and needs_modification:
- self.cmd.run('/sbin/service %s %s' % (entry.get('name'),
- command))
- pstatus = self.cmd.run('/sbin/service %s status' % \
- entry.get('name'))[0]
-
- # chkconfig/init.d service
- if entry.get('status') == 'on':
- status = status and not pstatus
-
- if not status:
- if entry.get('status') == 'on':
- entry.set('current_status', 'off')
- else:
- entry.set('current_status', 'on')
- return status
-
- def InstallService(self, entry):
- """Install Service entry."""
- rcmd = "/sbin/chkconfig %s %s"
- self.cmd.run("/sbin/chkconfig --add %s"%(entry.attrib['name']))
- self.logger.info("Installing Service %s" % (entry.get('name')))
- pass1 = True
- if entry.get('status') == 'off':
- rc = self.cmd.run(rcmd % (entry.get('name'),
- entry.get('status')) + \
- " --level 0123456")[0]
- pass1 = rc == 0
- rc = self.cmd.run(rcmd % (entry.get('name'), entry.get('status')))[0]
- return pass1 and rc == 0
-
- def FindExtra(self):
- """Locate extra chkconfig Services."""
- allsrv = [line.split()[0] for line in \
- self.cmd.run("/sbin/chkconfig --list|grep :on")[1]]
- self.logger.debug('Found active services:')
- self.logger.debug(allsrv)
- specified = [srv.get('name') for srv in self.getSupportedEntries()]
- return [Bcfg2.Client.XML.Element('Service',
- type='chkconfig',
- name=name) \
- for name in allsrv if name not in specified]
diff --git a/build/lib/Bcfg2/Client/Tools/DebInit.py b/build/lib/Bcfg2/Client/Tools/DebInit.py
deleted file mode 100644
index aee8ffd65..000000000
--- a/build/lib/Bcfg2/Client/Tools/DebInit.py
+++ /dev/null
@@ -1,117 +0,0 @@
-"""Debian Init Support for Bcfg2"""
-__revision__ = '$Revision$'
-
-import glob
-import os
-import re
-import Bcfg2.Client.Tools
-
-# Debian squeeze and beyond uses a dependecy based boot sequence
-DEBIAN_OLD_STYLE_BOOT_SEQUENCE = (
- 'etch', '4.0',
- 'lenny', '5.0', '5.0.1', '5.0.2', '5.0.3', '5.0.4', '5.0.4', '5.0.5',
- )
-
-
-class DebInit(Bcfg2.Client.Tools.SvcTool):
- """Debian Service Support for Bcfg2."""
- name = 'DebInit'
- __execs__ = ['/usr/sbin/update-rc.d', '/usr/sbin/invoke-rc.d']
- __handles__ = [('Service', 'deb')]
- __req__ = {'Service': ['name', 'status']}
- svcre = re.compile("/etc/.*/(?P<action>[SK])(?P<sequence>\d+)(?P<name>\S+)")
-
- # implement entry (Verify|Install) ops
- def VerifyService(self, entry, _):
- """Verify Service status for entry."""
- rawfiles = glob.glob("/etc/rc*.d/[SK]*%s" % (entry.get('name')))
- files = []
-
- try:
- deb_version = open('/etc/debian_version', 'r').read().split('/', 1)[0]
- except IOError:
- deb_version = 'unknown'
-
- if entry.get('sequence'):
- if (deb_version in DEBIAN_OLD_STYLE_BOOT_SEQUENCE):
- start_sequence = int(entry.get('sequence'))
- kill_sequence = 100 - start_sequence
- else:
- self.logger.warning("Your debian version boot sequence is "
- "dependency based \"sequence\" attribute "
- "will be ignored.")
- else:
- start_sequence = None
-
- for filename in rawfiles:
- match = self.svcre.match(filename)
- if not match:
- self.logger.error("Failed to match file: %s" % filename)
- continue
- if match.group('name') == entry.get('name'):
- files.append(filename)
- if entry.get('status') == 'off':
- if files:
- entry.set('current_status', 'on')
- return False
- else:
- return True
- else:
- if files:
- if start_sequence:
- for filename in files:
- match = self.svcre.match(filename)
- file_sequence = int(match.group('sequence'))
- if match.group('action') == 'S' and file_sequence != start_sequence:
- return False
- if match.group('action') == 'K' and file_sequence != kill_sequence:
- return False
- return True
- else:
- entry.set('current_status', 'off')
- return False
-
- def InstallService(self, entry):
- """Install Service for entry."""
- self.logger.info("Installing Service %s" % (entry.get('name')))
- try:
- os.stat('/etc/init.d/%s' % entry.get('name'))
- except OSError:
- self.logger.debug("Init script for service %s does not exist" % entry.get('name'))
- return False
-
- if entry.get('status') == 'off':
- self.cmd.run("/usr/sbin/invoke-rc.d %s stop" % (entry.get('name')))
- cmdrc = self.cmd.run("/usr/sbin/update-rc.d -f %s remove" % entry.get('name'))[0]
- else:
- command = "/usr/sbin/update-rc.d %s defaults" % (entry.get('name'))
- if entry.get('sequence'):
- cmdrc = self.cmd.run("/usr/sbin/update-rc.d -f %s remove" % entry.get('name'))[0]
- if cmdrc != 0:
- return False
- start_sequence = int(entry.get('sequence'))
- kill_sequence = 100 - start_sequence
- command = "%s %d %d" % (command, start_sequence, kill_sequence)
- cmdrc = self.cmd.run(command)[0]
- return cmdrc == 0
-
- def FindExtra(self):
- """Find Extra Debian Service entries."""
- specified = [entry.get('name') for entry in self.getSupportedEntries()]
- extra = []
- for name in [self.svcre.match(fname).group('name') for fname in
- glob.glob("/etc/rc[12345].d/S*") \
- if self.svcre.match(fname).group('name') not in specified]:
- if name not in extra:
- extra.append(name)
- return [Bcfg2.Client.XML.Element('Service', name=name, type='deb') for name \
- in extra]
-
- def Remove(self, _):
- """Remove extra service entries."""
- # Extra service removal is nonsensical
- # Extra services need to be reflected in the config
- return
-
- def get_svc_command(self, service, action):
- return '/usr/sbin/invoke-rc.d %s %s' % (service.get('name'), action)
diff --git a/build/lib/Bcfg2/Client/Tools/Encap.py b/build/lib/Bcfg2/Client/Tools/Encap.py
deleted file mode 100644
index 92062a750..000000000
--- a/build/lib/Bcfg2/Client/Tools/Encap.py
+++ /dev/null
@@ -1,55 +0,0 @@
-"""Bcfg2 Support for Encap Packages"""
-
-__revision__ = '$Revision$'
-
-import glob
-import re
-import Bcfg2.Client.Tools
-
-class Encap(Bcfg2.Client.Tools.PkgTool):
- """Support for Encap packages."""
- name = 'Encap'
- __execs__ = ['/usr/local/bin/epkg']
- __handles__ = [('Package', 'encap')]
- __req__ = {'Package': ['version', 'url']}
- pkgtype = 'encap'
- pkgtool = ("/usr/local/bin/epkg -l -f -q %s", ("%s", ["url"]))
- splitter = re.compile('.*/(?P<name>[\w-]+)\-(?P<version>[\w\.+-]+)')
-
-# If you define self.pkgtool and self.pkgname it will [use] the Pkgtool.Install
-# method will do the installation stuff for you
-
- def RefreshPackages(self):
- """Try to find encap packages."""
- self.installed = {}
- for pkg in glob.glob("/usr/local/encap/*"):
- match = self.splitter.match(pkg)
- if match:
- self.installed[match.group('name')] = match.group('version')
- else:
- print("Failed to split name %s" % pkg)
- self.logger.debug("Encap.py: RefreshPackages: self.installed.keys() are:")
- self.logger.debug("%s" % list(self.installed.keys()))
-
- def VerifyPackage(self, entry, _):
- """Verify Package status for entry."""
- if not entry.get('version'):
- self.logger.info("Insufficient information of Package %s; cannot Verify" % entry.get('name'))
- return False
- cmdrc = self.cmd.run("/usr/local/bin/epkg -q -S -k %s-%s >/dev/null" %
- (entry.get('name'), entry.get('version')))[0]
- if cmdrc != 0:
- self.logger.debug("Package %s version incorrect" % entry.get('name'))
- else:
- return True
- return False
-
- # Can use the FindExtraPackages method from Bcfg2.Client.Tools.PkgTool
-
- def RemovePackages(self, packages):
- """Deal with extra configuration detected."""
- names = " ".join([pkg.get('name') for pkg in packages])
- self.logger.info("Removing packages: %s" % (names))
- self.cmd.run("/usr/local/bin/epkg -l -q -r %s" % (names))
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
diff --git a/build/lib/Bcfg2/Client/Tools/FreeBSDInit.py b/build/lib/Bcfg2/Client/Tools/FreeBSDInit.py
deleted file mode 100644
index 10f0f2e93..000000000
--- a/build/lib/Bcfg2/Client/Tools/FreeBSDInit.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""FreeBSD Init Support for Bcfg2."""
-__revision__ = '$Rev$'
-
-# TODO
-# - hardcoded path to ports rc.d
-# - doesn't know about /etc/rc.d/
-
-import os
-import Bcfg2.Client.Tools
-
-
-class FreeBSDInit(Bcfg2.Client.Tools.SvcTool):
- """FreeBSD service support for Bcfg2."""
- name = 'FreeBSDInit'
- __handles__ = [('Service', 'freebsd')]
- __req__ = {'Service': ['name', 'status']}
-
- def __init__(self, logger, cfg, setup):
- Bcfg2.Client.Tools.Tool.__init__(self, logger, cfg, setup)
- if os.uname()[0] != 'FreeBSD':
- raise Bcfg2.Client.Tools.toolInstantiationError
-
- def VerifyService(self, entry, _):
- return True
-
- def get_svc_command(self, service, action):
- return "/usr/local/etc/rc.d/%s %s" % (service.get('name'), action)
diff --git a/build/lib/Bcfg2/Client/Tools/FreeBSDPackage.py b/build/lib/Bcfg2/Client/Tools/FreeBSDPackage.py
deleted file mode 100644
index 04c05adaa..000000000
--- a/build/lib/Bcfg2/Client/Tools/FreeBSDPackage.py
+++ /dev/null
@@ -1,47 +0,0 @@
-"""This is the Bcfg2 tool for the FreeBSD package system."""
-__revision__ = '$Rev$'
-
-# TODO
-# - actual package installation
-# - verification of package files
-
-import re
-import Bcfg2.Client.Tools
-
-
-class FreeBSDPackage(Bcfg2.Client.Tools.PkgTool):
- """The FreeBSD toolset implements package operations and inherits
- the rest from Toolset.Toolset."""
- name = 'FreeBSDPackage'
- __execs__ = ['/usr/sbin/pkg_add', '/usr/sbin/pkg_info']
- __handles__ = [('Package', 'freebsdpkg')]
- __req__ = {'Package': ['name', 'version']}
- pkgtool = ('/usr/sbin/pkg_add -r %s', ('%s-%s', ['name', 'version']))
- pkgtype = 'freebsdpkg'
-
- def RefreshPackages(self):
- self.installed = {}
- packages = self.cmd.run("/usr/sbin/pkg_info -a -E")[1]
- pattern = re.compile('(.*)-(\d.*)')
- for pkg in packages:
- if pattern.match(pkg):
- name = pattern.match(pkg).group(1)
- version = pattern.match(pkg).group(2)
- self.installed[name] = version
-
- def VerifyPackage(self, entry, modlist):
- if not 'version' in entry.attrib:
- self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
- return False
- if entry.attrib['name'] in self.installed:
- if self.installed[entry.attrib['name']] == entry.attrib['version']:
- # TODO: verfification
- return True
- else:
- entry.set('current_version', self.installed[entry.get('name')])
- return False
-
- self.logger.info("Package %s not installed" % (entry.get('name')))
- entry.set('current_exists', 'false')
- return False
diff --git a/build/lib/Bcfg2/Client/Tools/IPS.py b/build/lib/Bcfg2/Client/Tools/IPS.py
deleted file mode 100644
index 9afd23143..000000000
--- a/build/lib/Bcfg2/Client/Tools/IPS.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""This is the Bcfg2 support for OpenSolaris packages."""
-__revision__ = '$Revision$'
-
-import pkg.client.image as image
-import pkg.client.progress as progress
-
-import Bcfg2.Client.Tools
-
-
-class IPS(Bcfg2.Client.Tools.PkgTool):
- """The IPS driver implements OpenSolaris package operations."""
- name = 'IPS'
- pkgtype = 'ips'
- conflicts = ['SYSV']
- __handles__ = [('Package', 'ips')]
- __req__ = {'Package': ['name', 'version']}
- pkgtool = ('pkg install --no-refresh %s', ('%s', ['name']))
-
- def __init__(self, logger, setup, cfg):
- self.installed = {}
- self.pending_upgrades = set()
- self.image = image.Image()
- self.image.find_root('/', False)
- self.image.load_config()
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, cfg)
- self.cfg = cfg
-
- def RefreshPackages(self):
- self.installed = dict()
- self.image.history.operation_name = "list"
- self.image.load_catalogs(progress.NullProgressTracker())
- for (pfmri, pinfo) in self.image.inventory([], False):
- pname = pfmri.pkg_name
- pversion = pfmri.version.get_short_version()
- self.installed[pname] = pversion
- if pinfo['upgradable']:
- self.pending_upgrades.add(pname)
-
- def VerifyPackage(self, entry, modlist):
- """Verify package for entry."""
- pname = entry.get('name')
- if not 'version' in entry.attrib:
- self.logger.info("Cannot verify unversioned package %s" % (pname))
- return False
- if pname not in self.installed:
- self.logger.debug("IPS: Package %s not installed" % pname)
- return False
- if entry.get('version') == 'auto':
- if pname in self.pending_upgrades:
- return False
- elif entry.get('version') == 'any':
- pass
- else:
- if entry.get('version') != self.installed[pname]:
- self.logger.debug("IPS: Package %s: have %s want %s" \
- % (pname, self.installed[pname],
- entry.get('version')))
- return False
-
- # need to implement pkg chksum validation
- return True
diff --git a/build/lib/Bcfg2/Client/Tools/MacPorts.py b/build/lib/Bcfg2/Client/Tools/MacPorts.py
deleted file mode 100644
index 23b536451..000000000
--- a/build/lib/Bcfg2/Client/Tools/MacPorts.py
+++ /dev/null
@@ -1,60 +0,0 @@
-"""This provides Bcfg2 support for macports packages."""
-__revision__ = '$Revision$'
-
-import Bcfg2.Client.Tools
-
-
-class MacPorts(Bcfg2.Client.Tools.PkgTool):
- """macports package support."""
- name = 'MacPorts'
- __execs__ = ["/opt/local/bin/port"]
- __handles__ = [('Package', 'macport')]
- __req__ = {'Package': ['name', 'version']}
- pkgtype = 'macport'
- pkgtool = ("/opt/local/bin/port install %s")
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- self.installed = {}
- self.RefreshPackages()
-
- def RefreshPackages(self):
- """Refresh memory hashes of packages."""
- pkgcache = self.cmd.run("/opt/local/bin/port installed")[1]
- self.installed = {}
- for pkg in pkgcache:
- if pkg.startswith("The following ports are currently installed"):
- continue
- pkgname = pkg.split('@')[0].strip()
- version = pkg.split('@')[1].split(' ')[0]
- self.logger.info(" pkgname: %s\n version: %s" % (pkgname, version))
- self.installed[pkgname] = version
-
- def VerifyPackage(self, entry, modlist):
- """Verify Package status for entry."""
- if not 'version' in entry.attrib:
- self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
- return False
-
- if entry.attrib['name'] in self.installed:
- if self.installed[entry.attrib['name']] == entry.attrib['version']:
- #if not self.setup['quick'] and \
- # entry.get('verify', 'true') == 'true':
- #FIXME: We should be able to check this once
- # http://trac.macports.org/ticket/15709 is implemented
- return True
- else:
- entry.set('current_version', self.installed[entry.get('name')])
- return False
- entry.set('current_exists', 'false')
- return False
-
- def RemovePackages(self, packages):
- """Remove extra packages."""
- names = [pkg.get('name') for pkg in packages]
- self.logger.info("Removing packages: %s" % " ".join(names))
- self.cmd.run("/opt/local/bin/port uninstall %s" % \
- " ".join(names))
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
diff --git a/build/lib/Bcfg2/Client/Tools/POSIX.py b/build/lib/Bcfg2/Client/Tools/POSIX.py
deleted file mode 100644
index d2611130c..000000000
--- a/build/lib/Bcfg2/Client/Tools/POSIX.py
+++ /dev/null
@@ -1,766 +0,0 @@
-"""All POSIX Type client support for Bcfg2."""
-__revision__ = '$Revision$'
-
-from stat import S_ISVTX, S_ISGID, S_ISUID, S_IXUSR, S_IWUSR, S_IRUSR, S_IXGRP
-from stat import S_IWGRP, S_IRGRP, S_IXOTH, S_IWOTH, S_IROTH, ST_MODE, S_ISDIR
-from stat import S_IFREG, ST_UID, ST_GID, S_ISREG, S_IFDIR, S_ISLNK, ST_MTIME
-import binascii
-from datetime import datetime
-import difflib
-import errno
-import grp
-import logging
-import os
-import pwd
-import shutil
-import stat
-import time
-import Bcfg2.Client.Tools
-import Bcfg2.Options
-from Bcfg2.Client import XML
-
-log = logging.getLogger('posix')
-
-# map between dev_type attribute and stat constants
-device_map = {'block': stat.S_IFBLK,
- 'char': stat.S_IFCHR,
- 'fifo': stat.S_IFIFO}
-
-
-def calcPerms(initial, perms):
- """This compares ondisk permissions with specified ones."""
- pdisp = [{1:S_ISVTX, 2:S_ISGID, 4:S_ISUID},
- {1:S_IXUSR, 2:S_IWUSR, 4:S_IRUSR},
- {1:S_IXGRP, 2:S_IWGRP, 4:S_IRGRP},
- {1:S_IXOTH, 2:S_IWOTH, 4:S_IROTH}]
- tempperms = initial
- if len(perms) == 3:
- perms = '0%s' % (perms)
- pdigits = [int(perms[digit]) for digit in range(4)]
- for index in range(4):
- for (num, perm) in list(pdisp[index].items()):
- if pdigits[index] & num:
- tempperms |= perm
- return tempperms
-
-
-def normGid(entry):
- """
- This takes a group name or gid and
- returns the corresponding gid or False.
- """
- try:
- try:
- return int(entry.get('group'))
- except:
- return int(grp.getgrnam(entry.get('group'))[2])
- except (OSError, KeyError):
- log.error('GID normalization failed for %s' % (entry.get('name')))
- return False
-
-
-def normUid(entry):
- """
- This takes a user name or uid and
- returns the corresponding uid or False.
- """
- try:
- try:
- return int(entry.get('owner'))
- except:
- return int(pwd.getpwnam(entry.get('owner'))[2])
- except (OSError, KeyError):
- log.error('UID normalization failed for %s' % (entry.get('name')))
- return False
-
-
-class POSIX(Bcfg2.Client.Tools.Tool):
- """POSIX File support code."""
- name = 'POSIX'
- __handles__ = [('Path', 'device'),
- ('Path', 'directory'),
- ('Path', 'file'),
- ('Path', 'hardlink'),
- ('Path', 'nonexistent'),
- ('Path', 'permissions'),
- ('Path', 'symlink')]
- __req__ = {'Path': ['name', 'type']}
-
- # grab paranoid options from /etc/bcfg2.conf
- opts = {'ppath': Bcfg2.Options.PARANOID_PATH,
- 'max_copies': Bcfg2.Options.PARANOID_MAX_COPIES}
- setup = Bcfg2.Options.OptionParser(opts)
- setup.parse([])
- ppath = setup['ppath']
- max_copies = setup['max_copies']
-
- def canInstall(self, entry):
- """Check if entry is complete for installation."""
- if Bcfg2.Client.Tools.Tool.canInstall(self, entry):
- if (entry.tag,
- entry.get('type'),
- entry.text,
- entry.get('empty', 'false')) == ('Path',
- 'file',
- None,
- 'false'):
- return False
- return True
- else:
- return False
-
- def gatherCurrentData(self, entry):
- if entry.tag == 'Path' and entry.get('type') == 'file':
- try:
- ondisk = os.stat(entry.get('name'))
- except OSError:
- entry.set('current_exists', 'false')
- self.logger.debug("%s %s does not exist" %
- (entry.tag, entry.get('name')))
- return False
- try:
- entry.set('current_owner', str(ondisk[ST_UID]))
- entry.set('current_group', str(ondisk[ST_GID]))
- except (OSError, KeyError):
- pass
- entry.set('perms', str(oct(ondisk[ST_MODE])[-4:]))
- try:
- content = open(entry.get('name')).read()
- entry.set('current_bfile', binascii.b2a_base64(content))
- except IOError, error:
- self.logger.error("Failed to read %s: %s" % (error.filename,
- error.strerror))
-
- def Verifydevice(self, entry, _):
- """Verify device entry."""
- if entry.get('dev_type') == None or \
- entry.get('owner') == None or \
- entry.get('group') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- if entry.get('dev_type') in ['block', 'char']:
- # check if major/minor are properly specified
- if entry.get('major') == None or \
- entry.get('minor') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- try:
- # check for file existence
- filestat = os.stat(entry.get('name'))
- except OSError:
- entry.set('current_exists', 'false')
- self.logger.debug("%s %s does not exist" %
- (entry.tag, entry.get('name')))
- return False
-
- try:
- # attempt to verify device properties as specified in config
- dev_type = entry.get('dev_type')
- mode = calcPerms(device_map[dev_type],
- entry.get('mode', '0600'))
- owner = normUid(entry)
- group = normGid(entry)
- if dev_type in ['block', 'char']:
- # check for incompletely specified entries
- if entry.get('major') == None or \
- entry.get('minor') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- major = int(entry.get('major'))
- minor = int(entry.get('minor'))
- if major == os.major(filestat.st_rdev) and \
- minor == os.minor(filestat.st_rdev) and \
- mode == filestat.st_mode and \
- owner == filestat.st_uid and \
- group == filestat.st_gid:
- return True
- else:
- return False
- elif dev_type == 'fifo' and \
- mode == filestat.st_mode and \
- owner == filestat.st_uid and \
- group == filestat.st_gid:
- return True
- else:
- self.logger.info('Device properties for %s incorrect' % \
- entry.get('name'))
- return False
- except OSError:
- self.logger.debug("%s %s failed to verify" %
- (entry.tag, entry.get('name')))
- return False
-
- def Installdevice(self, entry):
- """Install device entries."""
- try:
- # check for existing paths and remove them
- os.lstat(entry.get('name'))
- try:
- os.unlink(entry.get('name'))
- exists = False
- except OSError:
- self.logger.info('Failed to unlink %s' % \
- entry.get('name'))
- return False
- except OSError:
- exists = False
-
- if not exists:
- try:
- dev_type = entry.get('dev_type')
- mode = calcPerms(device_map[dev_type],
- entry.get('mode', '0600'))
- if dev_type in ['block', 'char']:
- # check if major/minor are properly specified
- if entry.get('major') == None or \
- entry.get('minor') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- major = int(entry.get('major'))
- minor = int(entry.get('minor'))
- device = os.makedev(major, minor)
- os.mknod(entry.get('name'), mode, device)
- else:
- os.mknod(entry.get('name'), mode)
- os.chown(entry.get('name'), normUid(entry), normGid(entry))
- return True
- except KeyError:
- self.logger.error('Failed to install %s' % entry.get('name'))
- except OSError:
- self.logger.error('Failed to install %s' % entry.get('name'))
- return False
-
- def Verifydirectory(self, entry, modlist):
- """Verify Path type='directory' entry."""
- if entry.get('perms') == None or \
- entry.get('owner') == None or \
- entry.get('group') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- while len(entry.get('perms', '')) < 4:
- entry.set('perms', '0' + entry.get('perms', ''))
- try:
- ondisk = os.stat(entry.get('name'))
- except OSError:
- entry.set('current_exists', 'false')
- self.logger.debug("%s %s does not exist" %
- (entry.tag, entry.get('name')))
- return False
- try:
- owner = str(ondisk[ST_UID])
- group = str(ondisk[ST_GID])
- except (OSError, KeyError):
- self.logger.error('User/Group resolution failed for path %s' % \
- entry.get('name'))
- owner = 'root'
- group = '0'
- finfo = os.stat(entry.get('name'))
- perms = oct(finfo[ST_MODE])[-4:]
- if entry.get('mtime', '-1') != '-1':
- mtime = str(finfo[ST_MTIME])
- else:
- mtime = '-1'
- pTrue = ((owner == str(normUid(entry))) and
- (group == str(normGid(entry))) and
- (perms == entry.get('perms')) and
- (mtime == entry.get('mtime', '-1')))
-
- pruneTrue = True
- ex_ents = []
- if entry.get('prune', 'false') == 'true' \
- and (entry.tag == 'Path' and entry.get('type') == 'directory'):
- # check for any extra entries when prune='true' attribute is set
- try:
- entries = ['/'.join([entry.get('name'), ent]) \
- for ent in os.listdir(entry.get('name'))]
- ex_ents = [e for e in entries if e not in modlist]
- if ex_ents:
- pruneTrue = False
- self.logger.debug("Directory %s contains extra entries:" % \
- entry.get('name'))
- self.logger.debug(ex_ents)
- nqtext = entry.get('qtext', '') + '\n'
- nqtext += "Directory %s contains extra entries:" % \
- entry.get('name')
- nqtext += ":".join(ex_ents)
- entry.set('qtest', nqtext)
- [entry.append(XML.Element('Prune', path=x)) \
- for x in ex_ents]
- except OSError:
- ex_ents = []
- pruneTrue = True
-
- if not pTrue:
- if owner != str(normUid(entry)):
- entry.set('current_owner', owner)
- self.logger.debug("%s %s ownership wrong" % \
- (entry.tag, entry.get('name')))
- nqtext = entry.get('qtext', '') + '\n'
- nqtext += "%s owner wrong. is %s should be %s" % \
- (entry.get('name'), owner, entry.get('owner'))
- entry.set('qtext', nqtext)
- if group != str(normGid(entry)):
- entry.set('current_group', group)
- self.logger.debug("%s %s group wrong" % \
- (entry.tag, entry.get('name')))
- nqtext = entry.get('qtext', '') + '\n'
- nqtext += "%s group is %s should be %s" % \
- (entry.get('name'), group, entry.get('group'))
- entry.set('qtext', nqtext)
- if perms != entry.get('perms'):
- entry.set('current_perms', perms)
- self.logger.debug("%s %s permissions are %s should be %s" %
- (entry.tag,
- entry.get('name'),
- perms,
- entry.get('perms')))
- nqtext = entry.get('qtext', '') + '\n'
- nqtext += "%s %s perms are %s should be %s" % \
- (entry.tag,
- entry.get('name'),
- perms,
- entry.get('perms'))
- entry.set('qtext', nqtext)
- if mtime != entry.get('mtime', '-1'):
- entry.set('current_mtime', mtime)
- self.logger.debug("%s %s mtime is %s should be %s" \
- % (entry.tag, entry.get('name'), mtime,
- entry.get('mtime')))
- nqtext = entry.get('qtext', '') + '\n'
- nqtext += "%s mtime is %s should be %s" % \
- (entry.get('name'), mtime, entry.get('mtime'))
- entry.set('qtext', nqtext)
- if entry.get('type') != 'file':
- nnqtext = entry.get('qtext')
- nnqtext += '\nInstall %s %s: (y/N) ' % (entry.get('type'),
- entry.get('name'))
- entry.set('qtext', nnqtext)
- return pTrue and pruneTrue
-
- def Installdirectory(self, entry):
- """Install Path type='directory' entry."""
- if entry.get('perms') == None or \
- entry.get('owner') == None or \
- entry.get('group') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % \
- (entry.get('name')))
- return False
- self.logger.info("Installing directory %s" % (entry.get('name')))
- try:
- fmode = os.lstat(entry.get('name'))
- if not S_ISDIR(fmode[ST_MODE]):
- self.logger.debug("Found a non-directory entry at %s" % \
- (entry.get('name')))
- try:
- os.unlink(entry.get('name'))
- exists = False
- except OSError:
- self.logger.info("Failed to unlink %s" % \
- (entry.get('name')))
- return False
- else:
- self.logger.debug("Found a pre-existing directory at %s" % \
- (entry.get('name')))
- exists = True
- except OSError:
- # stat failed
- exists = False
-
- if not exists:
- parent = "/".join(entry.get('name').split('/')[:-1])
- if parent:
- try:
- os.stat(parent)
- except:
- self.logger.debug('Creating parent path for directory %s' % (entry.get('name')))
- for idx in range(len(parent.split('/')[:-1])):
- current = '/'+'/'.join(parent.split('/')[1:2+idx])
- try:
- sloc = os.stat(current)
- except OSError:
- try:
- os.mkdir(current)
- continue
- except OSError:
- return False
- if not S_ISDIR(sloc[ST_MODE]):
- try:
- os.unlink(current)
- os.mkdir(current)
- except OSError:
- return False
-
- try:
- os.mkdir(entry.get('name'))
- except OSError:
- self.logger.error('Failed to create directory %s' % \
- (entry.get('name')))
- return False
- if entry.get('prune', 'false') == 'true' and entry.get("qtest"):
- for pent in entry.findall('Prune'):
- pname = pent.get('path')
- ulfailed = False
- if os.path.isdir(pname):
- self.logger.info("Not removing extra directory %s, "
- "please check and remove manually" % pname)
- continue
- try:
- self.logger.debug("Unlinking file %s" % pname)
- os.unlink(pname)
- except OSError:
- self.logger.error("Failed to unlink path %s" % pname)
- ulfailed = True
- if ulfailed:
- return False
- return self.Installpermissions(entry)
-
- def Verifyfile(self, entry, _):
- """Verify Path type='file' entry."""
- # permissions check + content check
- permissionStatus = self.Verifydirectory(entry, _)
- tbin = False
- if entry.get('encoding', 'ascii') == 'base64':
- tempdata = binascii.a2b_base64(entry.text)
- tbin = True
- elif entry.get('empty', 'false') == 'true':
- tempdata = ''
- else:
- if entry.text == None:
- self.logger.error("Cannot verify incomplete Path type='%s' %s" % \
- (entry.get('type'), entry.get('name')))
- return False
- tempdata = entry.text
- if type(tempdata) == unicode:
- try:
- tempdata = tempdata.encode(self.setup['encoding'])
- except UnicodeEncodeError, e:
- self.logger.error("Error encoding file %s:\n %s" % \
- (entry.get('name'), e))
- try:
- content = open(entry.get('name')).read()
- except IOError, error:
- if error.strerror == "No such file or directory":
- # print diff for files that don't exist (yet)
- content = ''
- else:
- self.logger.error("Failed to read %s: %s" % \
- (error.filename, error.strerror))
- return False
- # comparison should be done with fingerprints or
- # md5sum so it would be faster for big binary files
- contentStatus = content == tempdata
- if not contentStatus:
- try:
- content.decode('ascii')
- isstring = True
- except:
- isstring = False
- if tbin or not isstring:
- entry.set('current_bfile', binascii.b2a_base64(content))
- nqtext = entry.get('qtext', '')
- nqtext += '\nBinary file, no printable diff'
- else:
- do_diff = True
- rawdiff = []
- start = time.time()
- longtime = False
- for x in difflib.ndiff(content.split('\n'),
- tempdata.split('\n')):
- now = time.time()
- rawdiff.append(x)
- if now - start > 5 and not longtime:
- self.logger.info("Diff of %s taking a long time" % \
- (entry.get('name')))
- longtime = True
- elif now - start > 30:
- self.logger.error("Diff of %s took too long; giving up" % \
- (entry.get('name')))
- do_diff = False
- break
- if do_diff:
- diff = '\n'.join(rawdiff)
- entry.set("current_bdiff", binascii.b2a_base64(diff))
-# entry.set("current_diff", diff)
- udiff = '\n'.join([x for x in \
- difflib.unified_diff(content.split('\n'), \
- tempdata.split('\n'))])
- try:
- eudiff = udiff.encode('ascii')
- except:
- eudiff = "Binary file: no diff printed"
-
- nqtext = entry.get('qtext', '')
-
- if nqtext:
- nqtext += '\n'
- nqtext += eudiff
- else:
- entry.set('current_bfile', binascii.b2a_base64(content))
- nqtext = entry.get('qtext', '')
- nqtext += '\nDiff took too long to compute, no printable diff'
- entry.set('qtext', nqtext)
- qtxt = entry.get('qtext', '')
- qtxt += "\nInstall %s %s: (y/N): " % (entry.tag, entry.get('name'))
- entry.set('qtext', qtxt)
- return contentStatus and permissionStatus
-
- def Installfile(self, entry):
- """Install Path type='file' entry."""
- self.logger.info("Installing file %s" % (entry.get('name')))
-
- parent = "/".join(entry.get('name').split('/')[:-1])
- if parent:
- try:
- os.stat(parent)
- except:
- self.logger.debug('Creating parent path for config file %s' % \
- (entry.get('name')))
- current = '/'
- for next in parent.split('/')[1:]:
- current += next + '/'
- try:
- sloc = os.stat(current)
- try:
- if not S_ISDIR(sloc[ST_MODE]):
- self.logger.debug('%s is not a directory; recreating' \
- % (current))
- os.unlink(current)
- os.mkdir(current)
- except OSError:
- return False
- except OSError:
- try:
- self.logger.debug("Creating non-existent path %s" % current)
- os.mkdir(current)
- except OSError:
- return False
-
- # If we get here, then the parent directory should exist
- if (entry.get("paranoid", False) == 'true') and \
- self.setup.get("paranoid", False) and not \
- (entry.get('current_exists', 'true') == 'false'):
- bkupnam = entry.get('name').replace('/', '_')
- # current list of backups for this file
- bkuplist = [f for f in os.listdir(self.ppath) if
- f.startswith(bkupnam)]
- bkuplist.sort()
- if len(bkuplist) == int(self.max_copies):
- # remove the oldest backup available
- oldest = bkuplist.pop(0)
- self.logger.info("Removing %s" % oldest)
- try:
- os.remove("%s/%s" % (self.ppath, oldest))
- except:
- self.logger.error("Failed to remove %s/%s" % \
- (self.ppath, oldest))
- return False
- try:
- # backup existing file
- shutil.copy(entry.get('name'),
- "%s/%s_%s" % (self.ppath, bkupnam, datetime.now()))
- self.logger.info("Backup of %s saved to %s" %
- (entry.get('name'), self.ppath))
- except IOError, e:
- self.logger.error("Failed to create backup file for %s" % \
- (entry.get('name')))
- self.logger.error(e)
- return False
- try:
- newfile = open("%s.new"%(entry.get('name')), 'w')
- if entry.get('encoding', 'ascii') == 'base64':
- filedata = binascii.a2b_base64(entry.text)
- elif entry.get('empty', 'false') == 'true':
- filedata = ''
- else:
- if type(entry.text) == unicode:
- filedata = entry.text.encode(self.setup['encoding'])
- else:
- filedata = entry.text
- newfile.write(filedata)
- newfile.close()
- try:
- os.chown(newfile.name, normUid(entry), normGid(entry))
- except KeyError:
- self.logger.error("Failed to chown %s to %s:%s" % \
- (entry.get('name'), entry.get('owner'),
- entry.get('group')))
- os.chown(newfile.name, 0, 0)
- os.chmod(newfile.name, calcPerms(S_IFREG, entry.get('perms')))
- os.rename(newfile.name, entry.get('name'))
- if entry.get('mtime', '-1') != '-1':
- try:
- os.utime(entry.get('name'), (int(entry.get('mtime')),
- int(entry.get('mtime'))))
- except:
- self.logger.error("File %s mtime fix failed" \
- % (entry.get('name')))
- return False
- return True
- except (OSError, IOError), err:
- if err.errno == errno.EACCES:
- self.logger.info("Failed to open %s for writing" % (entry.get('name')))
- else:
- print(err)
- return False
-
- def Verifyhardlink(self, entry, _):
- """Verify HardLink entry."""
- if entry.get('to') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % \
- (entry.get('name')))
- return False
- try:
- if os.path.samefile(entry.get('name'), entry.get('to')):
- return True
- self.logger.debug("Hardlink %s is incorrect" % \
- entry.get('name'))
- entry.set('qtext', "Link %s to %s? [y/N] " % \
- (entry.get('name'),
- entry.get('to')))
- return False
- except OSError:
- entry.set('current_exists', 'false')
- entry.set('qtext', "Link %s to %s? [y/N] " % \
- (entry.get('name'),
- entry.get('to')))
- return False
-
- def Installhardlink(self, entry):
- """Install HardLink entry."""
- if entry.get('to') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % \
- (entry.get('name')))
- return False
- self.logger.info("Installing Hardlink %s" % (entry.get('name')))
- if os.path.lexists(entry.get('name')):
- try:
- fmode = os.lstat(entry.get('name'))[ST_MODE]
- if S_ISREG(fmode) or S_ISLNK(fmode):
- self.logger.debug("Non-directory entry already exists at "
- "%s. Unlinking entry." % (entry.get('name')))
- os.unlink(entry.get('name'))
- elif S_ISDIR(fmode):
- self.logger.debug("Directory already exists at %s" % \
- (entry.get('name')))
- self.cmd.run("mv %s/ %s.bak" % \
- (entry.get('name'),
- entry.get('name')))
- else:
- os.unlink(entry.get('name'))
- except OSError:
- self.logger.info("Hardlink %s cleanup failed" % \
- (entry.get('name')))
- try:
- os.link(entry.get('to'), entry.get('name'))
- return True
- except OSError:
- return False
-
- def Verifynonexistent(self, entry, _):
- """Verify nonexistent entry."""
- # return true if path does _not_ exist
- return not os.path.lexists(entry.get('name'))
-
- def Installnonexistent(self, entry):
- '''Remove nonexistent entries'''
- try:
- os.remove(entry.get('name'))
- return True
- except OSError:
- self.logger.error('Failed to remove %s' % entry.get('name'))
- return False
-
- def Verifypermissions(self, entry, _):
- """Verify Path type='permissions' entry"""
- return self.Verifydirectory(entry, _)
-
- def Installpermissions(self, entry):
- """Install POSIX permissions"""
- if entry.get('perms') == None or \
- entry.get('owner') == None or \
- entry.get('group') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % (entry.get('name')))
- return False
- try:
- os.chown(entry.get('name'), normUid(entry), normGid(entry))
- os.chmod(entry.get('name'), calcPerms(S_IFDIR, entry.get('perms')))
- return True
- except (OSError, KeyError):
- self.logger.error('Permission fixup failed for %s' % \
- (entry.get('name')))
- return False
-
- def Verifysymlink(self, entry, _):
- """Verify Path type='symlink' entry."""
- if entry.get('to') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % \
- (entry.get('name')))
- return False
- try:
- sloc = os.readlink(entry.get('name'))
- if sloc == entry.get('to'):
- return True
- self.logger.debug("Symlink %s points to %s, should be %s" % \
- (entry.get('name'), sloc, entry.get('to')))
- entry.set('current_to', sloc)
- entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
- entry.get('to')))
- return False
- except OSError:
- entry.set('current_exists', 'false')
- entry.set('qtext', "Link %s to %s? [y/N] " % (entry.get('name'),
- entry.get('to')))
- return False
-
- def Installsymlink(self, entry):
- """Install Path type='symlink' entry."""
- if entry.get('to') == None:
- self.logger.error('Entry %s not completely specified. '
- 'Try running bcfg2-repo-validate.' % \
- (entry.get('name')))
- return False
- self.logger.info("Installing symlink %s" % (entry.get('name')))
- if os.path.lexists(entry.get('name')):
- try:
- fmode = os.lstat(entry.get('name'))[ST_MODE]
- if S_ISREG(fmode) or S_ISLNK(fmode):
- self.logger.debug("Non-directory entry already exists at "
- "%s. Unlinking entry." % \
- (entry.get('name')))
- os.unlink(entry.get('name'))
- elif S_ISDIR(fmode):
- self.logger.debug("Directory already exists at %s" %\
- (entry.get('name')))
- self.cmd.run("mv %s/ %s.bak" % \
- (entry.get('name'),
- entry.get('name')))
- else:
- os.unlink(entry.get('name'))
- except OSError:
- self.logger.info("Symlink %s cleanup failed" %\
- (entry.get('name')))
- try:
- os.symlink(entry.get('to'), entry.get('name'))
- return True
- except OSError:
- return False
-
- def InstallPath(self, entry):
- """Dispatch install to the proper method according to type"""
- ret = getattr(self, 'Install%s' % entry.get('type'))
- return ret(entry)
-
- def VerifyPath(self, entry, _):
- """Dispatch verify to the proper method according to type"""
- ret = getattr(self, 'Verify%s' % entry.get('type'))
- return ret(entry, _)
diff --git a/build/lib/Bcfg2/Client/Tools/Pacman.py b/build/lib/Bcfg2/Client/Tools/Pacman.py
deleted file mode 100644
index be3fb0c94..000000000
--- a/build/lib/Bcfg2/Client/Tools/Pacman.py
+++ /dev/null
@@ -1,82 +0,0 @@
-"""This is the bcfg2 support for pacman"""
-
-import Bcfg2.Client.Tools
-
-
-class Pacman(Bcfg2.Client.Tools.PkgTool):
- '''Archlinux package support'''
- name = 'Pacman'
- __execs__ = ["/usr/bin/pacman"]
- __handles__ = [('Package', 'pacman')]
- __req__ = {'Package': ['name', 'version']}
- pkgtype = 'pacman'
- pkgtool = ("/usr/bin/pacman --needed --noconfirm --noprogressbar")
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- self.installed = {}
- self.RefreshPackages()
-
- def RefreshPackages(self):
- '''Refresh memory hashes of packages'''
- pkgcache = self.cmd.run("/usr/bin/pacman -Q")[1]
- self.installed = {}
- for pkg in pkgcache:
- pkgname = pkg.split(' ')[0].strip()
- version = pkg.split(' ')[1].strip()
- #self.logger.info(" pkgname: %s, version: %s" % (pkgname, version))
- self.installed[pkgname] = version
-
- def VerifyPackage(self, entry, modlist):
- '''Verify Package status for entry'''
-
- self.logger.info("VerifyPackage : %s : %s" % entry.get('name'),
- entry.get('version'))
-
- if not 'version' in entry.attrib:
- self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
- return False
-
- if entry.attrib['name'] in self.installed:
- if entry.attrib['version'] == 'auto':
- return True
- elif self.installed[entry.attrib['name']] == entry.attrib['version']:
- #if not self.setup['quick'] and \
- # entry.get('verify', 'true') == 'true':
- #FIXME: need to figure out if pacman
- # allows you to verify packages
- return True
- else:
- entry.set('current_version', self.installed[entry.get('name')])
- self.logger.info("attribname: %s" % (entry.attrib['name']))
- self.logger.info("attribname: %s" % (entry.attrib['name']))
- return False
- entry.set('current_exists', 'false')
- self.logger.info("attribname: %s" % (entry.attrib['name']))
- return False
-
- def RemovePackages(self, packages):
- '''Remove extra packages'''
- names = [pkg.get('name') for pkg in packages]
- self.logger.info("Removing packages: %s" % " ".join(names))
- self.cmd.run("%s --noconfirm --noprogressbar -R %s" % \
- (self.pkgtool, " ".join(names)))
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
-
- def Install(self, packages, states):
- '''
- Pacman Install
- '''
- pkgline = ""
- for pkg in packages:
- pkgline += " " + pkg.get('name')
-
- print "packages : " + pkgline
-
- try:
- self.logger.debug("Running : %s -S %s" % (self.pkgtool, pkgline))
- self.cmd.run("%s -S %s" % (self.pkgtool, pkgline))
- except Exception, e:
- self.logger.error("Error occurred during installation: %s" % e)
diff --git a/build/lib/Bcfg2/Client/Tools/Portage.py b/build/lib/Bcfg2/Client/Tools/Portage.py
deleted file mode 100644
index 58d2aad29..000000000
--- a/build/lib/Bcfg2/Client/Tools/Portage.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""This is the Bcfg2 tool for the Gentoo Portage system."""
-__revision__ = '$Revision$'
-
-import re
-import Bcfg2.Client.Tools
-
-
-class Portage(Bcfg2.Client.Tools.PkgTool):
- """The Gentoo toolset implements package and service operations and
- inherits the rest from Toolset.Toolset."""
- name = 'Portage'
- __execs__ = ['/usr/bin/emerge', '/usr/bin/equery']
- __handles__ = [('Package', 'ebuild')]
- __req__ = {'Package': ['name', 'version']}
- pkgtype = 'ebuild'
- # requires a working PORTAGE_BINHOST in make.conf
- pkgtool = ('emerge --getbinpkgonly %s', ('=%s-%s', ['name', 'version']))
-
- def __init__(self, logger, cfg, setup):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, cfg, setup)
- self.__important__ = self.__important__ + ['/etc/make.conf']
- self.cfg = cfg
- self.installed = {}
- self.RefreshPackages()
-
- def RefreshPackages(self):
- """Refresh memory hashes of packages."""
- ret, cache = self.cmd.run("equery -q list")
- if ret == 2:
- cache = self.cmd.run("equery -q list '*'")[1]
- pattern = re.compile('(.*)-(\d.*)')
- self.installed = {}
- for pkg in cache:
- if pattern.match(pkg):
- name = pattern.match(pkg).group(1)
- version = pattern.match(pkg).group(2)
- self.installed[name] = version
- else:
- self.logger.info("Failed to parse pkg name %s" % pkg)
-
- def VerifyPackage(self, entry, modlist):
- """Verify package for entry."""
- if not 'version' in entry.attrib:
- self.logger.info("Cannot verify unversioned package %s" %
- (entry.attrib['name']))
- return False
- if entry.attrib['name'] in self.installed:
- if self.installed[entry.attrib['name']] == entry.attrib['version']:
- if not self.setup['quick'] and \
- entry.get('verify', 'true') == 'true':
- output = self.cmd.run("/usr/bin/equery check '=%s-%s' 2>&1 |grep '!!!' | awk '{print $2}'" \
- % (entry.get('name'), entry.get('version')))[1]
- if [filename for filename in output \
- if filename not in modlist]:
- return False
- return True
- else:
- entry.set('current_version', self.installed[entry.get('name')])
- return False
- entry.set('current_exists', 'false')
- return False
-
- def RemovePackages(self, packages):
- """Deal with extra configuration detected."""
- pkgnames = " ".join([pkg.get('name') for pkg in packages])
- if len(packages) > 0:
- self.logger.info('Removing packages:')
- self.logger.info(pkgnames)
- self.cmd.run("emerge --unmerge --quiet %s" % " ".join(pkgnames.split(' ')))
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
diff --git a/build/lib/Bcfg2/Client/Tools/RPMng.py b/build/lib/Bcfg2/Client/Tools/RPMng.py
deleted file mode 100644
index a1e14b3a6..000000000
--- a/build/lib/Bcfg2/Client/Tools/RPMng.py
+++ /dev/null
@@ -1,1034 +0,0 @@
-"""Bcfg2 Support for RPMS"""
-
-__revision__ = '$Revision$'
-
-import ConfigParser
-import os.path
-import rpm
-import rpmtools
-import Bcfg2.Client.Tools
-
-# Fix for python2.3
-try:
- set
-except NameError:
- from sets import Set as set
-
-class RPMng(Bcfg2.Client.Tools.PkgTool):
- """Support for RPM packages."""
- name = 'RPMng'
-
- __execs__ = ['/bin/rpm', '/var/lib/rpm']
- __handles__ = [('Package', 'rpm')]
-
- __req__ = {'Package': ['name', 'version']}
- __ireq__ = {'Package': ['url']}
-
- __new_req__ = {'Package': ['name'], 'Instance': ['version', 'release', 'arch']}
- __new_ireq__ = {'Package': ['uri'], \
- 'Instance': ['simplefile']}
-
- __gpg_req__ = {'Package': ['name', 'version']}
- __gpg_ireq__ = {'Package': ['name', 'version']}
-
- __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']}
- __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']}
-
- conflicts = ['RPM']
-
- pkgtype = 'rpm'
- pkgtool = ("rpm --oldpackage --replacepkgs --quiet -U %s", ("%s", ["url"]))
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
-
- # create a global ignore list used when ignoring particular
- # files during package verification
- self.ignores = [entry.get('name') for struct in config for entry in struct \
- if entry.get('type') == 'ignore']
- self.instance_status = {}
- self.extra_instances = []
- self.modlists = {}
- self.gpg_keyids = self.getinstalledgpg()
-
- # Process thee RPMng section from the config file.
- RPMng_CP = ConfigParser.ConfigParser()
- RPMng_CP.read(self.setup.get('setup'))
-
- # installonlypackages
- self.installOnlyPkgs = []
- if RPMng_CP.has_option(self.name, 'installonlypackages'):
- for i in RPMng_CP.get(self.name, 'installonlypackages').split(','):
- self.installOnlyPkgs.append(i.strip())
- if self.installOnlyPkgs == []:
- self.installOnlyPkgs = ['kernel', 'kernel-bigmem', 'kernel-enterprise', 'kernel-smp',
- 'kernel-modules', 'kernel-debug', 'kernel-unsupported',
- 'kernel-source', 'kernel-devel', 'kernel-default',
- 'kernel-largesmp-devel', 'kernel-largesmp', 'kernel-xen',
- 'gpg-pubkey']
- if 'gpg-pubkey' not in self.installOnlyPkgs:
- self.installOnlyPkgs.append('gpg-pubkey')
- self.logger.debug('installOnlyPackages = %s' % self.installOnlyPkgs)
-
- # erase_flags
- self.erase_flags = []
- if RPMng_CP.has_option(self.name, 'erase_flags'):
- for i in RPMng_CP.get(self.name, 'erase_flags').split(','):
- self.erase_flags.append(i.strip())
- if self.erase_flags == []:
- self.erase_flags = ['allmatches']
- self.logger.debug('erase_flags = %s' % self.erase_flags)
-
- # pkg_checks
- if RPMng_CP.has_option(self.name, 'pkg_checks'):
- self.pkg_checks = RPMng_CP.get(self.name, 'pkg_checks').lower()
- else:
- self.pkg_checks = 'true'
- self.logger.debug('pkg_checks = %s' % self.pkg_checks)
-
- # pkg_verify
- if RPMng_CP.has_option(self.name, 'pkg_verify'):
- self.pkg_verify = RPMng_CP.get(self.name, 'pkg_verify').lower()
- else:
- self.pkg_verify = 'true'
- self.logger.debug('pkg_verify = %s' % self.pkg_verify)
-
- # installed_action
- if RPMng_CP.has_option(self.name, 'installed_action'):
- self.installed_action = RPMng_CP.get(self.name, 'installed_action').lower()
- else:
- self.installed_action = 'install'
- self.logger.debug('installed_action = %s' % self.installed_action)
-
- # version_fail_action
- if RPMng_CP.has_option(self.name, 'version_fail_action'):
- self.version_fail_action = RPMng_CP.get(self.name, 'version_fail_action').lower()
- else:
- self.version_fail_action = 'upgrade'
- self.logger.debug('version_fail_action = %s' % self.version_fail_action)
-
- # verify_fail_action
- if self.name == "RPMng":
- if RPMng_CP.has_option(self.name, 'verify_fail_action'):
- self.verify_fail_action = RPMng_CP.get(self.name, 'verify_fail_action').lower()
- else:
- self.verify_fail_action = 'reinstall'
- else: # yum can't reinstall packages.
- self.verify_fail_action = 'none'
- self.logger.debug('verify_fail_action = %s' % self.verify_fail_action)
-
- # version_fail_action
- if RPMng_CP.has_option(self.name, 'verify_flags'):
- self.verify_flags = RPMng_CP.get(self.name, 'verify_flags').lower().split(',')
- else:
- self.verify_flags = []
- if '' in self.verify_flags:
- self.verify_flags.remove('')
- self.logger.debug('version_fail_action = %s' % self.version_fail_action)
- # Force a re- prelink of all packages if prelink exists.
- # Many, if not most package verifies can be caused by out of date prelinking.
- if os.path.isfile('/usr/sbin/prelink') and not self.setup['dryrun']:
- cmdrc, output = self.cmd.run('/usr/sbin/prelink -a -mR')
- if cmdrc == 0:
- self.logger.debug('Pre-emptive prelink succeeded')
- else:
- # FIXME : this is dumb - what if the output is huge?
- self.logger.error('Pre-emptive prelink failed: %s' % output)
-
-
- def RefreshPackages(self):
- """
- Creates self.installed{} which is a dict of installed packages.
-
- The dict items are lists of nevra dicts. This loosely matches the
- config from the server and what rpmtools uses to specify pacakges.
-
- e.g.
-
- self.installed['foo'] = [ {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'i386'},
- {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'x86_64'} ]
- """
- self.installed = {}
- refresh_ts = rpmtools.rpmtransactionset()
- # Don't bother with signature checks at this stage. The GPG keys might
- # not be installed.
- refresh_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES)
- for nevra in rpmtools.rpmpackagelist(refresh_ts):
- self.installed.setdefault(nevra['name'], []).append(nevra)
- if self.setup['debug']:
- print("The following package instances are installed:")
- for name, instances in list(self.installed.items()):
- self.logger.debug(" " + name)
- for inst in instances:
- self.logger.debug(" %s" %self.str_evra(inst))
- refresh_ts.closeDB()
- del refresh_ts
-
- def VerifyPackage(self, entry, modlist, pinned_version=None):
- """
- Verify Package status for entry.
- Performs the following:
- - Checks for the presence of required Package Instances.
- - Compares the evra 'version' info against self.installed{}.
- - RPM level package verify (rpm --verify).
- - Checks for the presence of unrequired package instances.
-
- Produces the following dict and list for RPMng.Install() to use:
- For installs/upgrades/fixes of required instances:
- instance_status = { <Instance Element Object>:
- { 'installed': True|False,
- 'version_fail': True|False,
- 'verify_fail': True|False,
- 'pkg': <Package Element Object>,
- 'modlist': [ <filename>, ... ],
- 'verify' : [ <rpm --verify results> ]
- }, ......
- }
-
- For deletions of unrequired instances:
- extra_instances = [ <Package Element Object>, ..... ]
-
- Constructs the text prompts for interactive mode.
- """
- instances = [inst for inst in entry if inst.tag == 'Instance' or inst.tag == 'Package']
- if instances == []:
- # We have an old style no Instance entry. Convert it to new style.
- instance = Bcfg2.Client.XML.SubElement(entry, 'Package')
- for attrib in list(entry.attrib.keys()):
- instance.attrib[attrib] = entry.attrib[attrib]
- if self.pkg_checks == 'true' and entry.get('pkg_checks', 'true') == 'true':
- if 'any' in [entry.get('version'), pinned_version]:
- version, release = 'any', 'any'
- elif entry.get('version') == 'auto':
- if pinned_version != None:
- version, release = pinned_version.split('-')
- else:
- return False
- else:
- version, release = entry.get('version').split('-')
- instance.set('version', version)
- instance.set('release', release)
- if entry.get('verify', 'true') == 'false':
- instance.set('verify', 'false')
- instances = [ instance ]
-
- self.logger.debug("Verifying package instances for %s" % entry.get('name'))
- package_fail = False
- qtext_versions = ''
-
- if entry.get('name') in self.installed:
- # There is at least one instance installed.
- if self.pkg_checks == 'true' and entry.get('pkg_checks', 'true') == 'true':
- rpmTs = rpm.TransactionSet()
- rpmHeader = None
- for h in rpmTs.dbMatch(rpm.RPMTAG_NAME, entry.get('name')):
- if rpmHeader is None or rpm.versionCompare(h, rpmHeader) > 0:
- rpmHeader = h
- rpmProvides = [ h['provides'] for h in \
- rpmTs.dbMatch(rpm.RPMTAG_NAME, entry.get('name')) ]
- rpmIntersection = set(rpmHeader['provides']) & \
- set(self.installOnlyPkgs)
- if len(rpmIntersection) > 0:
- # Packages that should only be installed or removed.
- # e.g. kernels.
- self.logger.debug(" Install only package.")
- for inst in instances:
- self.instance_status.setdefault(inst, {})['installed'] = False
- self.instance_status[inst]['version_fail'] = False
- if inst.tag == 'Package' and len(self.installed[entry.get('name')]) > 1:
- self.logger.error("WARNING: Multiple instances of package %s are installed." % \
- (entry.get('name')))
- for pkg in self.installed[entry.get('name')]:
- if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) \
- or self.inst_evra_equal(inst, pkg):
- if inst.get('version') == 'any':
- self.logger.error("got any version")
- self.logger.debug(" %s" % self.str_evra(inst))
- self.instance_status[inst]['installed'] = True
-
- if self.pkg_verify == 'true' and \
- inst.get('pkg_verify', 'true') == 'true':
- flags = inst.get('verify_flags', '').split(',') + self.verify_flags
- if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \
- entry.get('name') != 'gpg-pubkey':
- flags += ['nosignature', 'nodigest']
- self.logger.debug('WARNING: Package %s %s requires GPG Public key with ID %s'\
- % (pkg.get('name'), self.str_evra(pkg), \
- pkg.get('gpgkeyid', '')))
- self.logger.debug(' Disabling signature check.')
-
- if self.setup.get('quick', False):
- if rpmtools.prelink_exists:
- flags += ['nomd5', 'nosize']
- else:
- flags += ['nomd5']
- self.logger.debug(" verify_flags = %s" % flags)
-
- if inst.get('verify', 'true') == 'false':
- self.instance_status[inst]['verify'] = None
- else:
- vp_ts = rpmtools.rpmtransactionset()
- self.instance_status[inst]['verify'] = \
- rpmtools.rpm_verify( vp_ts, pkg, flags)
- vp_ts.closeDB()
- del vp_ts
-
- if self.instance_status[inst]['installed'] == False:
- self.logger.info(" Package %s %s not installed." % \
- (entry.get('name'), self.str_evra(inst)))
-
- qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
- entry.set('current_exists', 'false')
- else:
- # Normal Packages that can be upgraded.
- for inst in instances:
- self.instance_status.setdefault(inst, {})['installed'] = False
- self.instance_status[inst]['version_fail'] = False
-
- # Only installed packages with the same architecture are
- # relevant.
- if inst.get('arch', None) == None:
- arch_match = self.installed[entry.get('name')]
- else:
- arch_match = [pkg for pkg in self.installed[entry.get('name')] \
- if pkg.get('arch', None) == inst.get('arch', None)]
-
- if len(arch_match) > 1:
- self.logger.error("Multiple instances of package %s installed with the same achitecture." % \
- (entry.get('name')))
- elif len(arch_match) == 1:
- # There is only one installed like there should be.
- # Check that it is the right version.
- for pkg in arch_match:
- if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) or \
- self.inst_evra_equal(inst, pkg):
- self.logger.debug(" %s" % self.str_evra(inst))
- self.instance_status[inst]['installed'] = True
-
- if self.pkg_verify == 'true' and \
- inst.get('pkg_verify', 'true') == 'true':
- flags = inst.get('verify_flags', '').split(',') + self.verify_flags
- if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \
- 'nosignature' not in flags:
- flags += ['nosignature', 'nodigest']
- self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\
- % (pkg.get('name'), self.str_evra(pkg), \
- pkg.get('gpgkeyid', '')))
- self.logger.info(' Disabling signature check.')
-
- if self.setup.get('quick', False):
- if rpmtools.prelink_exists:
- flags += ['nomd5', 'nosize']
- else:
- flags += ['nomd5']
- self.logger.debug(" verify_flags = %s" % flags)
-
- if inst.get('verify', 'true') == 'false':
- self.instance_status[inst]['verify'] = None
- else:
- vp_ts = rpmtools.rpmtransactionset()
- self.instance_status[inst]['verify'] = \
- rpmtools.rpm_verify( vp_ts, pkg, flags )
- vp_ts.closeDB()
- del vp_ts
-
- else:
- # Wrong version installed.
- self.instance_status[inst]['version_fail'] = True
- self.logger.info(" Wrong version installed. Want %s, but have %s"\
- % (self.str_evra(inst), self.str_evra(pkg)))
-
- qtext_versions = qtext_versions + 'U(%s -> %s) ' % \
- (self.str_evra(pkg), self.str_evra(inst))
- elif len(arch_match) == 0:
- # This instance is not installed.
- self.instance_status[inst]['installed'] = False
- self.logger.info(" %s is not installed." % self.str_evra(inst))
- qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
-
- # Check the rpm verify results.
- for inst in instances:
- instance_fail = False
- # Dump the rpm verify results.
- #****Write something to format this nicely.*****
- if self.setup['debug'] and self.instance_status[inst].get('verify', None):
- self.logger.debug(self.instance_status[inst]['verify'])
-
- self.instance_status[inst]['verify_fail'] = False
- if self.instance_status[inst].get('verify', None):
- if len(self.instance_status[inst].get('verify')) > 1:
- self.logger.info("WARNING: Verification of more than one package instance.")
-
- for result in self.instance_status[inst]['verify']:
-
- # Check header results
- if result.get('hdr', None):
- instance_fail = True
- self.instance_status[inst]['verify_fail'] = True
-
- # Check dependency results
- if result.get('deps', None):
- instance_fail = True
- self.instance_status[inst]['verify_fail'] = True
-
- # Check the rpm verify file results against the modlist
- # and entry and per Instance Ignores.
- ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
- [ig.get('name') for ig in inst.findall('Ignore')] + \
- self.ignores
- for file_result in result.get('files', []):
- if file_result[-1] not in modlist + ignores:
- instance_fail = True
- self.instance_status[inst]['verify_fail'] = True
- else:
- self.logger.debug(" Modlist/Ignore match: %s" % \
- (file_result[-1]))
-
- if instance_fail == True:
- self.logger.debug("*** Instance %s failed RPM verification ***" % \
- self.str_evra(inst))
- qtext_versions = qtext_versions + 'R(%s) ' % self.str_evra(inst)
- self.modlists[entry] = modlist
-
- # Attach status structure for return to server for reporting.
- inst.set('verify_status', str(self.instance_status[inst]))
-
- if self.instance_status[inst]['installed'] == False or \
- self.instance_status[inst].get('version_fail', False)== True or \
- self.instance_status[inst].get('verify_fail', False) == True:
- package_fail = True
- self.instance_status[inst]['pkg'] = entry
- self.modlists[entry] = modlist
-
- # Find Installed Instances that are not in the Config.
- extra_installed = self.FindExtraInstances(entry, self.installed[entry.get('name')])
- if extra_installed != None:
- package_fail = True
- self.extra_instances.append(extra_installed)
- for inst in extra_installed.findall('Instance'):
- qtext_versions = qtext_versions + 'D(%s) ' % self.str_evra(inst)
- self.logger.debug("Found Extra Instances %s" % qtext_versions)
-
- if package_fail == True:
- self.logger.info(" Package %s failed verification." % \
- (entry.get('name')))
- qtext = 'Install/Upgrade/delete Package %s instance(s) - %s (y/N) ' % \
- (entry.get('name'), qtext_versions)
- entry.set('qtext', qtext)
-
- bcfg2_versions = ''
- for bcfg2_inst in [inst for inst in instances if inst.tag == 'Instance']:
- bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(bcfg2_inst)
- if bcfg2_versions != '':
- entry.set('version', bcfg2_versions)
- installed_versions = ''
-
- for installed_inst in self.installed[entry.get('name')]:
- installed_versions = installed_versions + '(%s) ' % \
- self.str_evra(installed_inst)
-
- entry.set('current_version', installed_versions)
- return False
-
- else:
- # There are no Instances of this package installed.
- self.logger.debug("Package %s has no instances installed" % (entry.get('name')))
- entry.set('current_exists', 'false')
- bcfg2_versions = ''
- for inst in instances:
- qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
- self.instance_status.setdefault(inst, {})['installed'] = False
- self.modlists[entry] = modlist
- self.instance_status[inst]['pkg'] = entry
- if inst.tag == 'Instance':
- bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(inst)
- if bcfg2_versions != '':
- entry.set('version', bcfg2_versions)
- entry.set('qtext', "Install Package %s Instance(s) %s? (y/N) " % \
- (entry.get('name'), qtext_versions))
-
- return False
- return True
-
- def RemovePackages(self, packages):
- """
- Remove specified entries.
-
- packages is a list of Package Entries with Instances generated
- by FindExtraPackages().
-
- """
- self.logger.debug('Running RPMng.RemovePackages()')
-
- pkgspec_list = []
- for pkg in packages:
- for inst in pkg:
- if pkg.get('name') != 'gpg-pubkey':
- pkgspec = { 'name':pkg.get('name'),
- 'epoch':inst.get('epoch', None),
- 'version':inst.get('version'),
- 'release':inst.get('release'),
- 'arch':inst.get('arch') }
- pkgspec_list.append(pkgspec)
- else:
- pkgspec = { 'name':pkg.get('name'),
- 'version':inst.get('version'),
- 'release':inst.get('release')}
- self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
- % (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.info(" This package will be deleted in a future version of the RPMng driver.")
- #pkgspec_list.append(pkg_spec)
-
- erase_results = rpmtools.rpm_erase(pkgspec_list, self.erase_flags)
- if erase_results == []:
- self.modified += packages
- for pkg in pkgspec_list:
- self.logger.info("Deleted %s %s" % (pkg.get('name'), self.str_evra(pkg)))
- else:
- self.logger.info("Bulk erase failed with errors:")
- self.logger.debug("Erase results = %s" % erase_results)
- self.logger.info("Attempting individual erase for each package.")
- pkgspec_list = []
- for pkg in packages:
- pkg_modified = False
- for inst in pkg:
- if pkg.get('name') != 'gpg-pubkey':
- pkgspec = { 'name':pkg.get('name'),
- 'epoch':inst.get('epoch', None),
- 'version':inst.get('version'),
- 'release':inst.get('release'),
- 'arch':inst.get('arch') }
- pkgspec_list.append(pkgspec)
- else:
- pkgspec = { 'name':pkg.get('name'),
- 'version':inst.get('version'),
- 'release':inst.get('release')}
- self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
- % (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.info(" This package will be deleted in a future version of the RPMng driver.")
- continue # Don't delete the gpg-pubkey packages for now.
- erase_results = rpmtools.rpm_erase([pkgspec], self.erase_flags)
- if erase_results == []:
- pkg_modified = True
- self.logger.info("Deleted %s %s" % \
- (pkgspec.get('name'), self.str_evra(pkgspec)))
- else:
- self.logger.error("unable to delete %s %s" % \
- (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.debug("Failure = %s" % erase_results)
- if pkg_modified == True:
- self.modified.append(pkg)
-
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
-
- def FixInstance(self, instance, inst_status):
- """"
- Control if a reinstall of a package happens or not based on the
- results from RPMng.VerifyPackage().
-
- Return True to reinstall, False to not reintstall.
-
- """
- fix = False
-
- if inst_status.get('installed', False) == False:
- if instance.get('installed_action', 'install') == "install" and \
- self.installed_action == "install":
- fix = True
- else:
- self.logger.debug('Installed Action for %s %s is to not install' % \
- (inst_status.get('pkg').get('name'),
- self.str_evra(instance)))
-
- elif inst_status.get('version_fail', False) == True:
- if instance.get('version_fail_action', 'upgrade') == "upgrade" and \
- self.version_fail_action == "upgrade":
- fix = True
- else:
- self.logger.debug('Version Fail Action for %s %s is to not upgrade' % \
- (inst_status.get('pkg').get('name'),
- self.str_evra(instance)))
-
- elif inst_status.get('verify_fail', False) == True and self.name == "RPMng":
- # yum can't reinstall packages so only do this for rpm.
- if instance.get('verify_fail_action', 'reinstall') == "reinstall" and \
- self.verify_fail_action == "reinstall":
- for inst in inst_status.get('verify'):
- # This needs to be a for loop rather than a straight get()
- # because the underlying routines handle multiple packages
- # and return a list of results.
- self.logger.debug('reinstall_check: %s %s:%s-%s.%s' % inst.get('nevra'))
-
- if inst.get("hdr", False):
- fix = True
-
- elif inst.get('files', False):
- # Parse rpm verify file results
- for file_result in inst.get('files', []):
- self.logger.debug('reinstall_check: file: %s' % file_result)
- if file_result[-2] != 'c':
- fix = True
- break
-
- # Shouldn't really need this, but included for clarity.
- elif inst.get("deps", False):
- fix = False
- else:
- self.logger.debug('Verify Fail Action for %s %s is to not reinstall' % \
- (inst_status.get('pkg').get('name'),
- self.str_evra(instance)))
-
- return fix
-
- def Install(self, packages, states):
- """
- Try and fix everything that RPMng.VerifyPackages() found wrong for
- each Package Entry. This can result in individual RPMs being
- installed (for the first time), reinstalled, deleted, downgraded
- or upgraded.
-
- packages is a list of Package Elements that has
- states[<Package Element>] == False
-
- The following effects occur:
- - states{} is conditionally updated for each package.
- - self.installed{} is rebuilt, possibly multiple times.
- - self.instance_statusi{} is conditionally updated for each instance
- of a package.
- - Each package will be added to self.modified[] if its states{}
- entry is set to True.
-
- """
- self.logger.info('Runing RPMng.Install()')
-
- install_only_pkgs = []
- gpg_keys = []
- upgrade_pkgs = []
-
- # Remove extra instances.
- # Can not reverify because we don't have a package entry.
- if len(self.extra_instances) > 0:
- if (self.setup.get('remove') == 'all' or \
- self.setup.get('remove') == 'packages') and\
- not self.setup.get('dryrun'):
- self.RemovePackages(self.extra_instances)
- else:
- self.logger.info("The following extra package instances will be removed by the '-r' option:")
- for pkg in self.extra_instances:
- for inst in pkg:
- self.logger.info(" %s %s" % (pkg.get('name'), self.str_evra(inst)))
-
- # Figure out which instances of the packages actually need something
- # doing to them and place in the appropriate work 'queue'.
- for pkg in packages:
- for inst in [instn for instn in pkg if instn.tag \
- in ['Instance', 'Package']]:
- if self.FixInstance(inst, self.instance_status[inst]):
- if pkg.get('name') == 'gpg-pubkey':
- gpg_keys.append(inst)
- elif pkg.get('name') in self.installOnlyPkgs:
- install_only_pkgs.append(inst)
- else:
- upgrade_pkgs.append(inst)
-
- # Fix installOnlyPackages
- if len(install_only_pkgs) > 0:
- self.logger.info("Attempting to install 'install only packages'")
- install_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile')) \
- for inst in install_only_pkgs])
- self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args)
- cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \
- install_args)
- if cmdrc == 0:
- # The rpm command succeeded. All packages installed.
- self.logger.info("Single Pass for InstallOnlyPkgs Succeded")
- self.RefreshPackages()
-
- else:
- # The rpm command failed. No packages installed.
- # Try installing instances individually.
- self.logger.error("Single Pass for InstallOnlyPackages Failed")
- installed_instances = []
- for inst in install_only_pkgs:
- install_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args)
- cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \
- install_args)
- if cmdrc == 0:
- installed_instances.append(inst)
- else:
- self.logger.debug("InstallOnlyPackage %s %s would not install." % \
- (self.instance_status[inst].get('pkg').get('name'), \
- self.str_evra(inst)))
-
- install_pkg_set = set([self.instance_status[inst].get('pkg') \
- for inst in install_only_pkgs])
- self.RefreshPackages()
-
- # Install GPG keys.
- if len(gpg_keys) > 0:
- for inst in gpg_keys:
- self.logger.info("Installing GPG keys.")
- key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- cmdrc, output = self.cmd.run("rpm --import %s" % key_arg)
- if cmdrc != 0:
- self.logger.debug("Unable to install %s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'), \
- self.str_evra(inst)))
- else:
- self.logger.debug("Installed %s-%s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'), \
- inst.get('version'), inst.get('release')))
- self.RefreshPackages()
- self.gpg_keyids = self.getinstalledgpg()
- pkg = self.instance_status[gpg_keys[0]].get('pkg')
- states[pkg] = self.VerifyPackage(pkg, [])
-
- # Fix upgradeable packages.
- if len(upgrade_pkgs) > 0:
- self.logger.info("Attempting to upgrade packages")
- upgrade_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile')) \
- for inst in upgrade_pkgs])
- cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \
- upgrade_args)
- if cmdrc == 0:
- # The rpm command succeeded. All packages upgraded.
- self.logger.info("Single Pass for Upgraded Packages Succeded")
- upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \
- for inst in upgrade_pkgs])
- self.RefreshPackages()
- else:
- # The rpm command failed. No packages upgraded.
- # Try upgrading instances individually.
- self.logger.error("Single Pass for Upgrading Packages Failed")
- upgraded_instances = []
- for inst in upgrade_pkgs:
- upgrade_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- #self.logger.debug("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \
- # upgrade_args)
- cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % upgrade_args)
- if cmdrc == 0:
- upgraded_instances.append(inst)
- else:
- self.logger.debug("Package %s %s would not upgrade." % \
- (self.instance_status[inst].get('pkg').get('name'), \
- self.str_evra(inst)))
-
- upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \
- for inst in upgrade_pkgs])
- self.RefreshPackages()
-
- if not self.setup['kevlar']:
- for pkg_entry in packages:
- self.logger.debug("Reverifying Failed Package %s" % (pkg_entry.get('name')))
- states[pkg_entry] = self.VerifyPackage(pkg_entry, \
- self.modlists.get(pkg_entry, []))
-
- for entry in [ent for ent in packages if states[ent]]:
- self.modified.append(entry)
-
- def canInstall(self, entry):
- """Test if entry has enough information to be installed."""
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Cannot install entry %s:%s with bind failure" % \
- (entry.tag, entry.get('name')))
- return False
-
-
- instances = entry.findall('Instance')
-
- # If the entry wasn't verifiable, then we really don't want to try and fix something
- # that we don't know is broken.
- if not self.canVerify(entry):
- self.logger.debug("WARNING: Package %s was not verifiable, not passing to Install()" \
- % entry.get('name'))
- return False
-
- if not instances:
- # Old non Instance format, unmodified.
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- return False
- else:
- if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- return False
- else:
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_gpg_ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if [attr for attr in self.__new_gpg_ireq__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install"\
- % (inst.tag, entry.get('name')))
- return False
- else:
- # New format with Instances.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- self.logger.error(" Required attributes that may not be present are %s" \
- % (self.__new_ireq__[entry.tag]))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if inst.tag == 'Instance':
- if [attr for attr in self.__new_ireq__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for %s of package %s; cannot install" \
- % (inst.tag, entry.get('name')))
- self.logger.error(" Required attributes that may not be present are %s" \
- % (self.__new_ireq__[inst.tag]))
- return False
- return True
-
- def canVerify(self, entry):
- """
- Test if entry has enough information to be verified.
-
- Three types of entries are checked.
- Old style Package
- New style Package with Instances
- pgp-pubkey packages
-
- Also the old style entries get modified after the first
- VerifyPackage() run, so there needs to be a second test.
-
- """
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Entry %s:%s reports bind failure: %s" % \
- (entry.tag, entry.get('name'), entry.get('failure')))
- return False
-
- # We don't want to do any checks so we don't care what the entry has in it.
- if self.pkg_checks == 'false' or \
- entry.get('pkg_checks', 'true').lower() == 'false':
- return True
-
- instances = entry.findall('Instance')
-
- if not instances:
- # Old non Instance format, unmodified.
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__gpg_req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- elif entry.tag == 'Path' and entry.get('type') == 'ignore':
- # ignored Paths are only relevant during failed package
- # verification
- pass
- else:
- if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- else:
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_gpg_req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if [attr for attr in self.__new_gpg_req__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (inst.tag, inst.get('name')))
- return False
- else:
- # New format with Instances, or old style modified.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if inst.tag == 'Instance':
- if [attr for attr in self.__new_req__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (inst.tag, inst.get('name')))
- return False
- return True
-
- def FindExtraPackages(self):
- """Find extra packages."""
- packages = [entry.get('name') for entry in self.getSupportedEntries()]
- extras = []
-
- for (name, instances) in list(self.installed.items()):
- if name not in packages:
- extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype)
- for installed_inst in instances:
- if self.setup['extra']:
- self.logger.info("Extra Package %s %s." % \
- (name, self.str_evra(installed_inst)))
- tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
- version = installed_inst.get('version'), \
- release = installed_inst.get('release'))
- if installed_inst.get('epoch', None) != None:
- tmp_entry.set('epoch', str(installed_inst.get('epoch')))
- if installed_inst.get('arch', None) != None:
- tmp_entry.set('arch', installed_inst.get('arch'))
- extras.append(extra_entry)
- return extras
-
-
- def FindExtraInstances(self, pkg_entry, installed_entry):
- """
- Check for installed instances that are not in the config.
- Return a Package Entry with Instances to remove, or None if there
- are no Instances to remove.
-
- """
- name = pkg_entry.get('name')
- extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype)
- instances = [inst for inst in pkg_entry if inst.tag == 'Instance' or inst.tag == 'Package']
- if name in self.installOnlyPkgs:
- for installed_inst in installed_entry:
- not_found = True
- for inst in instances:
- if self.pkg_vr_equal(inst, installed_inst) or \
- self.inst_evra_equal(inst, installed_inst):
- not_found = False
- break
- if not_found == True:
- # Extra package.
- self.logger.info("Extra InstallOnlyPackage %s %s." % \
- (name, self.str_evra(installed_inst)))
- tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
- version = installed_inst.get('version'), \
- release = installed_inst.get('release'))
- if installed_inst.get('epoch', None) != None:
- tmp_entry.set('epoch', str(installed_inst.get('epoch')))
- if installed_inst.get('arch', None) != None:
- tmp_entry.set('arch', installed_inst.get('arch'))
- else:
- # Normal package, only check arch.
- for installed_inst in installed_entry:
- not_found = True
- for inst in instances:
- if installed_inst.get('arch', None) == inst.get('arch', None) or\
- inst.tag == 'Package':
- not_found = False
- break
- if not_found:
- self.logger.info("Extra Normal Package Instance %s %s" % \
- (name, self.str_evra(installed_inst)))
- tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
- version = installed_inst.get('version'), \
- release = installed_inst.get('release'))
- if installed_inst.get('epoch', None) != None:
- tmp_entry.set('epoch', str(installed_inst.get('epoch')))
- if installed_inst.get('arch', None) != None:
- tmp_entry.set('arch', installed_inst.get('arch'))
-
- if len(extra_entry) == 0:
- extra_entry = None
-
- return extra_entry
-
- def str_evra(self, instance):
- """Convert evra dict entries to a string."""
- if instance.get('epoch', '*') in ['*', None]:
- return '%s-%s.%s' % (instance.get('version', '*'),
- instance.get('release', '*'),
- instance.get('arch', '*'))
- else:
- return '%s:%s-%s.%s' % (instance.get('epoch', '*'),
- instance.get('version', '*'),
- instance.get('release', '*'),
- instance.get('arch', '*'))
-
- def pkg_vr_equal(self, config_entry, installed_entry):
- '''
- Compare old style entry to installed entry. Which means ignore
- the epoch and arch.
- '''
- if (config_entry.tag == 'Package' and \
- config_entry.get('version') == installed_entry.get('version') and \
- config_entry.get('release') == installed_entry.get('release')):
- return True
- else:
- return False
-
- def inst_evra_equal(self, config_entry, installed_entry):
- """Compare new style instance to installed entry."""
-
- if config_entry.get('epoch', None) != None:
- epoch = int(config_entry.get('epoch'))
- else:
- epoch = None
-
- if (config_entry.tag == 'Instance' and \
- (epoch == installed_entry.get('epoch', 0) or \
- (epoch == 0 and installed_entry.get('epoch', 0) == None) or \
- (epoch == None and installed_entry.get('epoch', 0) == 0)) and \
- config_entry.get('version') == installed_entry.get('version') and \
- config_entry.get('release') == installed_entry.get('release') and \
- config_entry.get('arch', None) == installed_entry.get('arch', None)):
- return True
- else:
- return False
-
- def getinstalledgpg(self):
- """
- Create a list of installed GPG key IDs.
-
- The pgp-pubkey package version is the least significant 4 bytes
- (big-endian) of the key ID which is good enough for our purposes.
-
- """
- init_ts = rpmtools.rpmtransactionset()
- init_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES)
- gpg_hdrs = rpmtools.getheadersbykeyword(init_ts, **{'name':'gpg-pubkey'})
- keyids = [ header[rpm.RPMTAG_VERSION] for header in gpg_hdrs]
- keyids.append('None')
- init_ts.closeDB()
- del init_ts
- return keyids
-
- def VerifyPath(self, entry, _):
- """
- We don't do anything here since all
- Paths are processed in __init__
- """
- return True
diff --git a/build/lib/Bcfg2/Client/Tools/RcUpdate.py b/build/lib/Bcfg2/Client/Tools/RcUpdate.py
deleted file mode 100644
index 159172b78..000000000
--- a/build/lib/Bcfg2/Client/Tools/RcUpdate.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""This is rc-update support."""
-__revision__ = '$Revision$'
-
-import os
-import Bcfg2.Client.Tools
-import Bcfg2.Client.XML
-
-
-class RcUpdate(Bcfg2.Client.Tools.SvcTool):
- """RcUpdate support for Bcfg2."""
- name = 'RcUpdate'
- __execs__ = ['/sbin/rc-update', '/bin/rc-status']
- __handles__ = [('Service', 'rc-update')]
- __req__ = {'Service': ['name', 'status']}
-
- def VerifyService(self, entry, _):
- """
- Verify Service status for entry.
- Assumes we run in the "default" runlevel.
-
- """
- # check if service is enabled
- cmd = '/sbin/rc-update show default | grep %s'
- rc = self.cmd.run(cmd % entry.get('name'))[0]
- is_enabled = (rc == 0)
-
- if entry.get('mode', 'default') == 'supervised':
- # check if init script exists
- try:
- os.stat('/etc/init.d/%s' % entry.get('name'))
- except OSError:
- self.logger.debug('Init script for service %s does not exist' %
- entry.get('name'))
- return False
-
- # check if service is enabled
- cmd = '/etc/init.d/%s status | grep started'
- rc = self.cmd.run(cmd % entry.attrib['name'])[0]
- is_running = (rc == 0)
- else:
- # we don't care
- is_running = is_enabled
-
- if entry.get('status') == 'on' and not (is_enabled and is_running):
- entry.set('current_status', 'off')
- return False
-
- elif entry.get('status') == 'off' and (is_enabled or is_running):
- entry.set('current_status', 'on')
- return False
-
- return True
-
- def InstallService(self, entry):
- """
- Install Service entry
- In supervised mode we also take care it's (not) running.
-
- """
- self.logger.info('Installing Service %s' % entry.get('name'))
- if entry.get('status') == 'on':
- # make sure it's running if in supervised mode
- if entry.get('mode', 'default') == 'supervised' \
- and entry.get('current_status') == 'off':
- self.start_service(entry)
- # make sure it's enabled
- cmd = '/sbin/rc-update add %s default'
- rc = self.cmd.run(cmd % entry.get('name'))[0]
- return (rc == 0)
-
- elif entry.get('status') == 'off':
- # make sure it's not running if in supervised mode
- if entry.get('mode', 'default') == 'supervised' \
- and entry.get('current_status') == 'on':
- self.stop_service(entry)
- # make sure it's disabled
- cmd = '/sbin/rc-update del %s default'
- rc = self.cmd.run(cmd % entry.get('name'))[0]
- return (rc == 0)
-
- return False
-
- def FindExtra(self):
- """Locate extra rc-update services."""
- cmd = '/bin/rc-status -s | grep started'
- allsrv = [line.split()[0] for line in self.cmd.run(cmd)[1]]
- self.logger.debug('Found active services:')
- self.logger.debug(allsrv)
- specified = [srv.get('name') for srv in self.getSupportedEntries()]
- return [Bcfg2.Client.XML.Element('Service',
- type='rc-update',
- name=name) \
- for name in allsrv if name not in specified]
diff --git a/build/lib/Bcfg2/Client/Tools/SMF.py b/build/lib/Bcfg2/Client/Tools/SMF.py
deleted file mode 100644
index f0bc6bd05..000000000
--- a/build/lib/Bcfg2/Client/Tools/SMF.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""SMF support for Bcfg2"""
-__revision__ = '$Revision$'
-
-import glob
-import os
-
-import Bcfg2.Client.Tools
-
-
-class SMF(Bcfg2.Client.Tools.SvcTool):
- """Support for Solaris SMF Services."""
- __handles__ = [('Service', 'smf')]
- __execs__ = ['/usr/sbin/svcadm', '/usr/bin/svcs']
- name = 'SMF'
- __req__ = {'Service': ['name', 'status']}
- __ireq__ = {'Service': ['name', 'status', 'FMRI']}
-
- def get_svc_command(self, service, action):
- if service.get('type') == 'lrc':
- return Bcfg2.Client.Tools.SvcTool.get_svc_command(self,
- service, action)
- if action == 'stop':
- return "/usr/sbin/svcadm disable %s" % (service.get('FMRI'))
- elif action == 'restart':
- return "/usr/sbin/svcadm restart %s" % (service.get('FMRI'))
- elif action == 'start':
- return "/usr/sbin/svcadm enable %s" % (service.get('FMRI'))
-
- def GetFMRI(self, entry):
- """Perform FMRI resolution for service."""
- if not 'FMRI' in entry.attrib:
- name = self.cmd.run("/usr/bin/svcs -H -o FMRI %s 2>/dev/null" % \
- entry.get('name'))[1]
- if name:
- entry.set('FMRI', name[0])
- return True
- else:
- self.logger.info('Failed to locate FMRI for service %s' % \
- entry.get('name'))
- return False
- return True
-
- def VerifyService(self, entry, _):
- """Verify SMF Service entry."""
- if not self.GetFMRI(entry):
- self.logger.error("smf service %s doesn't have FMRI set" % \
- entry.get('name'))
- return False
- if entry.get('FMRI').startswith('lrc'):
- filename = entry.get('FMRI').split('/')[-1]
- # this is a legacy service
- gname = "/etc/rc*.d/%s" % filename
- files = glob.glob(gname.replace('_', '.'))
- if files:
- self.logger.debug("Matched %s with %s" % \
- (entry.get("FMRI"), ":".join(files)))
- return entry.get('status') == 'on'
- else:
- self.logger.debug("No service matching %s" % \
- (entry.get("FMRI")))
- return entry.get('status') == 'off'
- try:
- srvdata = self.cmd.run("/usr/bin/svcs -H -o STA %s" % \
- entry.get('FMRI'))[1][0].split()
- except IndexError:
- # Occurs when no lines are returned (service not installed)
- return False
-
- if entry.get('status') == 'on':
- return srvdata[0] == 'ON'
- else:
- return srvdata[0] in ['OFF', 'UN', 'MNT', 'DIS', 'DGD']
-
- def InstallService(self, entry):
- """Install SMF Service entry."""
- self.logger.info("Installing Service %s" % (entry.get('name')))
- if entry.get('status') == 'off':
- if entry.get("FMRI").startswith('lrc'):
- try:
- loc = entry.get("FMRI")[4:].replace('_', '.')
- self.logger.debug("Renaming file %s to %s" % \
- (loc, loc.replace('/S', '/DISABLED.S')))
- os.rename(loc, loc.replace('/S', '/DISABLED.S'))
- return True
- except OSError:
- self.logger.error("Failed to rename init script %s" % \
- (loc))
- return False
- else:
- cmdrc = self.cmd.run("/usr/sbin/svcadm disable %s" % \
- (entry.get('FMRI')))[0]
- else:
- if entry.get('FMRI').startswith('lrc'):
- loc = entry.get("FMRI")[4:].replace('_', '.')
- try:
- os.stat(loc.replace('/S', '/Disabled.'))
- self.logger.debug("Renaming file %s to %s" % \
- (loc.replace('/S', '/DISABLED.S'), loc))
- os.rename(loc.replace('/S', '/DISABLED.S'), loc)
- cmdrc = 0
- except OSError:
- self.logger.debug("Failed to rename %s to %s" % \
- (loc.replace('/S', '/DISABLED.S'), loc))
- cmdrc = 1
- else:
- srvdata = self.cmd.run("/usr/bin/svcs -H -o STA %s" %
- entry.get('FMRI'))[1] [0].split()
- if srvdata[0] == 'MNT':
- cmdarg = 'clear'
- else:
- cmdarg = 'enable'
- cmdrc = self.cmd.run("/usr/sbin/svcadm %s -r %s" % \
- (cmdarg, entry.get('FMRI')))[0]
- return cmdrc == 0
-
- def Remove(self, svcs):
- """Remove Extra SMF entries."""
- # Extra service entry removal is nonsensical
- # Extra service entries should be reflected in config, even if disabled
- pass
-
- def FindExtra(self):
- """Find Extra SMF Services."""
- allsrv = [name for name, version in \
- [srvc.split() for srvc in
- self.cmd.run("/usr/bin/svcs -a -H -o FMRI,STATE")[1]]
- if version != 'disabled']
-
- [allsrv.remove(svc.get('FMRI')) for svc in self.getSupportedEntries() \
- if svc.get("FMRI") in allsrv]
- return [Bcfg2.Client.XML.Element("Service", type='smf', name=name) \
- for name in allsrv]
diff --git a/build/lib/Bcfg2/Client/Tools/SYSV.py b/build/lib/Bcfg2/Client/Tools/SYSV.py
deleted file mode 100644
index b5e1f1c59..000000000
--- a/build/lib/Bcfg2/Client/Tools/SYSV.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# This is the bcfg2 support for solaris sysv packages
-"""This provides bcfg2 support for Solaris SYSV packages."""
-__revision__ = '$Revision$'
-
-import tempfile
-
-import Bcfg2.Client.Tools
-import Bcfg2.Client.XML
-
-
-noask = '''
-mail=
-instance=overwrite
-partial=nocheck
-runlevel=nocheck
-idepend=nocheck
-rdepend=nocheck
-space=ask
-setuid=nocheck
-conflict=nocheck
-action=nocheck
-basedir=default
-'''
-
-
-class SYSV(Bcfg2.Client.Tools.PkgTool):
- """Solaris SYSV package support."""
- __execs__ = ["/usr/sbin/pkgadd", "/usr/bin/pkginfo"]
- __handles__ = [('Package', 'sysv')]
- __req__ = {'Package': ['name', 'version']}
- __ireq__ = {'Package': ['name', 'url', 'version']}
- name = 'SYSV'
- pkgtype = 'sysv'
- pkgtool = ("/usr/sbin/pkgadd %s -n -d %%s", (('%s %s', ['url', 'name'])))
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- # noaskfile needs to live beyond __init__ otherwise file is removed
- self.noaskfile = tempfile.NamedTemporaryFile()
- self.noaskname = self.noaskfile.name
- try:
- self.noaskfile.write(noask)
- # flush admin file contents to disk
- self.noaskfile.flush()
- self.pkgtool = (self.pkgtool[0] % ("-a %s" % (self.noaskname)), \
- self.pkgtool[1])
- except:
- self.pkgtool = (self.pkgtool[0] % (""), self.pkgtool[1])
-
- def RefreshPackages(self):
- """Refresh memory hashes of packages."""
- self.installed = {}
- # Build list of packages
- lines = self.cmd.run("/usr/bin/pkginfo -x")[1]
- while lines:
- # Splitting on whitespace means that packages with spaces in
- # their version numbers don't work right. Found this with
- # IBM TSM software with package versions like
- # "Version 6 Release 1 Level 0.0"
- # Should probably be done with a regex but this works.
- version = lines.pop().split(') ')[1]
- pkg = lines.pop().split()[0]
- self.installed[pkg] = version
-
- def VerifyPackage(self, entry, modlist):
- """Verify Package status for entry."""
- if not entry.get('version'):
- self.logger.info("Insufficient information of Package %s; cannot Verify" % entry.get('name'))
- return False
-
- desiredVersion = entry.get('version')
- if desiredVersion == 'any':
- desiredVersion = self.installed.get(entry.get('name'), desiredVersion)
-
- cmdrc = self.cmd.run("/usr/bin/pkginfo -q -v \"%s\" %s" % \
- (desiredVersion, entry.get('name')))[0]
-
- if cmdrc != 0:
- if entry.get('name') in self.installed:
- self.logger.debug("Package %s version incorrect: have %s want %s" \
- % (entry.get('name'), self.installed[entry.get('name')],
- desiredVersion))
- else:
- self.logger.debug("Package %s not installed" % (entry.get("name")))
- else:
- if self.setup['quick'] or entry.attrib.get('verify', 'true') == 'false':
- return True
- (vstat, odata) = self.cmd.run("/usr/sbin/pkgchk -n %s" % (entry.get('name')))
- if vstat == 0:
- return True
- else:
- output = [line for line in odata if line[:5] == 'ERROR']
- if len([name for name in output if name.split()[-1] not in modlist]):
- self.logger.debug("Package %s content verification failed" % \
- (entry.get('name')))
- else:
- return True
- return False
-
- def RemovePackages(self, packages):
- """Remove specified Sysv packages."""
- names = [pkg.get('name') for pkg in packages]
- self.logger.info("Removing packages: %s" % (names))
- self.cmd.run("/usr/sbin/pkgrm -a %s -n %s" % \
- (self.noaskname, names))
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
diff --git a/build/lib/Bcfg2/Client/Tools/Upstart.py b/build/lib/Bcfg2/Client/Tools/Upstart.py
deleted file mode 100644
index 113f28d23..000000000
--- a/build/lib/Bcfg2/Client/Tools/Upstart.py
+++ /dev/null
@@ -1,78 +0,0 @@
-"""Upstart support for Bcfg2."""
-__revision__ = '$Revision$'
-
-import glob
-import re
-
-import Bcfg2.Client.Tools
-import Bcfg2.Client.XML
-
-
-class Upstart(Bcfg2.Client.Tools.SvcTool):
- """Upstart service support for Bcfg2."""
- name = 'Upstart'
- __execs__ = ['/lib/init/upstart-job',
- '/sbin/initctl',
- '/usr/sbin/service']
- __handles__ = [('Service', 'upstart')]
- __req__ = {'Service': ['name', 'status']}
- svcre = re.compile("/etc/init/(?P<name>.*).conf")
-
- def get_svc_command(self, service, action):
- return "/usr/sbin/service %s %s" % (service.get('name'), action)
-
- def VerifyService(self, entry, _):
- """Verify Service status for entry
-
- Verifying whether or not the service is enabled can be done
- at the file level with upstart using the contents of
- /etc/init/servicename.conf. All we need to do is make sure
- the service is running when it should be.
- """
- try:
- output = self.cmd.run('/usr/sbin/service %s status' % \
- entry.get('name'))[1][0]
- except IndexError:
- self.logger.error("Service %s not an Upstart service" % \
- entry.get('name'))
- return False
- try:
- running = output.split(' ')[1].split('/')[1].startswith('running')
- if running:
- entry.set('current_status', 'on')
- if entry.get('status') == 'off':
- status = False
- else:
- status = True
- else:
- entry.set('current_status', 'off')
- if entry.get('status') == 'on':
- status = False
- else:
- status = True
- except IndexError:
- # service does not exist
- entry.set('current_status', 'off')
- status = False
-
- return status
-
- def InstallService(self, entry):
- """Install Service for entry."""
- if entry.get('status') == 'on':
- pstatus = self.cmd.run(self.get_svc_command(entry, 'start'))[0]
- elif entry.get('status') == 'off':
- pstatus = self.cmd.run(self.get_svc_command(entry, 'stop'))[0]
- # pstatus is true if command failed
- return not pstatus
-
- def FindExtra(self):
- """Locate extra Upstart services."""
- specified = [entry.get('name') for entry in self.getSupportedEntries()]
- extra = []
- for name in [self.svcre.match(fname).group('name') for fname in
- glob.glob("/etc/init/*.conf") \
- if self.svcre.match(fname).group('name') not in specified]:
- extra.append(name)
- return [Bcfg2.Client.XML.Element('Service', type='upstart', name=name) \
- for name in extra]
diff --git a/build/lib/Bcfg2/Client/Tools/YUMng.py b/build/lib/Bcfg2/Client/Tools/YUMng.py
deleted file mode 100644
index f0d906717..000000000
--- a/build/lib/Bcfg2/Client/Tools/YUMng.py
+++ /dev/null
@@ -1,848 +0,0 @@
-"""This provides bcfg2 support for yum."""
-__revision__ = '$Revision$'
-
-import ConfigParser
-import copy
-import os.path
-import yum
-import yum.packages
-import yum.rpmtrans
-import yum.callbacks
-import yum.Errors
-import yum.misc
-import rpmUtils.arch
-import Bcfg2.Client.XML
-import Bcfg2.Client.Tools
-
-# Fix for python2.3
-try:
- set
-except NameError:
- from sets import Set as set
-
-
-def build_yname(pkgname, inst):
- """Build yum appropriate package name."""
- d = {}
- if isinstance(inst, yum.packages.PackageObject):
- for i in ['name', 'epoch', 'version', 'release', 'arch']:
- d[i] = getattr(inst, i)
- else:
- d['name'] = pkgname
- if inst.get('version') != 'any':
- d['version'] = inst.get('version')
- if inst.get('epoch', False):
- d['epoch'] = inst.get('epoch')
- if inst.get('release', False) and inst.get('release') != 'any':
- d['release'] = inst.get('release')
- if inst.get('arch', False) and inst.get('arch') != 'any':
- d['arch'] = inst.get('arch')
- return d
-
-
-def short_yname(nevra):
- d = nevra.copy()
- if 'version' in d:
- d['ver'] = d['version']
- del d['version']
- if 'release' in d:
- d['rel'] = d['release']
- del d['release']
- return d
-
-
-def nevraString(p):
- if isinstance(p, yum.packages.PackageObject):
- return str(p)
- else:
- ret = ""
- for i, j in [('epoch', '%s:'), ('name', '%s'), ('version', '-%s'),
- ('release', '-%s'), ('arch', '.%s')]:
- if i in p:
- ret = "%s%s" % (ret, j % p[i])
- return ret
-
-
-class Parser(ConfigParser.ConfigParser):
-
- def get(self, section, option, default):
- """
- Override ConfigParser.get: If the request option is not in the
- config file then return the value of default rather than raise
- an exception. We still raise exceptions on missing sections.
- """
- try:
- return ConfigParser.ConfigParser.get(self, section, option)
- except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
- return default
-
-
-class RPMDisplay(yum.rpmtrans.RPMBaseCallback):
- """We subclass the default RPM transaction callback so that we
- can control Yum's verbosity and pipe it through the right logger."""
-
- def __init__(self, logger):
- yum.rpmtrans.RPMBaseCallback.__init__(self)
- self.logger = logger
- self.state = None
- self.package = None
-
- def event(self, package, action, te_current, te_total,
- ts_current, ts_total):
- """
- @param package: A yum package object or simple string of a package name
- @param action: A yum.constant transaction set state or in the obscure
- rpm repackage case it could be the string 'repackaging'
- @param te_current: Current number of bytes processed in the transaction
- element being processed
- @param te_total: Total number of bytes in the transaction element being
- processed
- @param ts_current: number of processes completed in whole transaction
- @param ts_total: total number of processes in the transaction.
- """
-
- if self.package != str(package) or action != self.state:
- msg = "%s: %s" % (self.action[action], package)
- self.logger.info(msg)
- self.state = action
- self.package = str(package)
-
- def scriptout(self, package, msgs):
- """Handle output from package scripts."""
-
- if msgs:
- msg = "%s: %s" % (package, msgs)
- self.logger.debug(msg)
-
- def errorlog(self, msg):
- """Deal with error reporting."""
- self.logger.error(msg)
-
-
-class YumDisplay(yum.callbacks.ProcessTransBaseCallback):
- """Class to handle display of what step we are in the Yum transaction
- such as downloading packages, etc."""
-
- def __init__(self, logger):
- self.logger = logger
-
-
-class YUMng(Bcfg2.Client.Tools.PkgTool):
- """Support for Yum packages."""
- pkgtype = 'yum'
-
- name = 'YUMng'
- __execs__ = []
- __handles__ = [('Package', 'yum'),
- ('Package', 'rpm'),
- ('Path', 'ignore')]
-
- __req__ = {'Package': ['name'],
- 'Path': ['type']}
- __ireq__ = {'Package': ['name']}
-
- conflicts = ['RPMng']
-
- def __init__(self, logger, setup, config):
- self.yb = yum.YumBase()
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- self.ignores = [entry.get('name') for struct in config \
- for entry in struct \
- if entry.tag == 'Path' and \
- entry.get('type') == 'ignore']
- self.instance_status = {}
- self.extra_instances = []
- self.modlists = {}
- self._loadConfig()
- self.__important__ = self.__important__ + \
- [entry.get('name') for struct in config \
- for entry in struct \
- if entry.tag == 'Path' and \
- (entry.get('name').startswith('/etc/yum.d') \
- or entry.get('name').startswith('/etc/yum.repos.d')) \
- or entry.get('name') == '/etc/yum.conf']
- self.yum_avail = dict()
- self.yum_installed = dict()
- try:
- self.yb.doConfigSetup()
- self.yb.doTsSetup()
- self.yb.doRpmDBSetup()
- except yum.Errors.RepoError, e:
- self.logger.error("YUMng Repository error: %s" % e)
- raise Bcfg2.Client.Tools.toolInstantiationError
- except yum.Errors.YumBaseError, e:
- self.logger.error("YUMng error: %s" % e)
- raise Bcfg2.Client.Tools.toolInstantiationError
-
- yup = self.yb.doPackageLists(pkgnarrow='updates')
- if hasattr(self.yb.rpmdb, 'pkglist'):
- yinst = self.yb.rpmdb.pkglist
- else:
- yinst = self.yb.rpmdb.getPkgList()
- for dest, source in [(self.yum_avail, yup.updates),
- (self.yum_installed, yinst)]:
- for pkg in source:
- if dest is self.yum_avail:
- pname = pkg.name
- data = [(pkg.arch, (pkg.epoch, pkg.version, pkg.release))]
- else:
- pname = pkg[0]
- data = [(pkg[1], (pkg[2], pkg[3], pkg[4]))]
- if pname in dest:
- dest[pname].update(data)
- else:
- dest[pname] = dict(data)
-
- def _loadConfig(self):
- # Process the YUMng section from the config file.
- CP = Parser()
- CP.read(self.setup.get('setup'))
- truth = ['true', 'yes', '1']
-
- # These are all boolean flags, either we do stuff or we don't
- self.pkg_checks = CP.get(self.name, "pkg_checks", "true").lower() \
- in truth
- self.pkg_verify = CP.get(self.name, "pkg_verify", "true").lower() \
- in truth
- self.doInstall = CP.get(self.name, "installed_action",
- "install").lower() == "install"
- self.doUpgrade = CP.get(self.name,
- "version_fail_action", "upgrade").lower() == "upgrade"
- self.doReinst = CP.get(self.name, "verify_fail_action",
- "reinstall").lower() == "reinstall"
- self.verifyFlags = CP.get(self.name, "verify_flags",
- "").lower().replace(' ', ',')
-
- self.installOnlyPkgs = self.yb.conf.installonlypkgs
- if 'gpg-pubkey' not in self.installOnlyPkgs:
- self.installOnlyPkgs.append('gpg-pubkey')
-
- self.logger.debug("YUMng: Install missing: %s" \
- % self.doInstall)
- self.logger.debug("YUMng: pkg_checks: %s" % self.pkg_checks)
- self.logger.debug("YUMng: pkg_verify: %s" % self.pkg_verify)
- self.logger.debug("YUMng: Upgrade on version fail: %s" \
- % self.doUpgrade)
- self.logger.debug("YUMng: Reinstall on verify fail: %s" \
- % self.doReinst)
- self.logger.debug("YUMng: installOnlyPkgs: %s" \
- % str(self.installOnlyPkgs))
- self.logger.debug("YUMng: verify_flags: %s" % self.verifyFlags)
-
- def _fixAutoVersion(self, entry):
- # old style entry; synthesize Instances from current installed
- if entry.get('name') not in self.yum_installed and \
- entry.get('name') not in self.yum_avail:
- # new entry; fall back to default
- entry.set('version', 'any')
- else:
- data = copy.copy(self.yum_installed[entry.get('name')])
- if entry.get('name') in self.yum_avail:
- # installed but out of date
- data.update(self.yum_avail[entry.get('name')])
- for (arch, (epoch, vers, rel)) in list(data.items()):
- x = Bcfg2.Client.XML.SubElement(entry, "Instance",
- name=entry.get('name'),
- version=vers, arch=arch,
- release=rel, epoch=epoch)
- if 'verify_flags' in entry.attrib:
- x.set('verify_flags', entry.get('verify_flags'))
- if 'verify' in entry.attrib:
- x.set('verify', entry.get('verify'))
-
- def _buildInstances(self, entry):
- instances = [inst for inst in entry \
- if inst.tag == 'Instance' or inst.tag == 'Package']
-
- # XXX: Uniquify instances. Cases where duplicates are returned.
- # However, the elements aren't comparable.
-
- if instances == []:
- # We have an old style no Instance entry. Convert it to new style.
- instance = Bcfg2.Client.XML.SubElement(entry, 'Package')
- for attrib in list(entry.attrib.keys()):
- instance.attrib[attrib] = entry.attrib[attrib]
- instances = [instance]
-
- return instances
-
- def _getGPGKeysAsPackages(self):
- """Return a list of the GPG RPM signing keys installed on the
- system as a list of Package Objects."""
-
- # XXX GPG keys existing in the RPMDB have numbered days
- # and newer Yum versions will not return information about them
- if hasattr(self.yb.rpmdb, 'returnGPGPubkeyPackages'):
- return self.yb.rpmdb.returnGPGPubkeyPackages()
- return self.yb.rpmdb.searchNevra(name='gpg-pubkey')
-
- def _verifyHelper(self, po):
- # This code primarly deals with a yum bug where the PO.verify()
- # method does not properly take into count multilib sharing of files.
- # Neither does RPM proper, really....it just ignores the problem.
- def verify(p):
- # disabling file checksums is a new feature yum 3.2.17-ish
- try:
- vResult = p.verify(fast=self.setup.get('quick', False))
- except TypeError:
- # Older Yum API
- vResult = p.verify()
- return vResult
-
- key = (po.name, po.epoch, po.version, po.release, po.arch)
- if key in self.verifyCache:
- results = self.verifyCache[key]
- else:
- results = verify(po)
- self.verifyCache[key] = results
- if not rpmUtils.arch.isMultiLibArch():
- return results
-
- # Okay deal with a buggy yum multilib and verify
- packages = self.yb.rpmdb.searchNevra(name=po.name, epoch=po.epoch,
- ver=po.version, rel=po.release) # find all arches of pkg
- if len(packages) == 1:
- return results # No mathcing multilib packages
-
- files = set(po.returnFileEntries()) # Will be the list of common fns
- common = {}
- for p in packages:
- if p != po:
- files = files & set(p.returnFileEntries())
- for p in packages:
- k = (p.name, p.epoch, p.version, p.release, p.arch)
- self.logger.debug("Multilib Verify: comparing %s to %s" \
- % (po, p))
- if k in self.verifyCache:
- v = self.verifyCache[k]
- else:
- v = verify(p)
- self.verifyCache[k] = v
-
- for fn, probs in v.items():
- # file problems must exist in ALL multilib packages to be real
- if fn in files:
- common[fn] = common.get(fn, 0) + 1
-
- flag = len(packages) - 1
- for fn, i in common.items():
- if i == flag:
- # this fn had verify problems in all but one of the multilib
- # packages. That means its correct in the package that's
- # "on top." Therefore, this is a fake verify problem.
- if fn in results:
- del results[fn]
-
- return results
-
- def RefreshPackages(self):
- """
- Creates self.installed{} which is a dict of installed packages.
-
- The dict items are lists of nevra dicts. This loosely matches the
- config from the server and what rpmtools uses to specify pacakges.
-
- e.g.
-
- self.installed['foo'] = [ {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'i386'},
- {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'x86_64'} ]
- """
-
- self.installed = {}
- packages = self._getGPGKeysAsPackages() + \
- self.yb.rpmdb.returnPackages()
- for po in packages:
- d = {}
- for i in ['name', 'epoch', 'version', 'release', 'arch']:
- d[i] = getattr(po, i)
- self.installed.setdefault(po.name, []).append(d)
-
- def VerifyPackage(self, entry, modlist, pinned_version=None):
- """
- Verify Package status for entry.
- Performs the following:
- - Checks for the presence of required Package Instances.
- - Compares the evra 'version' info against self.installed{}.
- - RPM level package verify (rpm --verify).
- - Checks for the presence of unrequired package instances.
-
- Produces the following dict and list for YUMng.Install() to use:
- For installs/upgrades/fixes of required instances:
- instance_status = { <Instance Element Object>:
- { 'installed': True|False,
- 'version_fail': True|False,
- 'verify_fail': True|False,
- 'pkg': <Package Element Object>,
- 'modlist': [ <filename>, ... ],
- 'verify' : [ <rpm --verify results> ]
- }, ......
- }
-
- For deletions of unrequired instances:
- extra_instances = [ <Package Element Object>, ..... ]
-
- Constructs the text prompts for interactive mode.
- """
-
- if entry.get('version', False) == 'auto':
- self._fixAutoVersion(entry)
-
- self.logger.debug("Verifying package instances for %s" \
- % entry.get('name'))
-
- self.verifyCache = {} # Used for checking multilib packages
- self.modlists[entry] = modlist
- instances = self._buildInstances(entry)
- packageCache = []
- package_fail = False
- qtext_versions = []
- virtPkg = False
- pkg_checks = self.pkg_checks and \
- entry.get('pkg_checks', 'true').lower() == 'true'
- pkg_verify = self.pkg_verify and \
- entry.get('pkg_verify', 'true').lower() == 'true'
-
- if entry.get('name') == 'gpg-pubkey':
- POs = self._getGPGKeysAsPackages()
- pkg_verify = False # No files here to verify
- else:
- POs = self.yb.rpmdb.searchNevra(name=entry.get('name'))
- if len(POs) == 0:
- # Some sort of virtual capability? Try to resolve it
- POs = self.yb.rpmdb.searchProvides(entry.get('name'))
- if len(POs) > 0:
- virtPkg = True
- self.logger.info("%s appears to be provided by:" \
- % entry.get('name'))
- for p in POs:
- self.logger.info(" %s" % p)
-
- for inst in instances:
- nevra = build_yname(entry.get('name'), inst)
- snevra = short_yname(nevra)
- if nevra in packageCache:
- continue # Ignore duplicate instances
- else:
- packageCache.append(nevra)
-
- self.logger.debug("Verifying: %s" % nevraString(nevra))
-
- # Set some defaults here
- stat = self.instance_status.setdefault(inst, {})
- stat['installed'] = True
- stat['version_fail'] = False
- stat['verify'] = {}
- stat['verify_fail'] = False
- stat['pkg'] = entry
- stat['modlist'] = modlist
- verify_flags = inst.get('verify_flags', self.verifyFlags)
- verify_flags = verify_flags.lower().replace(' ', ',').split(',')
-
- if len(POs) == 0:
- # Package not installed
- self.logger.debug(" %s is not installed" % nevraString(nevra))
- stat['installed'] = False
- package_fail = True
- qtext_versions.append("I(%s)" % nevra)
- continue
-
- if not pkg_checks:
- continue
-
- # Check EVR
- if virtPkg:
- self.logger.debug(" Not checking version for virtual package")
- _POs = [po for po in POs] # Make a copy
- elif entry.get('name') == 'gpg-pubkey':
- _POs = [p for p in POs if p.version == nevra['version'] \
- and p.release == nevra['release']]
- else:
- _POs = self.yb.rpmdb.searchNevra(**snevra)
- if len(_POs) == 0:
- package_fail = True
- stat['version_fail'] = True
- # Just chose the first pkg for the error message
- self.logger.info(" Wrong version installed. "\
- "Want %s, but have %s" % (nevraString(nevra),
- nevraString(POs[0])))
- qtext_versions.append("U(%s)" % str(POs[0]))
- continue
-
- if not (pkg_verify and \
- inst.get('pkg_verify', 'true').lower() == 'true'):
- continue
-
- # XXX: We ignore GPG sig checking the package as it
- # has nothing to do with the individual file hash/size/etc.
- # GPG checking the package only eaxmines some header/rpmdb
- # wacky-ness, and will not properly detect a compromised rpmdb.
- # Yum's verify routine does not support it for that reaosn.
-
- if len(_POs) > 1:
- self.logger.debug(" Verify Instance found many packages:")
- for po in _POs:
- self.logger.debug(" %s" % str(po))
-
- try:
- vResult = self._verifyHelper(_POs[0])
- except Exception, e:
- # Unknown Yum exception
- self.logger.warning(" Verify Exception: %s" % str(e))
- package_fail = True
- continue
-
- # Now take out the Yum specific objects / modlists / unproblmes
- ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
- [ig.get('name') for ig in inst.findall('Ignore')] + \
- self.ignores
- for fn, probs in vResult.items():
- if fn in modlist:
- self.logger.debug(" %s in modlist, skipping" % fn)
- continue
- if fn in ignores:
- self.logger.debug(" %s in ignore list, skipping" % fn)
- continue
- tmp = []
- for p in probs:
- if p.type == 'missing' and os.path.islink(fn):
- continue
- elif 'no' + p.type in verify_flags:
- continue
- if p.type not in ['missingok', 'ghost']:
- tmp.append((p.type, p.message))
- if tmp != []:
- stat['verify'][fn] = tmp
-
- if stat['verify'] != {}:
- stat['verify_fail'] = True
- package_fail = True
- self.logger.debug(" Verify Problems:")
- for fn, probs in stat['verify'].items():
- self.logger.debug(" %s" % fn)
- for p in probs:
- self.logger.debug(" %s: %s" % p)
-
- if len(POs) > 0:
- # Is this an install only package? We just look at the first one
- provides = set([p[0] for p in POs[0].provides] + [POs[0].name])
- install_only = len(set(self.installOnlyPkgs) & provides) > 0
- else:
- install_only = False
-
- if virtPkg or (install_only and not self.setup['kevlar']):
- # XXX: virtual capability supplied, we a probably dealing
- # with multiple packages of different names. This check
- # doesn't make a lot of since in this case
- # XXX: install_only: Yum may clean some of these up itself.
- # Otherwise having multiple instances of install only packages
- # is considered correct
- self.extra_instances = None
- else:
- self.extra_instances = self.FindExtraInstances(entry, POs)
- if self.extra_instances is not None:
- package_fail = True
-
- return not package_fail
-
- def FindExtraInstances(self, entry, POs):
- """
- Check for installed instances that are not in the config.
- Return a Package Entry with Instances to remove, or None if there
- are no Instances to remove.
-
- """
- if len(POs) == 0:
- return None
- name = entry.get('name')
- extra_entry = Bcfg2.Client.XML.Element('Package', name=name,
- type=self.pkgtype)
- instances = self._buildInstances(entry)
- _POs = [p for p in POs] # Shallow copy
-
- # Algorythm is sensitive to duplicates, check for them
- checked = []
- for inst in instances:
- nevra = build_yname(name, inst)
- snevra = short_yname(nevra)
- pkgs = self.yb.rpmdb.searchNevra(**snevra)
- flag = True
- if len(pkgs) > 0:
- if pkgs[0] in checked:
- continue # We've already taken care of this Instance
- else:
- checked.append(pkgs[0])
- _POs.remove(pkgs[0])
-
- for p in _POs:
- self.logger.debug(" Extra Instance Found: %s" % str(p))
- Bcfg2.Client.XML.SubElement(extra_entry, 'Instance',
- epoch=p.epoch, name=p.name, version=p.version,
- release=p.release, arch=p.arch)
-
- if _POs == []:
- return None
- else:
- return extra_entry
-
- def FindExtraPackages(self):
- """Find extra packages."""
- packages = [e.get('name') for e in self.getSupportedEntries()]
- extras = []
-
- for p in self.installed.keys():
- if p not in packages:
- entry = Bcfg2.Client.XML.Element('Package', name=p,
- type=self.pkgtype)
- for i in self.installed[p]:
- inst = Bcfg2.Client.XML.SubElement(entry, 'Instance', \
- epoch = i['epoch'],
- version = i['version'],
- release = i['release'],
- arch = i['arch'])
-
- extras.append(entry)
-
- return extras
-
- def _installGPGKey(self, inst, key_file):
- """Examine the GPG keys carefully before installation. Avoid
- installing duplicate keys. Returns True on successful install."""
-
- # RPM Transaction Set
- ts = self.yb.rpmdb.readOnlyTS()
-
- if not os.path.exists(key_file):
- self.logger.debug("GPG Key file %s not installed" % key_file)
- return False
-
- rawkey = open(key_file).read()
- gpg = yum.misc.getgpgkeyinfo(rawkey)
-
- ver = yum.misc.keyIdToRPMVer(gpg['keyid'])
- rel = yum.misc.keyIdToRPMVer(gpg['timestamp'])
- if not (ver == inst.get('version') and rel == inst.get('release')):
- self.logger.info("GPG key file %s does not match gpg-pubkey-%s-%s"\
- % (key_file, inst.get('version'),
- inst.get('release')))
- return False
-
- if not yum.misc.keyInstalled(ts, gpg['keyid'],
- gpg['timestamp']) == 0:
- result = ts.pgpImportPubkey(yum.misc.procgpgkey(rawkey))
- else:
- self.logger.debug("gpg-pubkey-%s-%s already installed"\
- % (inst.get('version'),
- inst.get('release')))
- return True
-
- if result != 0:
- self.logger.debug("Unable to install %s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'),
- self.str_evra(inst)))
- return False
- else:
- self.logger.debug("Installed %s-%s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'),
- inst.get('version'), inst.get('release')))
- return True
-
- def _runYumTransaction(self):
- rDisplay = RPMDisplay(self.logger)
- yDisplay = YumDisplay(self.logger)
- # Run the Yum Transaction
- rescode, restring = self.yb.buildTransaction()
- self.logger.debug("Initial Yum buildTransaction() run said:")
- self.logger.debug(" resultcode: %s, msgs: %s" \
- % (rescode, restring))
-
- if rescode != 1:
- # Transaction built successfully, run it
- self.yb.processTransaction(callback=yDisplay,
- rpmDisplay=rDisplay)
- self.logger.info("Single Pass for Install Succeeded")
- else:
- # The yum command failed. No packages installed.
- # Try installing instances individually.
- self.logger.error("Single Pass Install of Packages Failed")
- skipBroken = self.yb.conf.skip_broken
- self.yb.conf.skip_broken = True
- rescode, restring = self.yb.buildTransaction()
- if rescode != 1:
- self.yb.processTransaction(callback=yDisplay,
- rpmDisplay=rDisplay)
- self.logger.debug(
- "Second pass install did not install all packages")
- else:
- self.logger.error("Second pass yum install failed.")
- self.logger.debug(" %s" % restring)
- self.yb.conf.skip_broken = skipBroken
-
- self.yb.closeRpmDB()
- self.RefreshPackages()
-
- def Install(self, packages, states):
- """
- Try and fix everything that YUMng.VerifyPackages() found wrong for
- each Package Entry. This can result in individual RPMs being
- installed (for the first time), deleted, downgraded
- or upgraded.
-
- packages is a list of Package Elements that has
- states[<Package Element>] == False
-
- The following effects occur:
- - states{} is conditionally updated for each package.
- - self.installed{} is rebuilt, possibly multiple times.
- - self.instance_status{} is conditionally updated for each instance
- of a package.
- - Each package will be added to self.modified[] if its states{}
- entry is set to True.
-
- """
- self.logger.debug('Running YUMng.Install()')
-
- install_pkgs = []
- gpg_keys = []
- upgrade_pkgs = []
- reinstall_pkgs = []
-
- def queuePkg(pkg, inst, queue):
- if pkg.get('name') == 'gpg-pubkey':
- gpg_keys.append(inst)
- else:
- queue.append(inst)
-
- # Remove extra instances.
- # Can not reverify because we don't have a package entry.
- if self.extra_instances is not None and len(self.extra_instances) > 0:
- if (self.setup.get('remove') == 'all' or \
- self.setup.get('remove') == 'packages'):
- self.RemovePackages(self.extra_instances)
- else:
- self.logger.info("The following extra package instances will be removed by the '-r' option:")
- for pkg in self.extra_instances:
- for inst in pkg:
- self.logger.info(" %s %s" % \
- ((pkg.get('name'), self.str_evra(inst))))
-
- # Figure out which instances of the packages actually need something
- # doing to them and place in the appropriate work 'queue'.
- for pkg in packages:
- insts = [pinst for pinst in pkg \
- if pinst.tag in ['Instance', 'Package']]
- if insts:
- for inst in insts:
- if inst not in self.instance_status:
- m = " Asked to install/update package never verified"
- p = nevraString(build_yname(pkg.get('name'), inst))
- self.logger.warning("%s: %s" % (m, p))
- continue
- status = self.instance_status[inst]
- if not status.get('installed', False) and self.doInstall:
- queuePkg(pkg, inst, install_pkgs)
- elif status.get('version_fail', False) and self.doUpgrade:
- queuePkg(pkg, inst, upgrade_pkgs)
- elif status.get('verify_fail', False) and self.doReinst:
- queuePkg(pkg, inst, reinstall_pkgs)
- else:
- # Either there was no Install/Version/Verify
- # task to be done or the user disabled the actions
- # in the configuration. XXX Logging for the latter?
- pass
- else:
- msg = "YUMng: Package tag found where Instance expected: %s"
- self.logger.warning(msg % pkg.get('name'))
- queuePkg(pkg, pkg, install_pkgs)
-
- # Install GPG keys.
- # Alternatively specify the required keys using 'gpgkey' in the
- # repository definition in yum.conf. YUM will install the keys
- # automatically.
- if len(gpg_keys) > 0:
- self.logger.info("Installing GPG keys.")
- for inst in gpg_keys:
- if inst.get('simplefile') is None:
- self.logger.error("GPG key has no simplefile attribute")
- continue
- key_file = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- self._installGPGKey(inst, key_file)
-
- self.RefreshPackages()
- pkg = self.instance_status[gpg_keys[0]].get('pkg')
- states[pkg] = self.VerifyPackage(pkg, [])
-
- # Install packages.
- if len(install_pkgs) > 0:
- self.logger.info("Attempting to install packages")
-
- for inst in install_pkgs:
- pkg_arg = self.instance_status[inst].get('pkg').get('name')
- try:
- self.yb.install(**build_yname(pkg_arg, inst))
- except yum.Errors.YumBaseError, yume:
- self.logger.error("Error installing some packages: %s" % yume)
-
- if len(upgrade_pkgs) > 0:
- self.logger.info("Attempting to upgrade packages")
-
- for inst in upgrade_pkgs:
- pkg_arg = self.instance_status[inst].get('pkg').get('name')
- try:
- self.yb.update(**build_yname(pkg_arg, inst))
- except yum.Errors.YumBaseError, yume:
- self.logger.error("Error upgrading some packages: %s" % yume)
-
- if len(reinstall_pkgs) > 0:
- self.logger.info("Attempting to reinstall packages")
- for inst in reinstall_pkgs:
- pkg_arg = self.instance_status[inst].get('pkg').get('name')
- try:
- self.yb.reinstall(**build_yname(pkg_arg, inst))
- except yum.Errors.YumBaseError, yume:
- self.logger.error("Error upgrading some packages: %s" \
- % yume)
-
- self._runYumTransaction()
-
- if not self.setup['kevlar']:
- for pkg_entry in [p for p in packages if self.canVerify(p)]:
- self.logger.debug("Reverifying Failed Package %s" \
- % (pkg_entry.get('name')))
- states[pkg_entry] = self.VerifyPackage(pkg_entry,
- self.modlists.get(pkg_entry, []))
-
- for entry in [ent for ent in packages if states[ent]]:
- self.modified.append(entry)
-
- def RemovePackages(self, packages):
- """
- Remove specified entries.
-
- packages is a list of Package Entries with Instances generated
- by FindExtraPackages().
- """
- self.logger.debug('Running YUMng.RemovePackages()')
-
- erase_args = []
- for pkg in packages:
- for inst in pkg:
- nevra = build_yname(pkg.get('name'), inst)
- if pkg.get('name') != 'gpg-pubkey':
- self.yb.remove(**nevra)
- self.modified.append(pkg)
- else:
- self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s-%s"\
- % (nevra['name'], nevra['version'], nevra['release']))
- self.logger.info(" This package will be deleted in a future version of the YUMng driver.")
-
- self._runYumTransaction()
- self.extra = self.FindExtraPackages()
-
- def VerifyPath(self, entry, _):
- """Do nothing here since we only verify Path type=ignore"""
- return True
diff --git a/build/lib/Bcfg2/Client/Tools/__init__.py b/build/lib/Bcfg2/Client/Tools/__init__.py
deleted file mode 100644
index 8a90e130c..000000000
--- a/build/lib/Bcfg2/Client/Tools/__init__.py
+++ /dev/null
@@ -1,370 +0,0 @@
-"""This contains all Bcfg2 Tool modules"""
-# suppress popen2 warnings for python 2.3
-import warnings
-warnings.filterwarnings("ignore", "The popen2 module is deprecated.*",
- DeprecationWarning)
-import os
-import popen2
-import stat
-import sys
-import time
-
-import Bcfg2.Client.XML
-__revision__ = '$Revision$'
-
-__all__ = [tool.split('.')[0] \
- for tool in os.listdir(os.path.dirname(__file__)) \
- if tool.endswith(".py") and tool != "__init__.py"]
-
-drivers = [item for item in __all__ if item not in ['rpmtools']]
-default = [item for item in drivers if item not in ['RPM', 'Yum']]
-
-
-class toolInstantiationError(Exception):
- """This error is called if the toolset cannot be instantiated."""
- pass
-
-
-class readonlypipe(popen2.Popen4):
- """This pipe sets up stdin --> /dev/null."""
-
- def __init__(self, cmd, bufsize=-1):
- popen2._cleanup()
- c2pread, c2pwrite = os.pipe()
- null = open('/dev/null', 'w+')
- self.pid = os.fork()
- if self.pid == 0:
- # Child
- os.dup2(null.fileno(), sys.__stdin__.fileno())
- #os.dup2(p2cread, 0)
- os.dup2(c2pwrite, 1)
- os.dup2(c2pwrite, 2)
- self._run_child(cmd)
- os.close(c2pwrite)
- self.fromchild = os.fdopen(c2pread, 'r', bufsize)
- popen2._active.append(self)
-
-
-class executor:
- """This class runs stuff for us"""
-
- def __init__(self, logger):
- self.logger = logger
-
- def run(self, command):
- """Run a command in a pipe dealing with stdout buffer overloads."""
- self.logger.debug('> %s' % command)
-
- runpipe = readonlypipe(command, bufsize=16384)
- output = []
- try:#macosx doesn't like this
- runpipe.fromchild.flush()
- except IOError:
- pass
- line = runpipe.fromchild.readline()
- cmdstat = -1
- while cmdstat == -1:
- while line:
- if len(line) > 0:
- self.logger.debug('< %s' % line[:-1])
- output.append(line[:-1])
- line = runpipe.fromchild.readline()
- time.sleep(0.1)
- cmdstat = runpipe.poll()
- output += [line[:-1] for line in runpipe.fromchild.readlines() \
- if line]
- # The exit code from the program is in the upper byte of the
- # value returned by cmdstat. Shift it down for tools looking at
- # the value.
- return ((cmdstat >> 8), output)
-
-
-class Tool:
- """
- All tools subclass this. It defines all interfaces that need to be defined.
- """
- name = 'Tool'
- __execs__ = []
- __handles__ = []
- __req__ = {}
- __important__ = []
-
- def __init__(self, logger, setup, config):
- self.__important__ = [entry.get('name') \
- for struct in config for entry in struct \
- if entry.tag == 'Path' and \
- entry.get('important') in ['true', 'True']]
- self.setup = setup
- self.logger = logger
- if not hasattr(self, '__ireq__'):
- self.__ireq__ = self.__req__
- self.config = config
- self.cmd = executor(logger)
- self.modified = []
- self.extra = []
- self.handled = [entry for struct in self.config for entry in struct \
- if self.handlesEntry(entry)]
- for filename in self.__execs__:
- try:
- mode = stat.S_IMODE(os.stat(filename)[stat.ST_MODE])
- if mode & stat.S_IEXEC != stat.S_IEXEC:
- self.logger.debug("%s: %s not executable" % \
- (self.name, filename))
- raise toolInstantiationError
- except OSError:
- raise toolInstantiationError
- except:
- self.logger.debug("%s failed" % filename, exc_info=1)
- raise toolInstantiationError
-
- def BundleUpdated(self, _, states):
- """This callback is used when bundle updates occur."""
- return
-
- def BundleNotUpdated(self, _, states):
- """This callback is used when a bundle is not updated."""
- return
-
- def Inventory(self, states, structures=[]):
- """Dispatch verify calls to underlying methods."""
- if not structures:
- structures = self.config.getchildren()
- mods = self.buildModlist()
- for (struct, entry) in [(struct, entry) for struct in structures \
- for entry in struct.getchildren() \
- if self.canVerify(entry)]:
- try:
- func = getattr(self, "Verify%s" % (entry.tag))
- states[entry] = func(entry, mods)
- except:
- self.logger.error(
- "Unexpected failure of verification method for entry type %s" \
- % (entry.tag), exc_info=1)
- self.extra = self.FindExtra()
-
- def Install(self, entries, states):
- """Install all entries in sublist."""
- for entry in entries:
- try:
- func = getattr(self, "Install%s" % (entry.tag))
- states[entry] = func(entry)
- self.modified.append(entry)
- except:
- self.logger.error("Unexpected failure of install method for entry type %s" \
- % (entry.tag), exc_info=1)
-
- def Remove(self, entries):
- """Remove specified extra entries"""
- pass
-
- def getSupportedEntries(self):
- """Return a list of supported entries."""
- return [entry for struct in \
- self.config.getchildren() for entry in \
- struct.getchildren() \
- if self.handlesEntry(entry)]
-
- def handlesEntry(self, entry):
- """Return if entry is handled by this tool."""
- return (entry.tag, entry.get('type')) in self.__handles__
-
- def buildModlist(self):
- '''Build a list of potentially modified POSIX paths for this entry'''
- return [entry.get('name') for struct in self.config.getchildren() \
- for entry in struct.getchildren() \
- if entry.tag in ['Ignore', 'Path']]
-
- def gatherCurrentData(self, entry):
- """Default implementation of the information gathering routines."""
- pass
-
- def canVerify(self, entry):
- """Test if entry has enough information to be verified."""
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Entry %s:%s reports bind failure: %s" % \
- (entry.tag, entry.get('name'), entry.get('failure')))
- return False
-
- missing = [attr for attr in self.__req__[entry.tag] \
- if attr not in entry.attrib]
- if missing:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- self.logger.error("\t... due to absence of %s attribute(s)" % \
- (":".join(missing)))
- try:
- self.gatherCurrentData(entry)
- except:
- self.logger.error("Unexpected error in gatherCurrentData", exc_info=1)
- return False
- return True
-
- def FindExtra(self):
- """Return a list of extra entries."""
- return []
-
- def canInstall(self, entry):
- """Test if entry has enough information to be installed."""
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Cannot install entry %s:%s with bind failure" % \
- (entry.tag, entry.get('name')))
- return False
-
- missing = [attr for attr in self.__ireq__[entry.tag] \
- if attr not in entry.attrib or not entry.attrib[attr]]
- if missing:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- self.logger.error("\t... due to absence of %s attribute" % \
- (":".join(missing)))
- return False
- return True
-
-
-class PkgTool(Tool):
- """
- PkgTool provides a one-pass install with
- fallback for use with packaging systems
- """
- pkgtool = ('echo %s', ('%s', ['name']))
- pkgtype = 'echo'
- name = 'PkgTool'
-
- def __init__(self, logger, setup, config):
- Tool.__init__(self, logger, setup, config)
- self.installed = {}
- self.Remove = self.RemovePackages
- self.FindExtra = self.FindExtraPackages
- self.RefreshPackages()
-
- def VerifyPackage(self, dummy, _):
- """Dummy verification method"""
- return False
-
- def Install(self, packages, states):
- """
- Run a one-pass install, followed by
- single pkg installs in case of failure.
- """
- self.logger.info("Trying single pass package install for pkgtype %s" % \
- self.pkgtype)
-
- data = [tuple([pkg.get(field) for field in self.pkgtool[1][1]]) for pkg in packages]
- pkgargs = " ".join([self.pkgtool[1][0] % datum for datum in data])
-
- self.logger.debug("Installing packages: :%s:" % pkgargs)
- self.logger.debug("Running command ::%s::" % (self.pkgtool[0] % pkgargs))
-
- cmdrc = self.cmd.run(self.pkgtool[0] % pkgargs)[0]
- if cmdrc == 0:
- self.logger.info("Single Pass Succeded")
- # set all package states to true and flush workqueues
- pkgnames = [pkg.get('name') for pkg in packages]
- for entry in [entry for entry in list(states.keys())
- if entry.tag == 'Package'
- and entry.get('type') == self.pkgtype
- and entry.get('name') in pkgnames]:
- self.logger.debug('Setting state to true for pkg %s' % \
- (entry.get('name')))
- states[entry] = True
- self.RefreshPackages()
- else:
- self.logger.error("Single Pass Failed")
- # do single pass installs
- self.RefreshPackages()
- for pkg in packages:
- # handle state tracking updates
- if self.VerifyPackage(pkg, []):
- self.logger.info("Forcing state to true for pkg %s" % \
- (pkg.get('name')))
- states[pkg] = True
- else:
- self.logger.info("Installing pkg %s version %s" %
- (pkg.get('name'), pkg.get('version')))
- cmdrc = self.cmd.run(self.pkgtool[0] %
- (self.pkgtool[1][0] %
- tuple([pkg.get(field) for field in self.pkgtool[1][1]])))
- if cmdrc[0] == 0:
- states[pkg] = True
- else:
- self.logger.error("Failed to install package %s" % \
- (pkg.get('name')))
- self.RefreshPackages()
- for entry in [ent for ent in packages if states[ent]]:
- self.modified.append(entry)
-
- def RefreshPackages(self):
- """Dummy state refresh method."""
- pass
-
- def RemovePackages(self, packages):
- """Dummy implementation of package removal method."""
- pass
-
- def FindExtraPackages(self):
- """Find extra packages."""
- packages = [entry.get('name') for entry in self.getSupportedEntries()]
- extras = [data for data in list(self.installed.items()) \
- if data[0] not in packages]
- return [Bcfg2.Client.XML.Element('Package', name=name, \
- type=self.pkgtype, version=version) \
- for (name, version) in extras]
-
-
-class SvcTool(Tool):
- """This class defines basic Service behavior"""
- name = 'SvcTool'
-
- def get_svc_command(self, service, action):
- """Return the basename of the command used to start/stop services."""
- return '/etc/init.d/%s %s' % (service.get('name'), action)
-
- def start_service(self, service):
- self.logger.debug('Starting service %s' % service.get('name'))
- return self.cmd.run(self.get_svc_command(service, 'start'))[0]
-
- def stop_service(self, service):
- self.logger.debug('Stopping service %s' % service.get('name'))
- return self.cmd.run(self.get_svc_command(service, 'stop'))[0]
-
- def restart_service(self, service):
- self.logger.debug('Restarting service %s' % service.get('name'))
- restart_target = 'restart'
- if service.get('mode', 'default') == 'custom':
- restart_target = service.get('target', 'restart')
- return self.cmd.run(self.get_svc_command(service, restart_target))[0]
-
- def check_service(self, service):
- # not supported for this driver
- return 0
-
- def BundleUpdated(self, bundle, states):
- """The Bundle has been updated."""
- if self.setup['servicemode'] == 'disabled':
- return
-
- for entry in [ent for ent in bundle if self.handlesEntry(ent)]:
- if entry.get('mode', 'default') == 'manual':
- continue
- # need to handle servicemode = (build|default)
- # need to handle mode = (default|supervised|custom)
- if entry.get('status') == 'on':
- if self.setup['servicemode'] == 'build':
- rc = self.stop_service(entry)
- else:
- if self.setup['interactive']:
- prompt = 'Restart service %s?: (y/N): ' % entry.get('name')
- if raw_input(prompt) not in ['y', 'Y']:
- continue
- rc = self.restart_service(entry)
- else:
- rc = self.stop_service(entry)
- if rc:
- self.logger.error("Failed to manipulate service %s" % \
- (entry.get('name')))
diff --git a/build/lib/Bcfg2/Client/Tools/launchd.py b/build/lib/Bcfg2/Client/Tools/launchd.py
deleted file mode 100644
index db6d94c1b..000000000
--- a/build/lib/Bcfg2/Client/Tools/launchd.py
+++ /dev/null
@@ -1,131 +0,0 @@
-"""launchd support for Bcfg2."""
-__revision__ = '$Revision$'
-
-import os
-import popen2
-
-import Bcfg2.Client.Tools
-
-
-class launchd(Bcfg2.Client.Tools.Tool):
- """Support for Mac OS X launchd services."""
- __handles__ = [('Service', 'launchd')]
- __execs__ = ['/bin/launchctl', '/usr/bin/defaults']
- name = 'launchd'
- __req__ = {'Service': ['name', 'status']}
-
- '''
- Currently requires the path to the plist to load/unload,
- and Name is acually a reverse-fqdn (or the label).
- '''
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.Tool.__init__(self, logger, setup, config)
-
- '''Locate plist file that provides given reverse-fqdn name
- /Library/LaunchAgents Per-user agents provided by the administrator.
- /Library/LaunchDaemons System wide daemons provided by the administrator.
- /System/Library/LaunchAgents Mac OS X Per-user agents.
- /System/Library/LaunchDaemons Mac OS X System wide daemons.'''
- plistLocations = ["/Library/LaunchDaemons", "/System/Library/LaunchDaemons"]
- self.plistMapping = {}
- for directory in plistLocations:
- for daemon in os.listdir(directory):
- try:
- if daemon.endswith(".plist"):
- d = daemon[:-6]
- else:
- d = daemon
- (stdout, _) = popen2.popen2('defaults read %s/%s Label' % (directory, d))
- label = stdout.read().strip()
- self.plistMapping[label] = "%s/%s" % (directory, daemon)
- except KeyError: #perhaps this could be more robust
- pass
-
- def FindPlist(self, entry):
- return self.plistMapping.get(entry.get('name'), None)
-
- def os_version(self):
- version = ""
- try:
- vers = self.cmd.run('sw_vers')[1]
- except:
- return version
-
- for line in vers:
- if line.startswith("ProductVersion"):
- version = line.split()[-1]
- return version
-
- def VerifyService(self, entry, _):
- """Verify launchd service entry."""
- try:
- services = self.cmd.run("/bin/launchctl list")[1]
- except IndexError:#happens when no services are running (should be never)
- services = []
- # launchctl output changed in 10.5
- # It is now three columns, with the last column being the name of the # service
- version = self.os_version()
- if version.startswith('10.5') or version.startswith('10.6'):
- services = [s.split()[-1] for s in services]
- if entry.get('name') in services:#doesn't check if non-spawning services are Started
- return entry.get('status') == 'on'
- else:
- self.logger.debug("Didn't find service Loaded (launchd running under same user as bcfg)")
- return entry.get('status') == 'off'
-
- try: #Perhaps add the "-w" flag to load and unload to modify the file itself!
- self.cmd.run("/bin/launchctl load -w %s" % self.FindPlist(entry))
- except IndexError:
- return 'on'
- return False
-
- def InstallService(self, entry):
- """Enable or disable launchd item."""
- name = entry.get('name')
- if entry.get('status') == 'on':
- self.logger.error("Installing service %s" % name)
- cmdrc = self.cmd.run("/bin/launchctl load -w %s" % self.FindPlist(entry))
- cmdrc = self.cmd.run("/bin/launchctl start %s" % name)
- else:
- self.logger.error("Uninstalling service %s" % name)
- cmdrc = self.cmd.run("/bin/launchctl stop %s" % name)
- cmdrc = self.cmd.run("/bin/launchctl unload -w %s" % self.FindPlist(entry))
- return cmdrc[0] == 0
-
- def Remove(self, svcs):
- """Remove Extra launchd entries."""
- pass
-
- def FindExtra(self):
- """Find Extra launchd services."""
- try:
- allsrv = self.cmd.run("/bin/launchctl list")[1]
- except IndexError:
- allsrv = []
-
- [allsrv.remove(svc) for svc in [entry.get("name") for entry
- in self.getSupportedEntries()] if svc in allsrv]
- return [Bcfg2.Client.XML.Element("Service",
- type='launchd',
- name=name,
- status='on') for name in allsrv]
-
- def BundleUpdated(self, bundle, states):
- """Reload launchd plist."""
- for entry in [entry for entry in bundle if self.handlesEntry(entry)]:
- if not self.canInstall(entry):
- self.logger.error("Insufficient information to restart service %s" % (entry.get('name')))
- else:
- name = entry.get('name')
- if entry.get('status') == 'on' and self.FindPlist(entry):
- self.logger.info("Reloading launchd service %s" % name)
- #stop?
- self.cmd.run("/bin/launchctl stop %s" % name)
- self.cmd.run("/bin/launchctl unload -w %s" % (self.FindPlist(entry)))#what if it disappeared? how do we stop services that are currently running but the plist disappeared?!
- self.cmd.run("/bin/launchctl load -w %s" % (self.FindPlist(entry)))
- self.cmd.run("/bin/launchctl start %s" % name)
- else:
- #only if necessary....
- self.cmd.run("/bin/launchctl stop %s" % name)
- self.cmd.run("/bin/launchctl unload -w %s" % (self.FindPlist(entry)))
diff --git a/build/lib/Bcfg2/Client/Tools/rpmtools.py b/build/lib/Bcfg2/Client/Tools/rpmtools.py
deleted file mode 100644
index 3cd2b7014..000000000
--- a/build/lib/Bcfg2/Client/Tools/rpmtools.py
+++ /dev/null
@@ -1,1115 +0,0 @@
-#!/usr/bin/env python
-"""
- Module that uses rpm-python to implement the following rpm
- functionality for the bcfg2 RPM and YUM client drivers:
-
- rpm -qa
- rpm --verify
- rpm --erase
-
- The code closely follows the rpm C code.
-
- The code was written to be used in the bcfg2 RPM/YUM drivers.
-
- Some command line options have been provided to assist with
- testing and development, but the output isn't pretty and looks
- nothing like rpm output.
-
- Run 'rpmtools' -h for the options.
-
-"""
-__revision__ = '$Revision$'
-
-import grp
-import optparse
-import os
-import pwd
-import rpm
-import stat
-import sys
-if sys.version_info >= (2, 5):
- import hashlib
- py24compat = False
-else:
- # FIXME: Remove when client python dep is 2.5 or greater
- py24compat = True
- import md5
-
-# Determine what prelink tools we have available.
-# The isprelink module is a python extension that examines the ELF headers
-# to see if the file has been prelinked. If it is not present a lot of files
-# are unnecessarily run through the prelink command.
-try:
- from isprelink import *
- isprelink_imported = True
-except ImportError:
- isprelink_imported = False
- #print '*********************** isprelink not loaded ***********************'
-
-# If the prelink command is installed on the system then we need to do
-# prelink -y on files.
-if os.access('/usr/sbin/prelink', os.X_OK):
- prelink_exists = True
-else:
- prelink_exists = False
-
-# If we don't have isprelink then we will use the prelink configuration file to
-# filter what we have to put through prelink -y.
-import re
-blacklist = []
-whitelist = []
-try:
- f = open('/etc/prelink.conf', mode='r')
- for line in f:
- if line.startswith('#'):
- continue
- option, pattern = line.split()
- if pattern.startswith('*.'):
- pattern = pattern.replace('*.', '\.')
- pattern += '$'
- elif pattern.startswith('/'):
- pattern = '^' + pattern
- if option == '-b':
- blacklist.append(pattern)
- elif option == '-l':
- whitelist.append(pattern)
- f.close()
-except IOError:
- pass
-
-blacklist_re = re.compile('|'.join(blacklist))
-whitelist_re = re.compile('|'.join(whitelist))
-
-# Flags that are not defined in rpm-python.
-# They are defined in lib/rpmcli.h
-# Bit(s) for verifyFile() attributes.
-#
-RPMVERIFY_NONE = 0 # /*!< */
-RPMVERIFY_MD5 = 1 # 1 << 0 # /*!< from %verify(md5) */
-RPMVERIFY_FILESIZE = 2 # 1 << 1 # /*!< from %verify(size) */
-RPMVERIFY_LINKTO = 4 # 1 << 2 # /*!< from %verify(link) */
-RPMVERIFY_USER = 8 # 1 << 3 # /*!< from %verify(user) */
-RPMVERIFY_GROUP = 16 # 1 << 4 # /*!< from %verify(group) */
-RPMVERIFY_MTIME = 32 # 1 << 5 # /*!< from %verify(mtime) */
-RPMVERIFY_MODE = 64 # 1 << 6 # /*!< from %verify(mode) */
-RPMVERIFY_RDEV = 128 # 1 << 7 # /*!< from %verify(rdev) */
-RPMVERIFY_CONTEXTS = 32768 # (1 << 15) # /*!< from --nocontexts */
-RPMVERIFY_READLINKFAIL = 268435456 # (1 << 28) # /*!< readlink failed */
-RPMVERIFY_READFAIL = 536870912 # (1 << 29) # /*!< file read failed */
-RPMVERIFY_LSTATFAIL = 1073741824 # (1 << 30) # /*!< lstat failed */
-RPMVERIFY_LGETFILECONFAIL = 2147483648 # (1 << 31) # /*!< lgetfilecon failed */
-
-RPMVERIFY_FAILURES = \
- (RPMVERIFY_LSTATFAIL|RPMVERIFY_READFAIL|RPMVERIFY_READLINKFAIL| \
- RPMVERIFY_LGETFILECONFAIL)
-
-# Bit(s) to control rpm_verify() operation.
-#
-VERIFY_DEFAULT = 0, # /*!< */
-VERIFY_MD5 = 1 << 0 # /*!< from --nomd5 */
-VERIFY_SIZE = 1 << 1 # /*!< from --nosize */
-VERIFY_LINKTO = 1 << 2 # /*!< from --nolinkto */
-VERIFY_USER = 1 << 3 # /*!< from --nouser */
-VERIFY_GROUP = 1 << 4 # /*!< from --nogroup */
-VERIFY_MTIME = 1 << 5 # /*!< from --nomtime */
-VERIFY_MODE = 1 << 6 # /*!< from --nomode */
-VERIFY_RDEV = 1 << 7 # /*!< from --nodev */
-# /* bits 8-14 unused, reserved for rpmVerifyAttrs */
-VERIFY_CONTEXTS = 1 << 15 # /*!< verify: from --nocontexts */
-VERIFY_FILES = 1 << 16 # /*!< verify: from --nofiles */
-VERIFY_DEPS = 1 << 17 # /*!< verify: from --nodeps */
-VERIFY_SCRIPT = 1 << 18 # /*!< verify: from --noscripts */
-VERIFY_DIGEST = 1 << 19 # /*!< verify: from --nodigest */
-VERIFY_SIGNATURE = 1 << 20 # /*!< verify: from --nosignature */
-VERIFY_PATCHES = 1 << 21 # /*!< verify: from --nopatches */
-VERIFY_HDRCHK = 1 << 22 # /*!< verify: from --nohdrchk */
-VERIFY_FOR_LIST = 1 << 23 # /*!< query: from --list */
-VERIFY_FOR_STATE = 1 << 24 # /*!< query: from --state */
-VERIFY_FOR_DOCS = 1 << 25 # /*!< query: from --docfiles */
-VERIFY_FOR_CONFIG = 1 << 26 # /*!< query: from --configfiles */
-VERIFY_FOR_DUMPFILES = 1 << 27 # /*!< query: from --dump */
-# /* bits 28-31 used in rpmVerifyAttrs */
-
-# Comes from C cource. lib/rpmcli.h
-VERIFY_ATTRS = \
- (VERIFY_MD5 | VERIFY_SIZE | VERIFY_LINKTO | VERIFY_USER | VERIFY_GROUP | \
- VERIFY_MTIME | VERIFY_MODE | VERIFY_RDEV | VERIFY_CONTEXTS)
-
-VERIFY_ALL = \
- (VERIFY_ATTRS | VERIFY_FILES | VERIFY_DEPS | VERIFY_SCRIPT | VERIFY_DIGEST |\
- VERIFY_SIGNATURE | VERIFY_HDRCHK)
-
-
-# Some masks for what checks to NOT do on these file types.
-# The C code actiually resets these up for every file.
-DIR_FLAGS = ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | \
- RPMVERIFY_LINKTO)
-
-# These file types all have the same mask, but hopefully this will make the
-# code more readable.
-FIFO_FLAGS = CHR_FLAGS = BLK_FLAGS = GHOST_FLAGS = DIR_FLAGS
-
-LINK_FLAGS = ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | \
- RPMVERIFY_MODE | RPMVERIFY_USER | RPMVERIFY_GROUP)
-
-REG_FLAGS = ~(RPMVERIFY_LINKTO)
-
-
-def s_isdev(mode):
- """
- Check to see if a file is a device.
-
- """
- return stat.S_ISBLK(mode) | stat.S_ISCHR(mode)
-
-def rpmpackagelist(rts):
- """
- Equivalent of rpm -qa. Intended for RefreshPackages() in the RPM Driver.
- Requires rpmtransactionset() to be run first to get a ts.
- Returns a list of pkgspec dicts.
-
- e.g. [ {'name':'foo', 'epoch':'20', 'version':'1.2', 'release':'5', 'arch':'x86_64' },
- {'name':'bar', 'epoch':'10', 'version':'5.2', 'release':'2', 'arch':'x86_64' } ]
-
- """
- return [{'name':header[rpm.RPMTAG_NAME],
- 'epoch':header[rpm.RPMTAG_EPOCH],
- 'version':header[rpm.RPMTAG_VERSION],
- 'release':header[rpm.RPMTAG_RELEASE],
- 'arch':header[rpm.RPMTAG_ARCH],
- 'gpgkeyid':header.sprintf("%|SIGGPG?{%{SIGGPG:pgpsig}}:{None}|").split()[-1]}
- for header in rts.dbMatch()]
-
-def getindexbykeyword(index_ts, **kwargs):
- """
- Return list of indexs from the rpmdb matching keywords
- ex: getHeadersByKeyword(name='foo', version='1', release='1')
-
- Can be passed any structure that can be indexed by the pkgspec
- keyswords as other keys are filtered out.
-
- """
- lst = []
- name = kwargs.get('name')
- if name:
- index_mi = index_ts.dbMatch(rpm.RPMTAG_NAME, name)
- else:
- index_mi = index_ts.dbMatch()
-
- if 'epoch' in kwargs:
- if kwargs['epoch'] != None and kwargs['epoch'] != 'None':
- kwargs['epoch'] = int(kwargs['epoch'])
- else:
- del(kwargs['epoch'])
-
- keywords = [key for key in list(kwargs.keys()) \
- if key in ('name', 'epoch', 'version', 'release', 'arch')]
- keywords_len = len(keywords)
- for hdr in index_mi:
- match = 0
- for keyword in keywords:
- if hdr[keyword] == kwargs[keyword]:
- match += 1
- if match == keywords_len:
- lst.append(index_mi.instance())
- del index_mi
- return lst
-
-def getheadersbykeyword(header_ts, **kwargs):
- """
- Borrowed parts of this from from Yum. Need to fix it though.
- Epoch is not handled right.
-
- Return list of headers from the rpmdb matching keywords
- ex: getHeadersByKeyword(name='foo', version='1', release='1')
-
- Can be passed any structure that can be indexed by the pkgspec
- keyswords as other keys are filtered out.
-
- """
- lst = []
- name = kwargs.get('name')
- if name:
- header_mi = header_ts.dbMatch(rpm.RPMTAG_NAME, name)
- else:
- header_mi = header_ts.dbMatch()
-
- if 'epoch' in kwargs:
- if kwargs['epoch'] != None and kwargs['epoch'] != 'None':
- kwargs['epoch'] = int(kwargs['epoch'])
- else:
- del(kwargs['epoch'])
-
- keywords = [key for key in list(kwargs.keys()) \
- if key in ('name', 'epoch', 'version', 'release', 'arch')]
- keywords_len = len(keywords)
- for hdr in header_mi:
- match = 0
- for keyword in keywords:
- if hdr[keyword] == kwargs[keyword]:
- match += 1
- if match == keywords_len:
- lst.append(hdr)
- del header_mi
- return lst
-
-def prelink_md5_check(filename):
- """
- Checks if a file is prelinked. If it is run it through prelink -y
- to get the unprelinked md5 and file size.
-
- Return 0 if the file was not prelinked, otherwise return the file size.
- Always return the md5.
-
- """
- prelink = False
- try:
- plf = open(filename, "rb")
- except IOError:
- return False, 0
-
- if prelink_exists:
- if isprelink_imported:
- plfd = plf.fileno()
- if isprelink(plfd):
- plf.close()
- cmd = '/usr/sbin/prelink -y %s 2> /dev/null' \
- % (re.escape(filename))
- plf = os.popen(cmd, 'rb')
- prelink = True
- elif whitelist_re.search(filename) and not blacklist_re.search(filename):
- plf.close()
- cmd = '/usr/sbin/prelink -y %s 2> /dev/null' \
- % (re.escape(filename))
- plf = os.popen(cmd, 'rb')
- prelink = True
-
- fsize = 0
- if py24compat:
- chksum = md5.new()
- else:
- chksum = hashlib.md5()
- while 1:
- data = plf.read()
- if not data:
- break
- fsize += len(data)
- chksum.update(data)
- plf.close()
- file_md5 = chksum.hexdigest()
- if prelink:
- return file_md5, fsize
- else:
- return file_md5, 0
-
-def prelink_size_check(filename):
- """
- This check is only done if the prelink_md5_check() is not done first.
-
- Checks if a file is prelinked. If it is run it through prelink -y
- to get the unprelinked file size.
-
- Return 0 if the file was not prelinked, otherwise return the file size.
-
- """
- fsize = 0
- try:
- plf = open(filename, "rb")
- except IOError:
- return False
-
- if prelink_exists:
- if isprelink_imported:
- plfd = plf.fileno()
- if isprelink(plfd):
- plf.close()
- cmd = '/usr/sbin/prelink -y %s 2> /dev/null' \
- % (re.escape(filename))
- plf = os.popen(cmd, 'rb')
-
- while 1:
- data = plf.read()
- if not data:
- break
- fsize += len(data)
-
- elif whitelist_re.search(filename) and not blacklist_re.search(filename):
- # print "***** Warning isprelink extension failed to import ******"
- plf.close()
- cmd = '/usr/sbin/prelink -y %s 2> /dev/null' \
- % (re.escape(filename))
- plf = os.popen(cmd, 'rb')
-
- while 1:
- data = plf.read()
- if not data:
- break
- fsize += len(data)
-
- plf.close()
-
- return fsize
-
-def debug_verify_flags(vflags):
- """
- Decodes the verify flags bits.
- """
- if vflags & RPMVERIFY_MD5:
- print('RPMVERIFY_MD5')
- if vflags & RPMVERIFY_FILESIZE:
- print('RPMVERIFY_FILESIZE')
- if vflags & RPMVERIFY_LINKTO:
- print('RPMVERIFY_LINKTO')
- if vflags & RPMVERIFY_USER:
- print('RPMVERIFY_USER')
- if vflags & RPMVERIFY_GROUP:
- print('RPMVERIFY_GROUP')
- if vflags & RPMVERIFY_MTIME:
- print('RPMVERIFY_MTIME')
- if vflags & RPMVERIFY_MODE:
- print('RPMVERIFY_MODE')
- if vflags & RPMVERIFY_RDEV:
- print('RPMVERIFY_RDEV')
- if vflags & RPMVERIFY_CONTEXTS:
- print('RPMVERIFY_CONTEXTS')
- if vflags & RPMVERIFY_READLINKFAIL:
- print('RPMVERIFY_READLINKFAIL')
- if vflags & RPMVERIFY_READFAIL:
- print('RPMVERIFY_READFAIL')
- if vflags & RPMVERIFY_LSTATFAIL:
- print('RPMVERIFY_LSTATFAIL')
- if vflags & RPMVERIFY_LGETFILECONFAIL:
- print('RPMVERIFY_LGETFILECONFAIL')
-
-def debug_file_flags(fflags):
- """
- Decodes the file flags bits.
- """
- if fflags & rpm.RPMFILE_CONFIG:
- print('rpm.RPMFILE_CONFIG')
-
- if fflags & rpm.RPMFILE_DOC:
- print('rpm.RPMFILE_DOC')
-
- if fflags & rpm.RPMFILE_ICON:
- print('rpm.RPMFILE_ICON')
-
- if fflags & rpm.RPMFILE_MISSINGOK:
- print('rpm.RPMFILE_MISSINGOK')
-
- if fflags & rpm.RPMFILE_NOREPLACE:
- print('rpm.RPMFILE_NOREPLACE')
-
- if fflags & rpm.RPMFILE_GHOST:
- print('rpm.RPMFILE_GHOST')
-
- if fflags & rpm.RPMFILE_LICENSE:
- print('rpm.RPMFILE_LICENSE')
-
- if fflags & rpm.RPMFILE_README:
- print('rpm.RPMFILE_README')
-
- if fflags & rpm.RPMFILE_EXCLUDE:
- print('rpm.RPMFILE_EXLUDE')
-
- if fflags & rpm.RPMFILE_UNPATCHED:
- print('rpm.RPMFILE_UNPATCHED')
-
- if fflags & rpm.RPMFILE_PUBKEY:
- print('rpm.RPMFILE_PUBKEY')
-
-def rpm_verify_file(fileinfo, rpmlinktos, omitmask):
- """
- Verify all the files in a package.
-
- Returns a list of error flags, the file type and file name. The list
- entries are strings that are the same as the labels for the bitwise
- flags used in the C code.
-
- """
- (fname, fsize, fmode, fmtime, fflags, frdev, finode, fnlink, fstate, \
- vflags, fuser, fgroup, fmd5) = fileinfo
-
- # 1. rpmtsRootDir stuff. What does it do and where to I get it from?
-
- file_results = []
- flags = vflags
-
- # Check to see if the file was installed - if not pretend all is ok.
- # This is what the rpm C code does!
- if fstate != rpm.RPMFILE_STATE_NORMAL:
- return file_results
-
- # Get the installed files stats
- try:
- lstat = os.lstat(fname)
- except OSError:
- if not (fflags & (rpm.RPMFILE_MISSINGOK|rpm.RPMFILE_GHOST)):
- file_results.append('RPMVERIFY_LSTATFAIL')
- #file_results.append(fname)
- return file_results
-
- # 5. Contexts? SELinux stuff?
-
- # Setup what checks to do. This is straight out of the C code.
- if stat.S_ISDIR(lstat.st_mode):
- flags &= DIR_FLAGS
- elif stat.S_ISLNK(lstat.st_mode):
- flags &= LINK_FLAGS
- elif stat.S_ISFIFO(lstat.st_mode):
- flags &= FIFO_FLAGS
- elif stat.S_ISCHR(lstat.st_mode):
- flags &= CHR_FLAGS
- elif stat.S_ISBLK(lstat.st_mode):
- flags &= BLK_FLAGS
- else:
- flags &= REG_FLAGS
-
- if (fflags & rpm.RPMFILE_GHOST):
- flags &= GHOST_FLAGS
-
- flags &= ~(omitmask | RPMVERIFY_FAILURES)
-
- # 8. SELinux stuff.
-
- prelink_size = 0
- if flags & RPMVERIFY_MD5:
- prelink_md5, prelink_size = prelink_md5_check(fname)
- if prelink_md5 == False:
- file_results.append('RPMVERIFY_MD5')
- file_results.append('RPMVERIFY_READFAIL')
- elif prelink_md5 != fmd5:
- file_results.append('RPMVERIFY_MD5')
-
- if flags & RPMVERIFY_LINKTO:
- linkto = os.readlink(fname)
- if not linkto:
- file_results.append('RPMVERIFY_READLINKFAIL')
- file_results.append('RPMVERIFY_LINKTO')
- else:
- if len(rpmlinktos) == 0 or linkto != rpmlinktos:
- file_results.append('RPMVERIFY_LINKTO')
-
- if flags & RPMVERIFY_FILESIZE:
- if not (flags & RPMVERIFY_MD5): # prelink check hasn't been done.
- prelink_size = prelink_size_check(fname)
- if (prelink_size != 0): # This is a prelinked file.
- if (prelink_size != fsize):
- file_results.append('RPMVERIFY_FILESIZE')
- elif lstat.st_size != fsize: # It wasn't a prelinked file.
- file_results.append('RPMVERIFY_FILESIZE')
-
- if flags & RPMVERIFY_MODE:
- metamode = fmode
- filemode = lstat.st_mode
-
- # Comparing the type of %ghost files is meaningless, but perms are ok.
- if fflags & rpm.RPMFILE_GHOST:
- metamode &= ~0xf000
- filemode &= ~0xf000
-
- if (stat.S_IFMT(metamode) != stat.S_IFMT(filemode)) or \
- (stat.S_IMODE(metamode) != stat.S_IMODE(filemode)):
- file_results.append('RPMVERIFY_MODE')
-
- if flags & RPMVERIFY_RDEV:
- if (stat.S_ISCHR(fmode) != stat.S_ISCHR(lstat.st_mode) or
- stat.S_ISBLK(fmode) != stat.S_ISBLK(lstat.st_mode)):
- file_results.append('RPMVERIFY_RDEV')
- elif (s_isdev(fmode) & s_isdev(lstat.st_mode)):
- st_rdev = lstat.st_rdev
- if frdev != st_rdev:
- file_results.append('RPMVERIFY_RDEV')
-
- if flags & RPMVERIFY_MTIME:
- if lstat.st_mtime != fmtime:
- file_results.append('RPMVERIFY_MTIME')
-
- if flags & RPMVERIFY_USER:
- try:
- user = pwd.getpwuid(lstat.st_uid)[0]
- except KeyError:
- user = None
- if not user or not fuser or (user != fuser):
- file_results.append('RPMVERIFY_USER')
-
- if flags & RPMVERIFY_GROUP:
- try:
- group = grp.getgrgid(lstat.st_gid)[0]
- except KeyError:
- group = None
- if not group or not fgroup or (group != fgroup):
- file_results.append('RPMVERIFY_GROUP')
-
- return file_results
-
-def rpm_verify_dependencies(header):
- """
- Check package dependencies. Header is an rpm.hdr.
-
- Don't like opening another ts to do this, but
- it was the only way I could find of clearing the ts
- out.
-
- Have asked on the rpm-maint list on how to do
- this the right way (28 Feb 2007).
-
- ts.check() returns:
-
- ((name, version, release), (reqname, reqversion), \
- flags, suggest, sense)
-
- """
- _ts1 = rpmtransactionset()
- _ts1.addInstall(header, 'Dep Check', 'i')
- dep_errors = _ts1.check()
- _ts1.closeDB()
- return dep_errors
-
-def rpm_verify_package(vp_ts, header, verify_options):
- """
- Verify a single package specified by header. Header is an rpm.hdr.
-
- If errors are found it returns a dictionary of errors.
-
- """
- # Set some transaction level flags.
- vsflags = 0
- if 'nodigest' in verify_options:
- vsflags |= rpm._RPMVSF_NODIGESTS
- if 'nosignature' in verify_options:
- vsflags |= rpm._RPMVSF_NOSIGNATURES
- ovsflags = vp_ts.setVSFlags(vsflags)
-
- # Map from the Python options to the rpm bitwise flags.
- omitmask = 0
-
- if 'nolinkto' in verify_options:
- omitmask |= VERIFY_LINKTO
- if 'nomd5' in verify_options:
- omitmask |= VERIFY_MD5
- if 'nosize' in verify_options:
- omitmask |= VERIFY_SIZE
- if 'nouser' in verify_options:
- omitmask |= VERIFY_USER
- if 'nogroup' in verify_options:
- omitmask |= VERIFY_GROUP
- if 'nomtime' in verify_options:
- omitmask |= VERIFY_MTIME
- if 'nomode' in verify_options:
- omitmask |= VERIFY_MODE
- if 'nordev' in verify_options:
- omitmask |= VERIFY_RDEV
-
- omitmask = ((~omitmask & VERIFY_ATTRS) ^ VERIFY_ATTRS)
- #print 'omitmask =', omitmask
-
- package_results = {}
-
- # Check Signatures and Digests.
- # No idea what this might return. Need to break something to see.
- # Setting the vsflags above determines what gets checked in the header.
- hdr_stat = vp_ts.hdrCheck(header.unload())
- if hdr_stat:
- package_results['hdr'] = hdr_stat
-
- # Check Package Depencies.
- if 'nodeps' not in verify_options:
- dep_stat = rpm_verify_dependencies(header)
- if dep_stat:
- package_results['deps'] = dep_stat
-
- # Check all the package files.
- if 'nofiles' not in verify_options:
- vp_fi = header.fiFromHeader()
- for fileinfo in vp_fi:
- # Do not bother doing anything with ghost files.
- # This is what RPM does.
- if fileinfo[4] & rpm.RPMFILE_GHOST:
- continue
-
- # This is only needed because of an inconsistency in the
- # rpm.fi interface.
- linktos = vp_fi.FLink()
-
- file_stat = rpm_verify_file(fileinfo, linktos, omitmask)
-
- #if len(file_stat) > 0 or options.verbose:
- if len(file_stat) > 0:
- fflags = fileinfo[4]
- if fflags & rpm.RPMFILE_CONFIG:
- file_stat.append('c')
- elif fflags & rpm.RPMFILE_DOC:
- file_stat.append('d')
- elif fflags & rpm.RPMFILE_GHOST:
- file_stat.append('g')
- elif fflags & rpm.RPMFILE_LICENSE:
- file_stat.append('l')
- elif fflags & rpm.RPMFILE_PUBKEY:
- file_stat.append('P')
- elif fflags & rpm.RPMFILE_README:
- file_stat.append('r')
- else:
- file_stat.append(' ')
-
- file_stat.append(fileinfo[0]) # The filename.
- package_results.setdefault('files', []).append(file_stat)
-
- # Run the verify script if there is one.
- # Do we want this?
- #if 'noscripts' not in verify_options:
- # script_stat = rpmVerifyscript()
- # if script_stat:
- # package_results['script'] = script_stat
-
- # If there have been any errors, add the package nevra to the result.
- if len(package_results) > 0:
- package_results.setdefault('nevra', (header[rpm.RPMTAG_NAME], \
- header[rpm.RPMTAG_EPOCH], \
- header[rpm.RPMTAG_VERSION], \
- header[rpm.RPMTAG_RELEASE], \
- header[rpm.RPMTAG_ARCH]))
- else:
- package_results = None
-
- # Put things back the way we found them.
- vsflags = vp_ts.setVSFlags(ovsflags)
-
- return package_results
-
-def rpm_verify(verify_ts, verify_pkgspec, verify_options=[]):
- """
- Requires rpmtransactionset() to be run first to get a ts.
-
- pkgspec is a dict specifying the package
- e.g.:
- For a single package
- { name='foo', epoch='20', version='1', release='1', arch='x86_64'}
-
- For all packages
- {}
-
- Or any combination of keywords to select one or more packages to verify.
-
- options is a list of 'rpm --verify' options. Default is to check everything.
- e.g.:
- [ 'nodeps', 'nodigest', 'nofiles', 'noscripts', 'nosignature',
- 'nolinkto' 'nomd5', 'nosize', 'nouser', 'nogroup', 'nomtime',
- 'nomode', 'nordev' ]
-
- Returns a list. One list entry per package. Each list entry is a
- dictionary. Dict keys are 'files', 'deps', 'nevra' and 'hdr'.
- Entries only get added for the failures. If nothing failed, None is
- returned.
-
- Its all a bit messy and probably needs reviewing.
-
- [ { 'hdr': [???],
- 'deps: [((name, version, release), (reqname, reqversion),
- flags, suggest, sense), .... ]
- 'files': [ ['filename1', 'RPMVERIFY_GROUP', 'RPMVERIFY_USER' ],
- ['filename2', 'RPMVERFIY_LSTATFAIL']]
- 'nevra': ['name1', 'epoch1', 'version1', 'release1', 'arch1'] }
- { 'hdr': [???],
- 'deps: [((name, version, release), (reqname, reqversion),
- flags, suggest, sense), .... ]
- 'files': [ ['filename', 'RPMVERIFY_GROUP', 'RPMVERIFY_USER" ],
- ['filename2', 'RPMVERFIY_LSTATFAIL']]
- 'nevra': ['name2', 'epoch2', 'version2', 'release2', 'arch2'] } ]
-
- """
- verify_results = []
- headers = getheadersbykeyword(verify_ts, **verify_pkgspec)
- for header in headers:
- result = rpm_verify_package(verify_ts, header, verify_options)
- if result:
- verify_results.append(result)
-
- return verify_results
-
-def rpmtransactionset():
- """
- A simple wrapper for rpm.TransactionSet() to keep everthiing together.
- Might use it to set some ts level flags later.
-
- """
- ts = rpm.TransactionSet()
- return ts
-
-class Rpmtscallback(object):
- """
- Callback for ts.run(). Used for adding, upgrading and removing packages.
- Starting with all possible reasons codes, but bcfg2 will probably only
- make use of a few of them.
-
- Mostly just printing stuff at the moment to understand how the callback
- is used.
-
- """
- def __init__(self):
- self.fdnos = {}
-
- def callback(self, reason, amount, total, key, client_data):
- """
- Generic rpmts call back.
- """
- if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:
- pass
- #print 'rpm.RPMCALLBACK_INST_OPEN_FILE'
- elif reason == rpm.RPMCALLBACK_INST_CLOSE_FILE:
- pass
- #print 'rpm.RPMCALLBACK_INST_CLOSE_FILE'
- elif reason == rpm.RPMCALLBACK_INST_START:
- pass
- #print 'rpm.RPMCALLBACK_INST_START'
- elif reason == rpm.RPMCALLBACK_TRANS_PROGRESS or \
- reason == rpm.RPMCALLBACK_INST_PROGRESS:
- pass
- #print 'rpm.RPMCALLBACK_TRANS_PROGRESS or \
- # rpm.RPMCALLBACK_INST_PROGRESS'
- elif reason == rpm.RPMCALLBACK_TRANS_START:
- pass
- #print 'rpm.RPMCALLBACK_TRANS_START'
- elif reason == rpm.RPMCALLBACK_TRANS_STOP:
- pass
- #print 'rpm.RPMCALLBACK_TRANS_STOP'
- elif reason == rpm.RPMCALLBACK_REPACKAGE_START:
- pass
- #print 'rpm.RPMCALLBACK_REPACKAGE_START'
- elif reason == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
- pass
- #print 'rpm.RPMCALLBACK_REPACKAGE_PROGRESS'
- elif reason == rpm.RPMCALLBACK_REPACKAGE_STOP:
- pass
- #print 'rpm.RPMCALLBACK_REPACKAGE_STOP'
- elif reason == rpm.RPMCALLBACK_UNINST_PROGRESS:
- pass
- #print 'rpm.RPMCALLBACK_UNINST_PROGRESS'
- elif reason == rpm.RPMCALLBACK_UNINST_START:
- pass
- #print 'rpm.RPMCALLBACK_UNINST_START'
- elif reason == rpm.RPMCALLBACK_UNINST_STOP:
- pass
- #print 'rpm.RPMCALLBACK_UNINST_STOP'
- #print '***Package ', key, ' deleted ***'
- # How do we get at this?
- # RPM.modified += key
- elif reason == rpm.RPMCALLBACK_UNPACK_ERROR:
- pass
- #print 'rpm.RPMCALLBACK_UNPACK_ERROR'
- elif reason == rpm.RPMCALLBACK_CPIO_ERROR:
- pass
- #print 'rpm.RPMCALLBACK_CPIO_ERROR'
- elif reason == rpm.RPMCALLBACK_UNKNOWN:
- pass
- #print 'rpm.RPMCALLBACK_UNKNOWN'
- else:
- print('ERROR - Fell through callBack')
-
- #print reason, amount, total, key, client_data
-
-def rpm_erase(erase_pkgspecs, erase_flags):
- """
- pkgspecs is a list of pkgspec dicts specifying packages
- e.g.:
- For a single package
- { name='foo', epoch='20', version='1', release='1', arch='x86_64'}
-
- """
- erase_ts_flags = 0
- if 'noscripts' in erase_flags:
- erase_ts_flags |= rpm.RPMTRANS_FLAG_NOSCRIPTS
- if 'notriggers' in erase_flags:
- erase_ts_flags |= rpm.RPMTRANS_FLAG_NOTRIGGERS
- if 'repackage' in erase_flags:
- erase_ts_flags |= rpm.RPMTRANS_FLAG_REPACKAGE
-
- erase_ts = rpmtransactionset()
- erase_ts.setFlags(erase_ts_flags)
-
- for pkgspec in erase_pkgspecs:
- idx_list = getindexbykeyword(erase_ts, **pkgspec)
- if len(idx_list) > 1 and not 'allmatches' in erase_flags:
- #pass
- print('ERROR - Multiple package match for erase', pkgspec)
- else:
- for idx in idx_list:
- erase_ts.addErase(idx)
-
- #for te in erase_ts:
- # print "%s %s:%s-%s.%s" % (te.N(), te.E(), te.V(), te.R(), te.A())
-
- erase_problems = []
- if 'nodeps' not in erase_flags:
- erase_problems = erase_ts.check()
-
- if erase_problems == []:
- erase_ts.order()
- erase_callback = Rpmtscallback()
- erase_ts.run(erase_callback.callback, 'Erase')
- #else:
- # print 'ERROR - Dependency failures on package erase'
- # print erase_problems
-
- erase_ts.closeDB()
- del erase_ts
- return erase_problems
-
-def display_verify_file(file_results):
- '''
- Display file results similar to rpm --verify.
- '''
- filename = file_results[-1]
- filetype = file_results[-2]
-
- result_string = ''
-
- if 'RPMVERIFY_LSTATFAIL' in file_results:
- result_string = 'missing '
- else:
- if 'RPMVERIFY_FILESIZE' in file_results:
- result_string = result_string + 'S'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_MODE' in file_results:
- result_string = result_string + 'M'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_MD5' in file_results:
- if 'RPMVERIFY_READFAIL' in file_results:
- result_string = result_string + '?'
- else:
- result_string = result_string + '5'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_RDEV' in file_results:
- result_string = result_string + 'D'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_LINKTO' in file_results:
- if 'RPMVERIFY_READLINKFAIL' in file_results:
- result_string = result_string + '?'
- else:
- result_string = result_string + 'L'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_USER' in file_results:
- result_string = result_string + 'U'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_GROUP' in file_results:
- result_string = result_string + 'G'
- else:
- result_string = result_string + '.'
-
- if 'RPMVERIFY_MTIME' in file_results:
- result_string = result_string + 'T'
- else:
- result_string = result_string + '.'
-
- print(result_string + ' ' + filetype + ' ' + filename)
- sys.stdout.flush()
-
-#===============================================================================
-# Some options and output to assist with development and testing.
-# These are not intended for normal use.
-if __name__ == "__main__":
-
- p = optparse.OptionParser()
-
- p.add_option('--name', action='store', \
- default=None, \
- help='''Package name to verify.
-
- ******************************************
- NOT SPECIFYING A NAME MEANS 'ALL' PACKAGES.
- ******************************************
-
- The specified operation will be carried out on all
- instances of packages that match the package specification
- (name, epoch, version, release, arch).''')
-
- p.add_option('--epoch', action='store', \
- default=None, \
- help='''Package epoch.''')
-
- p.add_option('--version', action='store', \
- default=None, \
- help='''Package version.''')
-
- p.add_option('--release', action='store', \
- default=None, \
- help='''Package release.''')
-
- p.add_option('--arch', action='store', \
- default=None, \
- help='''Package arch.''')
-
- p.add_option('--erase', '-e', action='store_true', \
- default=None, \
- help='''****************************************************
- REMOVE PACKAGES. THERE ARE NO WARNINGS. MULTIPLE
- PACKAGES WILL BE REMOVED IF A FULL PACKAGE SPEC IS NOT
- GIVEN. E.G. IF JUST A NAME IS GIVEN ALL INSTALLED
- INSTANCES OF THAT PACKAGE WILL BE REMOVED PROVIDED
- DEPENDENCY CHECKS PASS. IF JUST AN EPOCH IS GIVEN
- ALL PACKAGE INSTANCES WITH THAT EPOCH WILL BE REMOVED.
- ****************************************************''')
-
- p.add_option('--list', '-l', action='store_true', \
- help='''List package identity info. rpm -qa ish equivalent
- intended for use in RefreshPackages().''')
-
- p.add_option('--verify', action='store_true', \
- help='''Verify Package(s). Output is only produced after all
- packages has been verified. Be patient.''')
-
- p.add_option('--verbose', '-v', action='store_true', \
- help='''Verbose output for --verify option. Output is the
- same as rpm -v --verify.''')
-
- p.add_option('--nodeps', action='store_true', \
- default=False, \
- help='Do not do dependency testing.')
-
- p.add_option('--nodigest', action='store_true', \
- help='Do not check package digests.')
-
- p.add_option('--nofiles', action='store_true', \
- help='Do not do file checks.')
-
- p.add_option('--noscripts', action='store_true', \
- help='Do not run verification scripts.')
-
- p.add_option('--nosignature', action='store_true', \
- help='Do not do package signature verification.')
-
- p.add_option('--nolinkto', action='store_true', \
- help='Do not do symlink tests.')
-
- p.add_option('--nomd5', action='store_true', \
- help='''Do not do MD5 checksums on files. Note that this does
- not work for prelink files yet.''')
-
- p.add_option('--nosize', action='store_true', \
- help='''Do not do file size tests. Note that this does not work
- for prelink files yet.''')
-
- p.add_option('--nouser', action='store_true', \
- help='Do not check file user ownership.')
-
- p.add_option('--nogroup', action='store_true', \
- help='Do not check file group ownership.')
-
- p.add_option('--nomtime', action='store_true', \
- help='Do not check file modification times.')
-
- p.add_option('--nomode', action='store_true', \
- help='Do not check file modes (permissions).')
-
- p.add_option('--nordev', action='store_true', \
- help='Do not check device node.')
-
- p.add_option('--notriggers', action='store_true', \
- help='Do not do not generate triggers on erase.')
-
- p.add_option('--repackage', action='store_true', \
- help='''Do repackage on erase.i Packages are put
- in /var/spool/repackage.''')
-
- p.add_option('--allmatches', action='store_true', \
- help='''Remove all package instances that match the
- pkgspec.
-
- ***************************************************
- NO WARNINGS ARE GIVEN. IF THERE IS NO PACKAGE SPEC
- THAT MEANS ALL PACKAGES!!!!
- ***************************************************''')
-
- options, arguments = p.parse_args()
-
- pkgspec = {}
- rpm_options = []
-
- if options.nodeps:
- rpm_options.append('nodeps')
-
- if options.nodigest:
- rpm_options.append('nodigest')
-
- if options.nofiles:
- rpm_options.append('nofiles')
-
- if options.noscripts:
- rpm_options.append('noscripts')
-
- if options.nosignature:
- rpm_options.append('nosignature')
-
- if options.nolinkto:
- rpm_options.append('nolinkto')
-
- if options.nomd5:
- rpm_options.append('nomd5')
-
- if options.nosize:
- rpm_options.append('nosize')
-
- if options.nouser:
- rpm_options.append('nouser')
-
- if options.nogroup:
- rpm_options.append('nogroup')
-
- if options.nomtime:
- rpm_options.append('nomtime')
-
- if options.nomode:
- rpm_options.append('nomode')
-
- if options.nordev:
- rpm_options.append('nordev')
-
- if options.repackage:
- rpm_options.append('repackage')
-
- if options.allmatches:
- rpm_options.append('allmatches')
-
- main_ts = rpmtransactionset()
-
- cmdline_pkgspec = {}
- if options.name != 'all':
- if options.name:
- cmdline_pkgspec['name'] = str(options.name)
- if options.epoch:
- cmdline_pkgspec['epoch'] = str(options.epoch)
- if options.version:
- cmdline_pkgspec['version'] = str(options.version)
- if options.release:
- cmdline_pkgspec['release'] = str(options.release)
- if options.arch:
- cmdline_pkgspec['arch'] = str(options.arch)
-
- if options.verify:
- results = rpm_verify(main_ts, cmdline_pkgspec, rpm_options)
- for r in results:
- files = r.get('files', '')
- for f in files:
- display_verify_file(f)
-
- elif options.list:
- for p in rpmpackagelist(main_ts):
- print(p)
-
- elif options.erase:
- if options.name:
- rpm_erase([cmdline_pkgspec], rpm_options)
- else:
- print('You must specify the "--name" option')
diff --git a/build/lib/Bcfg2/Client/XML.py b/build/lib/Bcfg2/Client/XML.py
deleted file mode 100644
index 42b1017ac..000000000
--- a/build/lib/Bcfg2/Client/XML.py
+++ /dev/null
@@ -1,37 +0,0 @@
-'''XML lib compatibility layer for the Bcfg2 client'''
-__revision__ = '$Revision$'
-
-# library will use lxml, then builtin xml.etree, then ElementTree
-
-try:
- from lxml.etree import Element, SubElement, XML, tostring
- from lxml.etree import XMLSyntaxError as ParseError
- driver = 'lxml'
-except ImportError:
- # lxml not available
- from xml.parsers.expat import ExpatError as ParseError
- try:
- import xml.etree.ElementTree
- Element = xml.etree.ElementTree.Element
- SubElement = xml.etree.ElementTree.SubElement
- XML = xml.etree.ElementTree.XML
- def tostring(e, encoding=None, xml_declaration=None):
- return xml.etree.ElementTree.tostring(e, encoding=encoding)
- driver = 'etree-py'
- except ImportError:
- try:
- from elementtree.ElementTree import Element, SubElement, XML, tostring
- driver = 'etree'
- import elementtree.ElementTree
- Element = elementtree.ElementTree.Element
- SubElement = elementtree.ElementTree.SubElement
- XML = elementtree.ElementTree.XML
- def tostring(e, encoding=None, xml_declaration=None):
- return elementtree.ElementTree.tostring(e)
-
- except ImportError:
- print("Failed to load lxml, xml.etree and elementtree.ElementTree")
- print("Cannot continue")
- raise SystemExit(1)
-
-len([Element, SubElement, XML, tostring, ParseError])
diff --git a/build/lib/Bcfg2/Client/__init__.py b/build/lib/Bcfg2/Client/__init__.py
deleted file mode 100644
index ea60a4259..000000000
--- a/build/lib/Bcfg2/Client/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""This contains all Bcfg2 Client modules"""
-__revision__ = '$Revision$'
-
-__all__ = ["Frame", "Tools", "XML"]
diff --git a/build/lib/Bcfg2/Component.py b/build/lib/Bcfg2/Component.py
deleted file mode 100644
index 2a3ef20e1..000000000
--- a/build/lib/Bcfg2/Component.py
+++ /dev/null
@@ -1,277 +0,0 @@
-"""Cobalt component base."""
-
-__revision__ = '$Revision$'
-
-__all__ = ["Component", "exposed", "automatic", "run_component"]
-
-import inspect
-import logging
-import os
-import pydoc
-import sys
-import time
-import threading
-import urlparse
-import xmlrpclib
-
-import Bcfg2.Logger
-from Bcfg2.Statistics import Statistics
-from Bcfg2.SSLServer import XMLRPCServer
-
-logger = logging.getLogger()
-
-class NoExposedMethod (Exception):
- """There is no method exposed with the given name."""
-
-def run_component(component_cls, location, daemon, pidfile_name, to_file,
- cfile, argv=None, register=True,
- state_name=False, cls_kwargs={}, extra_getopt='', time_out=10,
- protocol='xmlrpc/ssl', certfile=None, keyfile=None, ca=None):
-
- # default settings
- level = logging.INFO
-
- logging.getLogger().setLevel(level)
- Bcfg2.Logger.setup_logging(component_cls.implementation,
- True,
- True,
- to_file=to_file)
-
- if daemon:
- child_pid = os.fork()
- if child_pid != 0:
- return
-
- os.setsid()
-
- child_pid = os.fork()
- if child_pid != 0:
- os._exit(0)
-
- redirect_file = open("/dev/null", "w+")
- os.dup2(redirect_file.fileno(), sys.__stdin__.fileno())
- os.dup2(redirect_file.fileno(), sys.__stdout__.fileno())
- os.dup2(redirect_file.fileno(), sys.__stderr__.fileno())
-
- os.chdir(os.sep)
-
- pidfile = open(pidfile_name or "/dev/null", "w")
- print >> pidfile, os.getpid()
- pidfile.close()
-
- component = component_cls(cfile=cfile, **cls_kwargs)
- up = urlparse.urlparse(location)
- port = tuple(up[1].split(':'))
- port = (port[0], int(port[1]))
- try:
- server = XMLRPCServer(port, keyfile=keyfile, certfile=certfile,
- register=register, timeout=time_out, ca=ca,
- protocol=protocol)
- except:
- logger.error("Server startup failed")
- os._exit(1)
- server.register_instance(component)
-
- try:
- server.serve_forever()
- finally:
- server.server_close()
- component.shutdown()
-
-def exposed(func):
- """Mark a method to be exposed publically.
-
- Examples:
- class MyComponent (Component):
- @expose
- def my_method (self, param1, param2):
- do_stuff()
-
- class MyComponent (Component):
- def my_method (self, param1, param2):
- do_stuff()
- my_method = expose(my_method)
-
- """
- func.exposed = True
- return func
-
-def automatic(func, period=10):
- """Mark a method to be run periodically."""
- func.automatic = True
- func.automatic_period = period
- func.automatic_ts = -1
- return func
-
-def locking(func):
- """Mark a function as being internally thread safe"""
- func.locking = True
- return func
-
-def readonly(func):
- """Mark a function as read-only -- no data effects in component inst"""
- func.readonly = True
- return func
-
-class Component (object):
- """Base component.
-
- Intended to be served as an instance by Cobalt.Component.XMLRPCServer
- >>> server = Cobalt.Component.XMLRPCServer(location, keyfile)
- >>> component = Cobalt.Component.Component()
- >>> server.serve_instance(component)
-
- Class attributes:
- name -- logical component name (e.g., "queue-manager", "process-manager")
- implementation -- implementation identifier (e.g., "BlueGene/L", "BlueGene/P")
-
- Methods:
- save -- pickle the component to a file
- do_tasks -- perform automatic tasks for the component
-
- """
-
- name = "component"
- implementation = "generic"
-
- def __init__(self, **kwargs):
- """Initialize a new component.
-
- Keyword arguments:
- statefile -- file in which to save state automatically
-
- """
- self.statefile = kwargs.get("statefile", None)
- self.logger = logging.getLogger("%s %s" % (self.implementation, self.name))
- self.lock = threading.Lock()
- self.instance_statistics = Statistics()
-
- def do_tasks(self):
- """Perform automatic tasks for the component.
-
- Automatic tasks are member callables with an attribute
- automatic == True.
-
- """
- for name, func in inspect.getmembers(self, callable):
- if getattr(func, "automatic", False):
- need_to_lock = not getattr(func, 'locking', False)
- if (time.time() - func.automatic_ts) > \
- func.automatic_period:
- if need_to_lock:
- t1 = time.time()
- self.lock.acquire()
- t2 = time.time()
- self.instance_statistics.add_value('component_lock', t2-t1)
- try:
- mt1 = time.time()
- try:
- func()
- except:
- self.logger.error("Automatic method %s failed" \
- % (name), exc_info=1)
- finally:
- mt2 = time.time()
-
- if need_to_lock:
- self.lock.release()
- self.instance_statistics.add_value(name, mt2-mt1)
- func.__dict__['automatic_ts'] = time.time()
-
- def _resolve_exposed_method(self, method_name):
- """Resolve an exposed method.
-
- Arguments:
- method_name -- name of the method to resolve
-
- """
- try:
- func = getattr(self, method_name)
- except AttributeError:
- raise NoExposedMethod(method_name)
- if not getattr(func, "exposed", False):
- raise NoExposedMethod(method_name)
- return func
-
- def _dispatch(self, method, args, dispatch_dict):
- """Custom XML-RPC dispatcher for components.
-
- method -- XML-RPC method name
- args -- tuple of paramaters to method
-
- """
- need_to_lock = True
- if method in dispatch_dict:
- method_func = dispatch_dict[method]
- else:
- try:
- method_func = self._resolve_exposed_method(method)
- except NoExposedMethod:
- self.logger.error("Unknown method %s" % (method))
- raise xmlrpclib.Fault(7, "Unknown method %s" % method)
- except Exception, e:
- if getattr(e, "log", True):
- self.logger.error(e, exc_info=True)
- raise xmlrpclib.Fault(getattr(e, "fault_code", 1), str(e))
-
- if getattr(method_func, 'locking', False):
- need_to_lock = False
- if need_to_lock:
- lock_start = time.time()
- self.lock.acquire()
- lock_done = time.time()
- try:
- method_start = time.time()
- try:
- result = method_func(*args)
- finally:
- method_done = time.time()
- if need_to_lock:
- self.lock.release()
- self.instance_statistics.add_value('component_lock',
- lock_done - lock_start)
- self.instance_statistics.add_value(method, method_done - method_start)
- except xmlrpclib.Fault:
- raise
- except Exception, e:
- if getattr(e, "log", True):
- self.logger.error(e, exc_info=True)
- raise xmlrpclib.Fault(getattr(e, "fault_code", 1), str(e))
- return result
-
- @exposed
- def listMethods(self):
- """Custom XML-RPC introspective method list."""
- return [
- name for name, func in inspect.getmembers(self, callable)
- if getattr(func, "exposed", False)
- ]
-
- @exposed
- def methodHelp(self, method_name):
- """Custom XML-RPC introspective method help.
-
- Arguments:
- method_name -- name of method to get help on
-
- """
- try:
- func = self._resolve_exposed_method(method_name)
- except NoExposedMethod:
- return ""
- return pydoc.getdoc(func)
-
- def get_name(self):
- """The name of the component."""
- return self.name
- get_name = exposed(get_name)
-
- def get_implementation(self):
- """The implementation of the component."""
- return self.implementation
- get_implementation = exposed(get_implementation)
-
- def get_statistics(self, _):
- """Get current statistics about component execution"""
- return self.instance_statistics.display()
- get_statistics = exposed(get_statistics)
diff --git a/build/lib/Bcfg2/Logger.py b/build/lib/Bcfg2/Logger.py
deleted file mode 100644
index e8cdd492d..000000000
--- a/build/lib/Bcfg2/Logger.py
+++ /dev/null
@@ -1,233 +0,0 @@
-"""Bcfg2 logging support"""
-__revision__ = '$Revision$'
-
-import copy
-import fcntl
-import logging
-import logging.handlers
-import math
-import socket
-import struct
-import sys
-import termios
-
-logging.raiseExceptions = 0
-
-def print_attributes(attrib):
- """Add the attributes for an element."""
- return ' '.join(['%s="%s"' % data for data in list(attrib.items())])
-
-def print_text(text):
- """Add text to the output (which will need normalising."""
- charmap = {'<':'&lt;', '>':'&gt;', '&':'&amp;'}
- return ''.join([charmap.get(char, char) for char in text]) + '\n'
-
-def xml_print(element, running_indent=0, indent=4):
- """Add an element and its children to the return string."""
- if (len(element.getchildren()) == 0) and (not element.text):
- ret = (' ' * running_indent)
- ret += '<%s %s/>\n' % (element.tag, print_attributes(element.attrib))
- else:
- child_indent = running_indent + indent
- ret = (' ' * running_indent)
- ret += '<%s%s>\n' % (element.tag, print_attributes(element))
- if element.text:
- ret += (' '* child_indent) + print_text(element.text)
- for child in element.getchildren():
- ret += xml_print(child, child_indent, indent)
- ret += (' ' * running_indent) + '</%s>\n' % (element.tag)
- if element.tail:
- ret += (' ' * child_indent) + print_text(element.tail)
- return ret
-
-class TermiosFormatter(logging.Formatter):
- """The termios formatter displays output in a terminal-sensitive fashion."""
-
- def __init__(self, fmt=None, datefmt=None):
- logging.Formatter.__init__(self, fmt, datefmt)
- if sys.stdout.isatty():
- # now get termios info
- try:
- self.width = struct.unpack('hhhh', fcntl.ioctl(0, termios.TIOCGWINSZ,
- "\000"*8))[1]
- if self.width == 0:
- self.width = 80
- except:
- self.width = 80
- else:
- # output to a pipe
- self.width = 32768
-
- def format(self, record):
- '''format a record for display'''
- returns = []
- line_len = self.width
- if isinstance(record.msg, str):
- for line in record.msg.split('\n'):
- if len(line) <= line_len:
- returns.append(line)
- else:
- inner_lines = int(math.floor(float(len(line)) / line_len))+1
- for i in range(inner_lines):
- returns.append("%s" % (line[i*line_len:(i+1)*line_len]))
- elif isinstance(record.msg, list):
- if not record.msg:
- return ''
- record.msg.sort()
- msgwidth = self.width
- columnWidth = max([len(item) for item in record.msg])
- columns = int(math.floor(float(msgwidth) / (columnWidth+2)))
- lines = int(math.ceil(float(len(record.msg)) / columns))
- for lineNumber in range(lines):
- indices = [idx for idx in [(colNum * lines) + lineNumber
- for colNum in range(columns)] if idx < len(record.msg)]
- format = (len(indices) * (" %%-%ds " % columnWidth))
- returns.append(format % tuple([record.msg[idx] for idx in indices]))
- #elif type(record.msg) == lxml.etree._Element:
- # returns.append(str(xml_print(record.msg)))
- else:
- returns.append(str(record.msg))
- if record.exc_info:
- returns.append(self.formatException(record.exc_info))
- return '\n'.join(returns)
-
-class FragmentingSysLogHandler(logging.handlers.SysLogHandler):
- """
- This handler fragments messages into
- chunks smaller than 250 characters
- """
-
- def __init__(self, procname, path, facility):
- self.procname = procname
- self.unixsocket = False
- logging.handlers.SysLogHandler.__init__(self, path, facility)
-
- def emit(self, record):
- """Chunk and deliver records."""
- record.name = self.procname
- if str(record.msg) > 250:
- msgs = []
- error = record.exc_info
- record.exc_info = None
- msgdata = record.msg
- while msgdata:
- newrec = copy.deepcopy(record)
- newrec.msg = msgdata[:250]
- msgs.append(newrec)
- msgdata = msgdata[250:]
- msgs[0].exc_info = error
- else:
- msgs = [record]
- for newrec in msgs:
- msg = self.log_format_string % (self.encodePriority(self.facility,
- newrec.levelname.lower()), self.format(newrec))
- try:
- self.socket.send(msg)
- except socket.error:
- for i in xrange(10):
- try:
- if isinstance(self.address, tuple):
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self.socket.connect(self.address)
- else:
- self._connect_unixsocket(self.address)
- break
- except socket.error:
- continue
- try:
- self.socket.send("Reconnected to syslog")
- self.socket.send(msg)
- except:
- """
- If we still fail then drop it. Running bcfg2-server as non-root can
- trigger permission denied exceptions.
- """
- pass
-
-def setup_logging(procname, to_console=True, to_syslog=True, syslog_facility='daemon', level=0, to_file=None):
- """Setup logging for Bcfg2 software."""
- if hasattr(logging, 'already_setup'):
- return
- # add the handler to the root logger
- if to_console:
- console = logging.StreamHandler(sys.stdout)
- console.setLevel(logging.DEBUG)
- # tell the handler to use this format
- console.setFormatter(TermiosFormatter())
- logging.root.addHandler(console)
- if to_syslog:
- try:
- try:
- syslog = FragmentingSysLogHandler(procname, '/dev/log', syslog_facility)
- except socket.error:
- syslog = FragmentingSysLogHandler(procname, ('localhost', 514), syslog_facility)
- syslog.setLevel(logging.DEBUG)
- syslog.setFormatter(logging.Formatter('%(name)s[%(process)d]: %(message)s'))
- logging.root.addHandler(syslog)
- except socket.error:
- logging.root.error("failed to activate syslogging")
- except:
- print("Failed to activate syslogging")
- if not to_file == None:
- filelog = logging.FileHandler(to_file)
- filelog.setLevel(logging.DEBUG)
- filelog.setFormatter(logging.Formatter('%(asctime)s %(name)s[%(process)d]: %(message)s'))
- logging.root.addHandler(filelog)
- logging.root.setLevel(level)
- logging.already_setup = True
-
-def trace_process(**kwargs):
- """Literally log every line of python code as it runs.
-
- Keyword arguments:
- log -- file (name) to log to (default stderr)
- scope -- base scope to log to (default Cobalt)
-
- """
-
- file_name = kwargs.get("log", None)
- if file_name is not None:
- log_file = open(file_name, "w")
- else:
- log_file = sys.stderr
-
- scope = kwargs.get("scope", "Cobalt")
-
- def traceit(frame, event, arg):
- if event == "line":
- lineno = frame.f_lineno
- filename = frame.f_globals["__file__"]
- if (filename.endswith(".pyc") or
- filename.endswith(".pyo")):
- filename = filename[:-1]
- name = frame.f_globals["__name__"]
- line = linecache.getline(filename, lineno)
- print >> log_file, "%s:%s: %s" % (name, lineno, line.rstrip())
- return traceit
-
- sys.settrace(traceit)
-
-def log_to_stderr(logger_name, level=logging.INFO):
- """Set up console logging."""
- try:
- logger = logging.getLogger(logger_name)
- except:
- # assume logger_name is already a logger
- logger = logger_name
- handler = logging.StreamHandler() # sys.stderr is the default stream
- handler.setLevel(level)
- handler.setFormatter(TermiosFormatter()) # investigate this formatter
- logger.addHandler(handler)
-
-def log_to_syslog(logger_name, level=logging.INFO, format='%(name)s[%(process)d]: %(message)s'):
- """Set up syslog logging."""
- try:
- logger = logging.getLogger(logger_name)
- except:
- # assume logger_name is already a logger
- logger = logger_name
- # anticipate an exception somewhere below
- handler = logging.handlers.SysLogHandler() # investigate FragmentingSysLogHandler
- handler.setLevel(level)
- handler.setFormatter(logging.Formatter(format))
- logger.addHandler(handler)
diff --git a/build/lib/Bcfg2/Options.py b/build/lib/Bcfg2/Options.py
deleted file mode 100644
index 1dcad6427..000000000
--- a/build/lib/Bcfg2/Options.py
+++ /dev/null
@@ -1,334 +0,0 @@
-"""Option parsing library for utilities."""
-__revision__ = '$Revision$'
-
-import ConfigParser
-import getopt
-import os
-import sys
-import Bcfg2.Client.Tools
-
-def bool_cook(x):
- if x:
- return True
- else:
- return False
-
-class OptionFailure(Exception):
- pass
-
-DEFAULT_CONFIG_LOCATION = '/etc/bcfg2.conf' #/etc/bcfg2.conf
-DEFAULT_INSTALL_PREFIX = '/usr' #/usr
-
-class Option(object):
- cfpath = DEFAULT_CONFIG_LOCATION
- __cfp = False
-
- def getCFP(self):
- if not self.__cfp:
- self.__cfp = ConfigParser.ConfigParser()
- self.__cfp.readfp(open(self.cfpath))
- return self.__cfp
- cfp = property(getCFP)
-
- def get_cooked_value(self, value):
- if self.boolean:
- return True
- if self.cook:
- return self.cook(value)
- else:
- return value
-
- def __init__(self, desc, default, cmd=False, odesc=False,
- env=False, cf=False, cook=False, long_arg=False):
- self.desc = desc
- self.default = default
- self.cmd = cmd
- self.long = long_arg
- if not self.long:
- if cmd and (cmd[0] != '-' or len(cmd) != 2):
- raise OptionFailure("Poorly formed command %s" % cmd)
- else:
- if cmd and (not cmd.startswith('--')):
- raise OptionFailure("Poorly formed command %s" % cmd)
- self.odesc = odesc
- self.env = env
- self.cf = cf
- self.boolean = False
- if not odesc and not cook:
- self.boolean = True
- self.cook = cook
-
- def buildHelpMessage(self):
- msg = ''
- if self.cmd:
- if not self.long:
- msg = self.cmd.ljust(3)
- else:
- msg = self.cmd
- if self.odesc:
- if self.long:
- msg = "%-28s" % ("%s=%s" % (self.cmd, self.odesc))
- else:
- msg += '%-25s' % (self.odesc)
- else:
- msg += '%-25s' % ('')
- msg += "%s\n" % self.desc
- return msg
-
- def buildGetopt(self):
- gstr = ''
- if self.long:
- return gstr
- if self.cmd:
- gstr = self.cmd[1]
- if self.odesc:
- gstr += ':'
- return gstr
-
- def buildLongGetopt(self):
- if self.odesc:
- return self.cmd[2:]+'='
- else:
- return self.cmd[2:]
-
- def parse(self, opts, rawopts):
- if self.cmd and opts:
- # processing getopted data
- optinfo = [opt[1] for opt in opts if opt[0] == self.cmd]
- if optinfo:
- if optinfo[0]:
- self.value = self.get_cooked_value(optinfo[0])
- else:
- self.value = True
- return
- if self.cmd and self.cmd in rawopts:
- data = rawopts[rawopts.index(self.cmd) + 1]
- self.value = self.get_cooked_value(data)
- return
- # no command line option found
- if self.env and self.env in os.environ:
- self.value = self.get_cooked_value(os.environ[self.env])
- return
- if self.cf:
- try:
- self.value = self.get_cooked_value(self.cfp.get(*self.cf))
- return
- except:
- pass
- # default value not cooked
- self.value = self.default
-
-class OptionSet(dict):
- def __init__(self, *args):
- dict.__init__(self, *args)
- self.hm = self.buildHelpMessage()
-
- def buildGetopt(self):
- return ''.join([opt.buildGetopt() for opt in list(self.values())])
-
- def buildLongGetopt(self):
- return [opt.buildLongGetopt() for opt in list(self.values()) if opt.long]
-
- def buildHelpMessage(self):
- if hasattr(self, 'hm'):
- return self.hm
- return ' '.join([opt.buildHelpMessage() for opt in list(self.values())])
-
- def helpExit(self, msg='', code=1):
- if msg:
- print(msg)
- print("Usage:\n %s" % self.buildHelpMessage())
- raise SystemExit(code)
-
- def parse(self, argv, do_getopt=True):
- '''Parse options'''
- if do_getopt:
- try:
- opts, args = getopt.getopt(argv, self.buildGetopt(),
- self.buildLongGetopt())
- except getopt.GetoptError, err:
- self.helpExit(err)
- if '-h' in argv:
- self.helpExit('', 0)
- self['args'] = args
- for key in list(self.keys()):
- if key == 'args':
- continue
- option = self[key]
- if do_getopt:
- option.parse(opts, [])
- else:
- option.parse([], argv)
- if hasattr(option, 'value'):
- val = option.value
- self[key] = val
-
-list_split = lambda x:x.replace(' ','').split(',')
-flist_split = lambda x:list_split(x.replace(':', '').lower())
-
-def colon_split(c_string):
- if c_string:
- return c_string.split(':')
- return []
-
-#General options
-CFILE = Option('Specify configuration file', DEFAULT_CONFIG_LOCATION, cmd='-C',
- odesc='<conffile>')
-LOCKFILE = Option('Specify lockfile',
- "/var/lock/bcfg2.run",
- cf=('components', 'lockfile'),
- odesc='<Path to lockfile>')
-HELP = Option('Print this usage message', False, cmd='-h')
-DEBUG = Option("Enable debugging output", False, cmd='-d')
-VERBOSE = Option("Enable verbose output", False, cmd='-v')
-DAEMON = Option("Daemonize process, storing pid", False,
- cmd='-D', odesc="<pidfile>")
-INSTALL_PREFIX = Option('Installation location', cf=('server', 'prefix'),
- default=DEFAULT_INSTALL_PREFIX, odesc='</path>')
-SENDMAIL_PATH = Option('Path to sendmail', cf=('reports', 'sendmailpath'),
- default='/usr/lib/sendmail')
-INTERACTIVE = Option('prompt the user for each change', default=False,
- cmd='-I', )
-ENCODING = Option('Encoding of cfg files', default=sys.getdefaultencoding(),
- cmd='-E', odesc='<encoding>',
- cf=('components', 'encoding'))
-PARANOID_PATH = Option('Specify path for paranoid file backups',
- default='/var/cache/bcfg2', cf=('paranoid', 'path'),
- odesc='<paranoid backup path>')
-PARANOID_MAX_COPIES = Option('Specify the number of paranoid copies you want',
- default=1, cf=('paranoid', 'max_copies'),
- odesc='<max paranoid copies>')
-OMIT_LOCK_CHECK = Option('Omit lock check', default=False, cmd='-O')
-CORE_PROFILE = Option('profile',
- default=False, cmd='-p', )
-
-#Metadata options
-MDATA_OWNER = Option('Default Path owner',
- default='root', cf=('mdata', 'owner'),
- odesc='owner permissions')
-MDATA_GROUP = Option('Default Path group',
- default='root', cf=('mdata', 'group'),
- odesc='group permissions')
-MDATA_IMPORTANT = Option('Default Path priority (importance)',
- default='False', cf=('mdata', 'important'),
- odesc='Important entries are installed first')
-MDATA_PERMS = Option('Default Path permissions',
- '644', cf=('mdata', 'perms'),
- odesc='octal permissions')
-MDATA_PARANOID = Option('Default Path paranoid setting',
- 'false', cf=('mdata', 'paranoid'),
- odesc='Path paranoid setting')
-
-#Server options
-SERVER_REPOSITORY = Option('Server repository path', '/var/lib/bcfg2',
- cf=('server', 'repository'), cmd='-Q',
- odesc='<repository path>')
-SERVER_PLUGINS = Option('Server plugin list', cf=('server', 'plugins'),
- # default server plugins
- default=[
- 'Base',
- 'Bundler',
- 'Cfg',
- 'Metadata',
- 'Pkgmgr',
- 'Rules',
- 'SSHbase',
- ],
- cook=list_split)
-SERVER_MCONNECT = Option('Server Metadata Connector list', cook=list_split,
- cf=('server', 'connectors'), default=['Probes'], )
-SERVER_FILEMONITOR = Option('Server file monitor', cf=('server', 'filemonitor'),
- default='default', odesc='File monitoring driver')
-SERVER_LOCATION = Option('Server Location', cf=('components', 'bcfg2'),
- default='https://localhost:6789', cmd='-S',
- odesc='https://server:port')
-SERVER_STATIC = Option('Server runs on static port', cf=('components', 'bcfg2'),
- default=False, cook=bool_cook)
-SERVER_KEY = Option('Path to SSL key', cf=('communication', 'key'),
- default=False, cmd='--ssl-key', odesc='<ssl key>',
- long_arg=True)
-SERVER_CERT = Option('Path to SSL certificate', default='/etc/bcfg2.key',
- cf=('communication', 'certificate'), odesc='<ssl cert>')
-SERVER_CA = Option('Path to SSL CA Cert', default=None,
- cf=('communication', 'ca'), odesc='<ca cert>')
-SERVER_PASSWORD = Option('Communication Password', cmd='-x', odesc='<password>',
- cf=('communication', 'password'), default=False)
-SERVER_PROTOCOL = Option('Server Protocol', cf=('communication', 'procotol'),
- default='xmlrpc/ssl')
-#Client options
-CLIENT_KEY = Option('Path to SSL key', cf=('communication', 'key'),
- default=None, cmd="--ssl-key", odesc='<ssl key>',
- long_arg=True)
-CLIENT_CERT = Option('Path to SSL certificate', default=None, cmd="--ssl-cert",
- cf=('communication', 'certificate'), odesc='<ssl cert>',
- long_arg=True)
-CLIENT_CA = Option('Path to SSL CA Cert', default=None, cmd="--ca-cert",
- cf=('communication', 'ca'), odesc='<ca cert>',
- long_arg=True)
-CLIENT_SCNS = Option('list of server commonNames', default=None, cmd="--ssl-cns",
- cf=('communication', 'serverCommonNames'),
- odesc='<commonName1:commonName2>', cook=list_split,
- long_arg=True)
-CLIENT_PROFILE = Option('assert the given profile for the host',
- default=False, cmd='-p', odesc="<profile>")
-CLIENT_RETRIES = Option('the number of times to retry network communication',
- default='3', cmd='-R', cf=('communication', 'retries'),
- odesc="<retry count>")
-CLIENT_DRYRUN = Option('do not actually change the system',
- default=False, cmd='-n', )
-CLIENT_EXTRA_DISPLAY = Option('enable extra entry output',
- default=False, cmd='-e', )
-CLIENT_PARANOID = Option('make automatic backups of config files',
- default=False, cmd='-P', cf=('client', 'paranoid'))
-CLIENT_DRIVERS = Option('Specify tool driver set', cmd='-D',
- cf=('client', 'drivers'),
- odesc="<driver1,driver2>", cook=list_split,
- default=Bcfg2.Client.Tools.default)
-CLIENT_CACHE = Option('store the configuration in a file',
- default=False, cmd='-c', odesc="<cache path>")
-CLIENT_REMOVE = Option('force removal of additional configuration items',
- default=False, cmd='-r', odesc="<entry type|all>")
-CLIENT_BUNDLE = Option('only configure the given bundle(s)', default=[],
- cmd='-b', odesc='<bundle:bundle>', cook=colon_split)
-CLIENT_BUNDLEQUICK = Option('only verify/configure the given bundle(s)', default=False,
- cmd='-Q')
-CLIENT_INDEP = Option('only configure the given bundle(s)', default=False,
- cmd='-z')
-CLIENT_KEVLAR = Option('run in kevlar (bulletproof) mode', default=False,
- cmd='-k', )
-CLIENT_DLIST = Option('run client in server decision list mode', default=False,
- cmd='-l', odesc='<whitelist|blacklist>')
-CLIENT_FILE = Option('configure from a file rather than querying the server',
- default=False, cmd='-f', odesc='<specification path>')
-CLIENT_QUICK = Option('disable some checksum verification', default=False,
- cmd='-q', )
-CLIENT_USER = Option('the user to provide for authentication', default='root',
- cmd='-u', cf=('communication', 'user'), odesc='<user>')
-CLIENT_SERVICE_MODE = Option('Set client service mode', default='default',
- cmd='-s', odesc='<default|disabled|build>')
-
-# APT client tool options
-CLIENT_APT_TOOLS_INSTALL_PATH = Option('Apt tools install path',
- cf=('APT', 'install_path'),
- default='/usr')
-CLIENT_APT_TOOLS_VAR_PATH = Option('Apt tools var path',
- cf=('APT', 'var_path'), default='/var')
-CLIENT_SYSTEM_ETC_PATH = Option('System etc path', cf=('APT', 'etc_path'),
- default='/etc')
-
-#Logging options
-LOGGING_FILE_PATH = Option('Set path of file log', default=None,
- cmd='-o', odesc='<path>', cf=('logging', 'path'))
-
-class OptionParser(OptionSet):
- """
- OptionParser bootstraps option parsing,
- getting the value of the config file
- """
- def __init__(self, args):
- self.Bootstrap = OptionSet([('configfile', CFILE)])
- self.Bootstrap.parse(sys.argv[1:], do_getopt=False)
- if self.Bootstrap['configfile'] != Option.cfpath:
- Option.cfpath = self.Bootstrap['configfile']
- Option.__cfp = False
- OptionSet.__init__(self, args)
diff --git a/build/lib/Bcfg2/Proxy.py b/build/lib/Bcfg2/Proxy.py
deleted file mode 100644
index 275405faf..000000000
--- a/build/lib/Bcfg2/Proxy.py
+++ /dev/null
@@ -1,316 +0,0 @@
-"""RPC client access to cobalt components.
-
-Classes:
-ComponentProxy -- an RPC client proxy to Cobalt components
-
-Functions:
-load_config -- read configuration files
-
-"""
-
-__revision__ = '$Revision: $'
-
-
-from xmlrpclib import _Method
-
-import httplib
-import logging
-import re
-import socket
-
-# The ssl module is provided by either Python 2.6 or a separate ssl
-# package that works on older versions of Python (see
-# http://pypi.python.org/pypi/ssl). If neither can be found, look for
-# M2Crypto instead.
-try:
- import ssl
- SSL_LIB = 'py26_ssl'
-except ImportError, e:
- from M2Crypto import SSL
- import M2Crypto.SSL.Checker
- SSL_LIB = 'm2crypto'
-
-
-import string
-import sys
-import time
-import urlparse
-import xmlrpclib
-
-version = sys.version_info[:2]
-has_py23 = map(int, version) >= [2, 3]
-has_py26 = map(int, version) >= [2, 6]
-
-__all__ = ["ComponentProxy", "RetryMethod", "SSLHTTPConnection", "XMLRPCTransport"]
-
-class CertificateError(Exception):
- def __init__(self, commonName):
- self.commonName = commonName
-
-class RetryMethod(_Method):
- """Method with error handling and retries built in."""
- log = logging.getLogger('xmlrpc')
- max_retries = 4
- def __call__(self, *args):
- for retry in range(self.max_retries):
- try:
- return _Method.__call__(self, *args)
- except xmlrpclib.ProtocolError, err:
- self.log.error("Server failure: Protocol Error: %s %s" % \
- (err.errcode, err.errmsg))
- raise xmlrpclib.Fault(20, "Server Failure")
- except xmlrpclib.Fault:
- raise
- except socket.error, err:
- if hasattr(err, 'errno') and err.errno == 336265218:
- self.log.error("SSL Key error")
- break
- if retry == 3:
- self.log.error("Server failure: %s" % err)
- raise xmlrpclib.Fault(20, err)
- except CertificateError, ce:
- self.log.error("Got unallowed commonName %s from server" \
- % ce.commonName)
- break
- except KeyError:
- self.log.error("Server disallowed connection")
- break
- except:
- self.log.error("Unknown failure", exc_info=1)
- break
- time.sleep(0.5)
- raise xmlrpclib.Fault(20, "Server Failure")
-
-# sorry jon
-xmlrpclib._Method = RetryMethod
-
-class SSLHTTPConnection(httplib.HTTPConnection):
- """Extension of HTTPConnection that implements SSL and related behaviors."""
-
- logger = logging.getLogger('Bcfg2.Proxy.SSLHTTPConnection')
-
- def __init__(self, host, port=None, strict=None, timeout=90, key=None,
- cert=None, ca=None, scns=None, protocol='xmlrpc/ssl'):
- """Initializes the `httplib.HTTPConnection` object and stores security
- parameters
-
- Parameters
- ----------
- host : string
- Name of host to contact
- port : int, optional
- Port on which to contact the host. If none is specified,
- the default port of 80 will be used unless the `host`
- string has a port embedded in the form host:port.
- strict : Boolean, optional
- Passed to the `httplib.HTTPConnection` constructor and if
- True, causes the `BadStatusLine` exception to be raised if
- the status line cannot be parsed as a valid HTTP 1.0 or
- 1.1 status.
- timeout : int, optional
- Causes blocking operations to timeout after `timeout`
- seconds.
- key : string, optional
- The file system path to the local endpoint's SSL key. May
- specify the same file as `cert` if using a file that
- contains both. See
- http://docs.python.org/library/ssl.html#ssl-certificates
- for details. Required if using xmlrpc/ssl with client
- certificate authentication.
- cert : string, optional
- The file system path to the local endpoint's SSL
- certificate. May specify the same file as `cert` if using
- a file that contains both. See
- http://docs.python.org/library/ssl.html#ssl-certificates
- for details. Required if using xmlrpc/ssl with client
- certificate authentication.
- ca : string, optional
- The file system path to a set of concatenated certificate
- authority certs, which are used to validate certificates
- passed from the other end of the connection.
- scns : array-like, optional
- List of acceptable server commonNames. The peer cert's
- common name must appear in this list, otherwise the
- connect() call will throw a `CertificateError`.
- protocol : {'xmlrpc/ssl', 'xmlrpc/tlsv1'}, optional
- Communication protocol to use.
-
- """
- if not has_py26:
- httplib.HTTPConnection.__init__(self, host, port, strict)
- else:
- httplib.HTTPConnection.__init__(self, host, port, strict, timeout)
- self.key = key
- self.cert = cert
- self.ca = ca
- self.scns = scns
- self.protocol = protocol
- self.timeout = timeout
-
- def connect(self):
- """Initiates a connection using previously set attributes."""
- if SSL_LIB == 'py26_ssl':
- self._connect_py26ssl()
- elif SSL_LIB == 'm2crypto':
- self._connect_m2crypto()
- else:
- raise Exception, "No SSL module support"
-
-
- def _connect_py26ssl(self):
- """Initiates a connection using the ssl module."""
- rawsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- if self.protocol == 'xmlrpc/ssl':
- ssl_protocol_ver = ssl.PROTOCOL_SSLv23
- elif self.protocol == 'xmlrpc/tlsv1':
- ssl_protocol_ver = ssl.PROTOCOL_TLSv1
- else:
- self.logger.error("Unknown protocol %s" % (self.protocol))
- raise Exception, "unknown protocol %s" % self.protocol
- if self.ca:
- other_side_required = ssl.CERT_REQUIRED
- else:
- other_side_required = ssl.CERT_NONE
- self.logger.warning("No ca is specified. Cannot authenticate the server with SSL.")
- if self.cert and not self.key:
- self.logger.warning("SSL cert specfied, but key. Cannot authenticate this client with SSL.")
- self.cert = None
- if self.key and not self.cert:
- self.logger.warning("SSL key specfied, but no cert. Cannot authenticate this client with SSL.")
- self.key = None
-
- if has_py23:
- rawsock.settimeout(self.timeout)
- self.sock = ssl.SSLSocket(rawsock, cert_reqs=other_side_required,
- ca_certs=self.ca, suppress_ragged_eofs=True,
- keyfile=self.key, certfile=self.cert,
- ssl_version=ssl_protocol_ver)
- self.sock.connect((self.host, self.port))
- peer_cert = self.sock.getpeercert()
- if peer_cert and self.scns:
- scn = [x[0][1] for x in peer_cert['subject'] if x[0][0] == 'commonName'][0]
- if scn not in self.scns:
- raise CertificateError, scn
- self.sock.closeSocket = True
-
- def _connect_m2crypto(self):
- """Initiates a connection using the M2Crypto module."""
-
- if self.protocol == 'xmlrpc/ssl':
- ctx = SSL.Context('sslv23')
- elif self.protocol == 'xmlrpc/tlsv1':
- ctx = SSL.Context('tlsv1')
- else:
- self.logger.error("Unknown protocol %s" % (self.protocol))
- raise Exception, "unknown protocol %s" % self.protocol
-
- if self.ca:
- # Use the certificate authority to validate the cert
- # presented by the server
- ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9)
- if ctx.load_verify_locations(self.ca) != 1:
- raise Exception('No CA certs')
- else:
- self.logger.warning("No ca is specified. Cannot authenticate the server with SSL.")
-
- if self.cert and self.key:
- # A cert/key is defined, use them to support client
- # authentication to the server
- ctx.load_cert(self.cert, self.key)
- elif self.cert:
- self.logger.warning("SSL cert specfied, but key. Cannot authenticate this client with SSL.")
- elif self.key:
- self.logger.warning("SSL key specfied, but no cert. Cannot authenticate this client with SSL.")
-
- self.sock = SSL.Connection(ctx)
- if re.match('\\d+\\.\\d+\\.\\d+\\.\\d+', self.host):
- # host is ip address
- try:
- hostname = socket.gethostbyaddr(self.host)[0]
- except:
- # fall back to ip address
- hostname = self.host
- else:
- hostname = self.host
- try:
- self.sock.connect((hostname, self.port))
- # automatically checks cert matches host
- except M2Crypto.SSL.Checker.WrongHost, wr:
- raise CertificateError, wr
-
-
-class XMLRPCTransport(xmlrpclib.Transport):
- def __init__(self, key=None, cert=None, ca=None, scns=None, use_datetime=0, timeout=90):
- if hasattr(xmlrpclib.Transport, '__init__'):
- xmlrpclib.Transport.__init__(self, use_datetime)
- self.key = key
- self.cert = cert
- self.ca = ca
- self.scns = scns
- self.timeout = timeout
-
- def make_connection(self, host):
- host = self.get_host_info(host)[0]
- http = SSLHTTPConnection(host, key=self.key, cert=self.cert, ca=self.ca,
- scns=self.scns, timeout=self.timeout)
- https = httplib.HTTP()
- https._setup(http)
- return https
-
- def request(self, host, handler, request_body, verbose=0):
- """Send request to server and return response."""
- h = self.make_connection(host)
- self.send_request(h, handler, request_body)
- self.send_host(h, host)
- self.send_user_agent(h)
- self.send_content(h, request_body)
-
- errcode, errmsg, headers = h.getreply()
-
- if errcode != 200:
- raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
-
- self.verbose = verbose
- msglen = int(headers.dict['content-length'])
- return self._get_response(h.getfile(), msglen)
-
- def _get_response(self, fd, length):
- # read response from input file/socket, and parse it
- recvd = 0
-
- p, u = self.getparser()
-
- while recvd < length:
- rlen = min(length - recvd, 1024)
- response = fd.read(rlen)
- recvd += len(response)
- if not response:
- break
- if self.verbose:
- print "body:", repr(response), len(response)
- p.feed(response)
-
- fd.close()
- p.close()
-
- return u.close()
-
-def ComponentProxy(url, user=None, password=None, key=None, cert=None, ca=None,
- allowedServerCNs=None, timeout=90):
-
- """Constructs proxies to components.
-
- Arguments:
- component_name -- name of the component to connect to
-
- Additional arguments are passed to the ServerProxy constructor.
-
- """
-
- if user and password:
- method, path = urlparse.urlparse(url)[:2]
- newurl = "%s://%s:%s@%s" % (method, user, password, path)
- else:
- newurl = url
- ssl_trans = XMLRPCTransport(key, cert, ca, allowedServerCNs, timeout=timeout)
- return xmlrpclib.ServerProxy(newurl, allow_none=True, transport=ssl_trans)
diff --git a/build/lib/Bcfg2/SSLServer.py b/build/lib/Bcfg2/SSLServer.py
deleted file mode 100644
index 7c5b76664..000000000
--- a/build/lib/Bcfg2/SSLServer.py
+++ /dev/null
@@ -1,416 +0,0 @@
-"""Bcfg2 SSL server."""
-
-__revision__ = '$Revision$'
-
-__all__ = [
- "SSLServer", "XMLRPCRequestHandler", "XMLRPCServer",
-]
-
-import os
-import sys
-import xmlrpclib
-import socket
-import SocketServer
-import SimpleXMLRPCServer
-import base64
-import select
-import signal
-import logging
-import ssl
-import threading
-import time
-
-class ForkedChild(Exception):
- pass
-
-class XMLRPCDispatcher (SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
- logger = logging.getLogger("Cobalt.Server.XMLRPCDispatcher")
- def __init__(self, allow_none, encoding):
- try:
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self,
- allow_none,
- encoding)
- except:
- # Python 2.4?
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
-
- self.allow_none = allow_none
- self.encoding = encoding
-
- def _marshaled_dispatch(self, address, data):
- method_func = None
- params, method = xmlrpclib.loads(data)
- try:
- if '.' not in method:
- params = (address, ) + params
- response = self.instance._dispatch(method, params, self.funcs)
- response = (response, )
- raw_response = xmlrpclib.dumps(response, methodresponse=1,
- allow_none=self.allow_none,
- encoding=self.encoding)
- except xmlrpclib.Fault, fault:
- raw_response = xmlrpclib.dumps(fault,
- allow_none=self.allow_none,
- encoding=self.encoding)
- except:
- self.logger.error("Unexpected handler error", exc_info=1)
- # report exception back to server
- raw_response = xmlrpclib.dumps(
- xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)),
- allow_none=self.allow_none, encoding=self.encoding)
- return raw_response
-
-class SSLServer (SocketServer.TCPServer, object):
-
- """TCP server supporting SSL encryption.
-
- Methods:
- handshake -- perform a SSL/TLS handshake
-
- Properties:
- url -- A url pointing to this server.
-
- """
-
- allow_reuse_address = True
- logger = logging.getLogger("Cobalt.Server.TCPServer")
-
- def __init__(self, server_address, RequestHandlerClass, keyfile=None,
- certfile=None, reqCert=False, ca=None, timeout=None, protocol='xmlrpc/ssl'):
-
- """Initialize the SSL-TCP server.
-
- Arguments:
- server_address -- address to bind to the server
- RequestHandlerClass -- class to handle requests
-
- Keyword arguments:
- keyfile -- private encryption key filename (enables ssl encryption)
- certfile -- certificate file (enables ssl encryption)
- reqCert -- client must present certificate
- timeout -- timeout for non-blocking request handling
-
- """
-
- all_iface_address = ('', server_address[1])
- try:
- SocketServer.TCPServer.__init__(self, all_iface_address,
- RequestHandlerClass)
- except socket.error:
- self.logger.error("Failed to bind to socket")
- raise
-
- self.timeout = timeout
- self.socket.settimeout(timeout)
- self.keyfile = keyfile
- if keyfile != None:
- if keyfile == False or not os.path.exists(keyfile):
- self.logger.error("Keyfile %s does not exist" % keyfile)
- raise Exception, "keyfile doesn't exist"
- self.certfile = certfile
- if certfile != None:
- if certfile == False or not os.path.exists(certfile):
- self.logger.error("Certfile %s does not exist" % certfile)
- raise Exception, "certfile doesn't exist"
- self.ca = ca
- if ca != None:
- if ca == False or not os.path.exists(ca):
- self.logger.error("CA %s does not exist" % ca)
- raise Exception, "ca doesn't exist"
- self.reqCert = reqCert
- if ca and certfile:
- self.mode = ssl.CERT_OPTIONAL
- else:
- self.mode = ssl.CERT_NONE
- if protocol == 'xmlrpc/ssl':
- self.ssl_protocol = ssl.PROTOCOL_SSLv23
- elif protocol == 'xmlrpc/tlsv1':
- self.ssl_protocol = ssl.PROTOCOL_TLSv1
- else:
- self.logger.error("Unknown protocol %s" % (protocol))
- raise Exception, "unknown protocol %s" % protocol
-
- def get_request(self):
- (sock, sockinfo) = self.socket.accept()
- sock.settimeout(self.timeout)
- sslsock = ssl.wrap_socket(sock, server_side=True, certfile=self.certfile,
- keyfile=self.keyfile, cert_reqs=self.mode,
- ca_certs=self.ca, ssl_version=self.ssl_protocol)
- return sslsock, sockinfo
-
- def close_request(self, request):
- try:
- request.unwrap()
- except:
- pass
- try:
- request.close()
- except:
- pass
-
- def _get_url(self):
- port = self.socket.getsockname()[1]
- hostname = socket.gethostname()
- protocol = "https"
- return "%s://%s:%i" % (protocol, hostname, port)
- url = property(_get_url)
-
-
-class XMLRPCRequestHandler (SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
-
- """Component XML-RPC request handler.
-
- Adds support for HTTP authentication.
-
- Exceptions:
- CouldNotAuthenticate -- client did not present acceptable authentication information
-
- Methods:
- authenticate -- prompt a check of a client's provided username and password
- handle_one_request -- handle a single rpc (optionally authenticating)
-
- """
- logger = logging.getLogger("Cobalt.Server.XMLRPCRequestHandler")
-
- def authenticate(self):
- try:
- header = self.headers['Authorization']
- except KeyError:
- self.logger.error("No authentication data presented")
- return False
- auth_type, auth_content = header.split()
- auth_content = base64.standard_b64decode(auth_content)
- try:
- username, password = auth_content.split(":")
- except ValueError:
- username = auth_content
- password = ""
- cert = self.request.getpeercert()
- client_address = self.request.getpeername()
- return self.server.instance.authenticate(cert, username,
- password, client_address)
-
- def parse_request(self):
- """Extends parse_request.
-
- Optionally check HTTP authentication when parsing.
-
- """
- if not SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.parse_request(self):
- return False
- try:
- if not self.authenticate():
- self.logger.error("Authentication Failure")
- self.send_error(401, self.responses[401][0])
- return False
- except:
- self.logger.error("Unexpected Authentication Failure", exc_info=1)
- self.send_error(401, self.responses[401][0])
- return False
- return True
-
- ### need to override do_POST here
- def do_POST(self):
- try:
- max_chunk_size = 10*1024*1024
- size_remaining = int(self.headers["content-length"])
- L = []
- while size_remaining:
- try:
- select.select([self.rfile.fileno()], [], [], 3)
- except select.error:
- print "got select timeout"
- raise
- chunk_size = min(size_remaining, max_chunk_size)
- L.append(self.rfile.read(chunk_size))
- size_remaining -= len(L[-1])
- data = ''.join(L)
- response = self.server._marshaled_dispatch(self.client_address, data)
- except:
- try:
- self.send_response(500)
- self.end_headers()
- except:
- (type, msg) = sys.exc_info()[:2]
- self.logger.error("Error sending 500 response (%s): %s" % \
- (type, msg))
- raise
- else:
- # got a valid XML RPC response
- try:
- self.send_response(200)
- self.send_header("Content-type", "text/xml")
- self.send_header("Content-length", str(len(response)))
- self.end_headers()
- failcount = 0
- while True:
- try:
- # If we hit SSL3_WRITE_PENDING here try to resend.
- self.wfile.write(response)
- break
- except ssl.SSLError, e:
- if str(e).find("SSL3_WRITE_PENDING") < 0:
- raise
- self.logger.error("SSL3_WRITE_PENDING")
- failcount += 1
- if failcount < 5:
- continue
- raise
- except:
- (type, msg) = sys.exc_info()[:2]
- if str(type) == 'socket.error' and msg[0] == 32:
- self.logger.warning("Connection dropped from %s" % self.client_address[0])
- elif str(type) == 'socket.error' and msg[0] == 104:
- self.logger.warning("Connection reset by peer: %s" % self.client_address[0])
- else:
- self.logger.error("Error sending response (%s): %s" % \
- (type, msg))
- raise
-
- def finish(self):
- # shut down the connection
- if not self.wfile.closed:
- self.wfile.flush()
- self.wfile.close()
- self.rfile.close()
-
-class XMLRPCServer (SocketServer.ThreadingMixIn, SSLServer,
- XMLRPCDispatcher, object):
-
- """Component XMLRPCServer.
-
- Methods:
- serve_daemon -- serve_forever in a daemonized process
- serve_forever -- handle_one_request until not self.serve
- shutdown -- stop serve_forever (by setting self.serve = False)
- ping -- return all arguments received
-
- RPC methods:
- ping
-
- (additional system.* methods are inherited from base dispatcher)
-
- Properties:
- require_auth -- the request handler is requiring authorization
- credentials -- valid credentials being used for authentication
-
- """
-
- def __init__(self, server_address, RequestHandlerClass=None,
- keyfile=None, certfile=None, ca=None, protocol='xmlrpc/ssl',
- timeout=10,
- logRequests=False,
- register=True, allow_none=True, encoding=None):
-
- """Initialize the XML-RPC server.
-
- Arguments:
- server_address -- address to bind to the server
- RequestHandlerClass -- request handler used by TCP server (optional)
-
- Keyword arguments:
- keyfile -- private encryption key filename
- certfile -- certificate file
- logRequests -- log all requests (default False)
- register -- presence should be reported to service-location (default True)
- allow_none -- allow None values in xml-rpc
- encoding -- encoding to use for xml-rpc (default UTF-8)
-
- """
-
- XMLRPCDispatcher.__init__(self, allow_none, encoding)
-
- if not RequestHandlerClass:
- class RequestHandlerClass (XMLRPCRequestHandler):
- """A subclassed request handler to prevent class-attribute conflicts."""
-
- SSLServer.__init__(self,
- server_address, RequestHandlerClass, ca=ca,
- timeout=timeout, keyfile=keyfile, certfile=certfile, protocol=protocol)
- self.logRequests = logRequests
- self.serve = False
- self.register = register
- self.register_introspection_functions()
- self.register_function(self.ping)
- self.logger.info("service available at %s" % self.url)
- self.timeout = timeout
-
- def _tasks_thread(self):
- try:
- while self.serve:
- try:
- if self.instance and hasattr(self.instance, 'do_tasks'):
- self.instance.do_tasks()
- except:
- self.logger.error("Unexpected task failure", exc_info=1)
- time.sleep(self.timeout)
- except:
- self.logger.error("tasks_thread failed", exc_info=1)
-
- def server_close(self):
- SSLServer.server_close(self)
- self.logger.info("server_close()")
-
- def _get_require_auth(self):
- return getattr(self.RequestHandlerClass, "require_auth", False)
- def _set_require_auth(self, value):
- self.RequestHandlerClass.require_auth = value
- require_auth = property(_get_require_auth, _set_require_auth)
-
- def _get_credentials(self):
- try:
- return self.RequestHandlerClass.credentials
- except AttributeError:
- return dict()
- def _set_credentials(self, value):
- self.RequestHandlerClass.credentials = value
- credentials = property(_get_credentials, _set_credentials)
-
- def register_instance(self, instance, *args, **kwargs):
- XMLRPCDispatcher.register_instance(self, instance, *args, **kwargs)
- try:
- name = instance.name
- except AttributeError:
- name = "unknown"
- if hasattr(instance, 'plugins'):
- for pname, pinst in instance.plugins.iteritems():
- for mname in pinst.__rmi__:
- xmname = "%s.%s" % (pname, mname)
- fn = getattr(pinst, mname)
- self.register_function(fn, name=xmname)
- self.logger.info("serving %s at %s" % (name, self.url))
-
- def serve_forever(self):
- """Serve single requests until (self.serve == False)."""
- self.serve = True
- self.task_thread = threading.Thread(target=self._tasks_thread)
- self.task_thread.start()
- self.logger.info("serve_forever() [start]")
- signal.signal(signal.SIGINT, self._handle_shutdown_signal)
- signal.signal(signal.SIGTERM, self._handle_shutdown_signal)
-
- try:
- while self.serve:
- try:
- self.handle_request()
- except socket.timeout:
- pass
- except select.error:
- pass
- except:
- self.logger.error("Got unexpected error in handle_request",
- exc_info=1)
- finally:
- self.logger.info("serve_forever() [stop]")
-
- def shutdown(self):
- """Signal that automatic service should stop."""
- self.serve = False
-
- def _handle_shutdown_signal(self, *_):
- self.shutdown()
-
- def ping(self, *args):
- """Echo response."""
- self.logger.info("ping(%s)" % (", ".join([repr(arg) for arg in args])))
- return args
diff --git a/build/lib/Bcfg2/Server/Admin/Backup.py b/build/lib/Bcfg2/Server/Admin/Backup.py
deleted file mode 100644
index d6458f97d..000000000
--- a/build/lib/Bcfg2/Server/Admin/Backup.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import glob
-import os
-import sys
-import time
-import tarfile
-import Bcfg2.Server.Admin
-import Bcfg2.Options
-
-class Backup(Bcfg2.Server.Admin.MetadataCore):
- __shorthelp__ = "Make a backup of the Bcfg2 repository."
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin backup")
- #"\n\nbcfg2-admin backup restore")
- __usage__ = ("bcfg2-admin backup")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile,
- self.__usage__)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
- # Get Bcfg2 repo directory
- opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY}
- setup = Bcfg2.Options.OptionParser(opts)
- setup.parse(sys.argv[1:])
- self.datastore = setup['repo']
- timestamp = time.strftime('%Y%m%d%H%M%S')
- format = 'gz'
- mode = 'w:' + format
- filename = timestamp + '.tar' + '.' + format
- out = tarfile.open(self.datastore + '/' + filename, mode=mode)
- out.add(self.datastore, os.path.basename(self.datastore))
- out.close()
- print "Archive %s was stored under %s" % (filename, self.datastore)
diff --git a/build/lib/Bcfg2/Server/Admin/Bundle.py b/build/lib/Bcfg2/Server/Admin/Bundle.py
deleted file mode 100644
index 41cd5727e..000000000
--- a/build/lib/Bcfg2/Server/Admin/Bundle.py
+++ /dev/null
@@ -1,100 +0,0 @@
-import lxml.etree
-import glob
-import sys
-import re
-import Bcfg2.Server.Admin
-import Bcfg2.Options
-from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError
-
-class Bundle(Bcfg2.Server.Admin.MetadataCore):
- __shorthelp__ = "Create or delete bundle entries"
- __longhelp__ = (__shorthelp__ + #"\n\nbcfg2-admin bundle add <bundle> "
- #"\n\nbcfg2-admin bundle del <bundle>"
- "\n\nbcfg2-admin bundle list-xml"
- "\n\nbcfg2-admin bundle list-genshi"
- "\n\nbcfg2-admin bundle show")
- __usage__ = ("bcfg2-admin bundle [options] [add|del] [group]")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile,
- self.__usage__)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
- reg='((?:[a-z][a-z\\.\\d\\-]+)\\.(?:[a-z][a-z\\-]+))(?![\\w\\.])'
-
- #Get all bundles out of the Bundle/ directory
- opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY}
- setup = Bcfg2.Options.OptionParser(opts)
- setup.parse(sys.argv[1:])
- repo = setup['repo']
- xml_list = glob.glob("%s/Bundler/*.xml" % repo)
- genshi_list = glob.glob("%s/Bundler/*.genshi" % repo)
-
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin bundle help for usage.")
-# if args[0] == 'add':
-# try:
-# self.metadata.add_bundle(args[1])
-# except MetadataConsistencyError:
-# print "Error in adding bundle."
-# raise SystemExit(1)
-# elif args[0] in ['delete', 'remove', 'del', 'rm']:
-# try:
-# self.metadata.remove_bundle(args[1])
-# except MetadataConsistencyError:
-# print "Error in deleting bundle."
-# raise SystemExit(1)
- #Lists all available xml bundles
- elif args[0] in ['list-xml', 'ls-xml']:
- bundle_name = []
- for bundle_path in xml_list:
- rg = re.compile(reg,re.IGNORECASE|re.DOTALL)
- bundle_name.append(rg.search(bundle_path).group(1))
- for bundle in bundle_name:
- print bundle.split('.')[0]
- #Lists all available genshi bundles
- elif args[0] in ['list-genshi', 'ls-gen']:
- bundle_name = []
- for bundle_path in genshi_list:
- rg = re.compile(reg,re.IGNORECASE|re.DOTALL)
- bundle_name.append(rg.search(bundle_path).group(1))
- for bundle in bundle_name:
- print bundle.split('.')[0]
- #Shows a list of all available bundles and prints bundle
- #details after the user choose one bundle.
- #FIXME: Add support for detailed output of genshi bundles
- elif args[0] in ['show']:
- bundle_name = []
- bundle_list = xml_list + genshi_list
- for bundle_path in bundle_list:
- rg = re.compile(reg,re.IGNORECASE|re.DOTALL)
- bundle_name.append(rg.search(bundle_path).group(1))
- text = "Available bundles (Number of bundles: %s)" % \
- (len(bundle_list))
- print text
- print "%s" % (len(text) * "-")
- for i in range(len(bundle_list)):
- print "[%i]\t%s" % (i, bundle_name[i])
- print "Enter the line number of a bundle for details:",
- lineno = raw_input()
- if int(lineno) >= int(len(bundle_list)):
- print "No line with this number."
- else:
- if '%s/Bundler/%s' % \
- (repo, bundle_name[int(lineno)]) in genshi_list:
- print "Detailed output for *.genshi bundle is not supported."
- else:
- print 'Details for the "%s" bundle:' % \
- (bundle_name[int(lineno)].split('.')[0])
- tree = lxml.etree.parse(bundle_list[int(lineno)])
- #Prints bundle content
- #print lxml.etree.tostring(tree)
- names = ['Action', 'Package', 'Path', 'Service']
- for name in names:
- for node in tree.findall("//" + name):
- print "%s:\t%s" % (name, node.attrib["name"])
- else:
- print "No command specified"
- raise SystemExit(1)
diff --git a/build/lib/Bcfg2/Server/Admin/Client.py b/build/lib/Bcfg2/Server/Admin/Client.py
deleted file mode 100644
index 0eee22ae4..000000000
--- a/build/lib/Bcfg2/Server/Admin/Client.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import lxml.etree
-import Bcfg2.Server.Admin
-from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError
-
-class Client(Bcfg2.Server.Admin.MetadataCore):
- __shorthelp__ = "Create, delete, or modify client entries"
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin client add <client> "
- "attr1=val1 attr2=val2\n"
- "\n\nbcfg2-admin client update <client> "
- "attr1=val1 attr2=val2\n"
- "\n\nbcfg2-admin client list\n"
- "bcfg2-admin client del <client>")
- __usage__ = ("bcfg2-admin client [options] [add|del|update|list] [attr=val]")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile,
- self.__usage__)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin client help for usage.")
- if args[0] == 'add':
- attr_d = {}
- for i in args[2:]:
- attr, val = i.split('=', 1)
- if attr not in ['profile', 'uuid', 'password',
- 'location', 'secure', 'address']:
- print "Attribute %s unknown" % attr
- raise SystemExit(1)
- attr_d[attr] = val
- try:
- self.metadata.add_client(args[1], attr_d)
- except MetadataConsistencyError:
- print "Error in adding client"
- raise SystemExit(1)
- elif args[0] in ['update', 'up']:
- attr_d = {}
- for i in args[2:]:
- attr, val = i.split('=', 1)
- if attr not in ['profile', 'uuid', 'password',
- 'location', 'secure', 'address']:
- print "Attribute %s unknown" % attr
- raise SystemExit(1)
- attr_d[attr] = val
- try:
- self.metadata.update_client(args[1], attr_d)
- except MetadataConsistencyError:
- print "Error in updating client"
- raise SystemExit(1)
- elif args[0] in ['delete', 'remove', 'del', 'rm']:
- try:
- self.metadata.remove_client(args[1])
- except MetadataConsistencyError:
- print "Error in deleting client"
- raise SystemExit(1)
- elif args[0] in ['list', 'ls']:
- tree = lxml.etree.parse(self.metadata.data + "/clients.xml")
- for node in tree.findall("//Client"):
- print node.attrib["name"]
- else:
- print "No command specified"
- raise SystemExit(1)
diff --git a/build/lib/Bcfg2/Server/Admin/Compare.py b/build/lib/Bcfg2/Server/Admin/Compare.py
deleted file mode 100644
index f97233b0e..000000000
--- a/build/lib/Bcfg2/Server/Admin/Compare.py
+++ /dev/null
@@ -1,137 +0,0 @@
-import lxml.etree, os
-import Bcfg2.Server.Admin
-
-class Compare(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = ("Determine differences between files or "
- "directories of client specification instances")
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin compare <file1> <file2>"
- "\nbcfg2-admin compare -r <dir1> <dir2>")
- __usage__ = ("bcfg2-admin compare <old> <new>\n\n"
- " -r\trecursive")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.Mode.__init__(self, configfile)
- self.important = {'Package':['name', 'version'],
- 'Service':['name', 'status'],
- 'Directory':['name', 'owner', 'group', 'perms'],
- 'SymLink':['name', 'to'],
- 'ConfigFile':['name', 'owner', 'group', 'perms'],
- 'Permissions':['name', 'perms'],
- 'PostInstall':['name']}
-
- def compareStructures(self, new, old):
- for child in new.getchildren():
- equiv = old.xpath('%s[@name="%s"]' %
- (child.tag, child.get('name')))
- if child.tag in self.important:
- print "tag type %s not handled" % (child.tag)
- continue
- if len(equiv) == 0:
- print ("didn't find matching %s %s" %
- (child.tag, child.get('name')))
- continue
- elif len(equiv) >= 1:
- if child.tag == 'ConfigFile':
- if child.text != equiv[0].text:
- print " %s %s contents differ" \
- % (child.tag, child.get('name'))
- continue
- noattrmatch = [field for field in self.important[child.tag] if \
- child.get(field) != equiv[0].get(field)]
- if not noattrmatch:
- new.remove(child)
- old.remove(equiv[0])
- else:
- print " %s %s attributes %s do not match" % \
- (child.tag, child.get('name'), noattrmatch)
- if len(old.getchildren()) == 0 and len(new.getchildren()) == 0:
- return True
- if new.tag == 'Independent':
- name = 'Base'
- else:
- name = new.get('name')
- both = []
- oldl = ["%s %s" % (entry.tag, entry.get('name')) for entry in old]
- newl = ["%s %s" % (entry.tag, entry.get('name')) for entry in new]
- for entry in newl:
- if entry in oldl:
- both.append(entry)
- newl.remove(entry)
- oldl.remove(entry)
- for entry in both:
- print " %s differs (in bundle %s)" % (entry, name)
- for entry in oldl:
- print " %s only in old configuration (in bundle %s)" % (entry, name)
- for entry in newl:
- print " %s only in new configuration (in bundle %s)" % (entry, name)
- return False
-
- def compareSpecifications(self, path1, path2):
- try:
- new = lxml.etree.parse(path1).getroot()
- except IOError:
- print "Failed to read %s" % (path1)
- raise SystemExit(1)
-
- try:
- old = lxml.etree.parse(path2).getroot()
- except IOError:
- print "Failed to read %s" % (path2)
- raise SystemExit(1)
-
- for src in [new, old]:
- for bundle in src.findall('./Bundle'):
- if bundle.get('name')[-4:] == '.xml':
- bundle.set('name', bundle.get('name')[:-4])
-
- rcs = []
- for bundle in new.findall('./Bundle'):
- equiv = old.xpath('Bundle[@name="%s"]' % (bundle.get('name')))
- if len(equiv) == 0:
- print "couldnt find matching bundle for %s" % bundle.get('name')
- continue
- if len(equiv) == 1:
- if self.compareStructures(bundle, equiv[0]):
- new.remove(bundle)
- old.remove(equiv[0])
- rcs.append(True)
- else:
- rcs.append(False)
- else:
- print "Unmatched bundle %s" % (bundle.get('name'))
- rcs.append(False)
- i1 = new.find('./Independent')
- i2 = old.find('./Independent')
- if self.compareStructures(i1, i2):
- new.remove(i1)
- old.remove(i2)
- else:
- rcs.append(False)
- return False not in rcs
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin compare help for usage.")
- if '-r' in args:
- args = list(args)
- args.remove('-r')
- (oldd, newd) = args
- (old, new) = [os.listdir(spot) for spot in args]
- for item in old:
- print "Entry:", item
- state = self.__call__([oldd + '/' + item, newd + '/' + item])
- new.remove(item)
- if state:
- print "Entry:", item, "good"
- else:
- print "Entry:", item, "bad"
- if new:
- print "new has extra entries", new
- return
- try:
- (old, new) = args
- except IndexError:
- print self.__call__.__doc__
- raise SystemExit(1)
diff --git a/build/lib/Bcfg2/Server/Admin/Examples.py b/build/lib/Bcfg2/Server/Admin/Examples.py
deleted file mode 100644
index 3335c5e10..000000000
--- a/build/lib/Bcfg2/Server/Admin/Examples.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import dulwich
-import time
-import tarfile
-from subprocess import Popen
-import Bcfg2.Server.Admin
-from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError
-
-class Examples(Bcfg2.Server.Admin.MetadataCore):
- __shorthelp__ = "Pulls in the data from the Bcfg2 sample repository"
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin examples pull\n"
- "\n\nbcfg2-admin examples update\n"
- "bcfg2-admin examples backup")
- __usage__ = ("bcfg2-admin examples [options] [add|del|update|list] [attr=val]")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile,
- self.__usage__)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
-
-
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self)
- self.core = core
- self.datastore = datastore
-
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin examples help for usage.")
-
- if args[0] == 'pull':
- try:
- # FIXME: Repo URL is hardcoded for now
- Popen(['git', 'clone', 'https://github.com/solj/bcfg2-repo.git', datastore])
- except MetadataConsistencyError:
- print "Error in pulling examples."
- raise SystemExit(1)
-
-#fatal: destination path 'bcfg2-test' already exists and is not an empty directory.
-
- elif args[0] == 'backup':
- try:
- self.metadata.add_group(args[1], attr_d)
- except MetadataConsistencyError:
- print "Error in adding group"
- raise SystemExit(1)
-
-
- elif args[0] == 'backup':
- try:
- self.metadata.add_group(args[1], attr_d)
- except MetadataConsistencyError:
- print "Error in adding group"
- raise SystemExit(1)
-
- else:
- print "No command specified"
- raise SystemExit(1)
-
- def repobackup():
- """Make a backup of the existing files in the Bcfg2 repo directory."""
- if os.path.isdir(datastore):
- print 'Backup in progress...'
- target = time.strftime('%Y%m%d%H%M%S')
-
-
- out = tarfile.open(filename, w.gz)
- else:
- logger.error("%s doesn't exist." % datastore)
- #raise Bcfg2.Server.Plugin.PluginInitError
diff --git a/build/lib/Bcfg2/Server/Admin/Group.py b/build/lib/Bcfg2/Server/Admin/Group.py
deleted file mode 100644
index 6a1c13775..000000000
--- a/build/lib/Bcfg2/Server/Admin/Group.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import lxml.etree
-import Bcfg2.Server.Admin
-from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError
-
-class Group(Bcfg2.Server.Admin.MetadataCore):
- __shorthelp__ = "Create, delete, or modify group entries"
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin group add <group> "
- "attr1=val1 attr2=val2\n"
- "\n\nbcfg2-admin group update <group> "
- "attr1=val1 attr2=val2\n"
- "\n\nbcfg2-admin group list\n"
- "bcfg2-admin group del <group>")
- __usage__ = ("bcfg2-admin group [options] [add|del|update|list] [attr=val]")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile,
- self.__usage__)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin group help for usage.")
- if args[0] == 'add':
- attr_d = {}
- for i in args[2:]:
- attr, val = i.split('=', 1)
- if attr not in ['profile', 'public', 'default',
- 'name', 'auth', 'toolset', 'category',
- 'comment']:
- print "Attribute %s unknown" % attr
- raise SystemExit(1)
- attr_d[attr] = val
- try:
- self.metadata.add_group(args[1], attr_d)
- except MetadataConsistencyError:
- print "Error in adding group"
- raise SystemExit(1)
- elif args[0] in ['update', 'up']:
- attr_d = {}
- for i in args[2:]:
- attr, val = i.split('=', 1)
- if attr not in ['profile', 'public', 'default',
- 'name', 'auth', 'toolset', 'category',
- 'comment']:
- print "Attribute %s unknown" % attr
- raise SystemExit(1)
- attr_d[attr] = val
- try:
- self.metadata.update_group(args[1], attr_d)
- except MetadataConsistencyError:
- print "Error in updating group"
- raise SystemExit(1)
- elif args[0] in ['delete', 'remove', 'del', 'rm']:
- try:
- self.metadata.remove_group(args[1])
- except MetadataConsistencyError:
- print "Error in deleting group"
- raise SystemExit(1)
- elif args[0] in ['list', 'ls']:
- tree = lxml.etree.parse(self.metadata.data + "/groups.xml")
- for node in tree.findall("//Group"):
- print node.attrib["name"]
- else:
- print "No command specified"
- raise SystemExit(1)
diff --git a/build/lib/Bcfg2/Server/Admin/Init.py b/build/lib/Bcfg2/Server/Admin/Init.py
deleted file mode 100644
index c6d1f9e3d..000000000
--- a/build/lib/Bcfg2/Server/Admin/Init.py
+++ /dev/null
@@ -1,280 +0,0 @@
-import getpass
-import os
-import random
-import socket
-import string
-import subprocess
-import Bcfg2.Server.Admin
-import Bcfg2.Server.Plugin
-import Bcfg2.Options
-
-# default config file
-config = '''
-[server]
-repository = %s
-plugins = %s
-
-[statistics]
-sendmailpath = %s
-database_engine = sqlite3
-# 'postgresql', 'mysql', 'mysql_old', 'sqlite3' or 'ado_mssql'.
-database_name =
-# Or path to database file if using sqlite3.
-#<repository>/etc/brpt.sqlite is default path if left empty
-database_user =
-# Not used with sqlite3.
-database_password =
-# Not used with sqlite3.
-database_host =
-# Not used with sqlite3.
-database_port =
-# Set to empty string for default. Not used with sqlite3.
-web_debug = True
-
-[communication]
-protocol = %s
-password = %s
-certificate = %s/%s
-key = %s/%s
-ca = %s/%s
-
-[components]
-bcfg2 = %s
-'''
-
-# Default groups
-groups = '''<Groups version='3.0'>
- <Group profile='true' public='true' default='true' name='basic'>
- <Group name='%s'/>
- </Group>
- <Group name='ubuntu'/>
- <Group name='debian'/>
- <Group name='freebsd'/>
- <Group name='gentoo'/>
- <Group name='redhat'/>
- <Group name='suse'/>
- <Group name='mandrake'/>
- <Group name='solaris'/>
-</Groups>
-'''
-
-# Default contents of clients.xml
-clients = '''<Clients version="3.0">
- <Client profile="basic" pingable="Y" pingtime="0" name="%s"/>
-</Clients>
-'''
-
-# Mapping of operating system names to groups
-os_list = [
- ('Red Hat/Fedora/RHEL/RHAS/Centos', 'redhat'),
- ('SUSE/SLES', 'suse'),
- ('Mandrake', 'mandrake'),
- ('Debian', 'debian'),
- ('Ubuntu', 'ubuntu'),
- ('Gentoo', 'gentoo'),
- ('FreeBSD', 'freebsd')
- ]
-
-# Complete list of plugins
-plugin_list = ['Account', 'Base', 'Bundler', 'Cfg',
- 'Decisions', 'Deps', 'Metadata', 'Packages',
- 'Pkgmgr', 'Probes', 'Properties', 'Rules',
- 'Snapshots', 'SSHbase', 'Statistics', 'Svcmgr',
- 'TCheetah', 'TGenshi']
-
-# Default list of plugins to use
-default_plugins = ['SSHbase', 'Cfg', 'Pkgmgr', 'Rules',
- 'Metadata', 'Base', 'Bundler']
-
-def gen_password(length):
- """Generates a random alphanumeric password with length characters."""
- chars = string.letters + string.digits
- newpasswd = ''
- for i in range(length):
- newpasswd = newpasswd + random.choice(chars)
- return newpasswd
-
-def create_key(hostname, keypath, certpath):
- """Creates a bcfg2.key at the directory specifed by keypath."""
- kcstr = "openssl req -batch -x509 -nodes -subj '/C=US/ST=Illinois/L=Argonne/CN=%s' -days 1000 -newkey rsa:2048 -keyout %s -noout" % (hostname, keypath)
- subprocess.call((kcstr), shell=True)
- ccstr = "openssl req -batch -new -subj '/C=US/ST=Illinois/L=Argonne/CN=%s' -key %s | openssl x509 -req -days 1000 -signkey %s -out %s" % (hostname, keypath, keypath, certpath)
- subprocess.call((ccstr), shell=True)
- os.chmod(keypath, 0600)
-
-def create_conf(confpath, confdata):
- # don't overwrite existing bcfg2.conf file
- if os.path.exists(confpath):
- result = raw_input("\nWarning: %s already exists. "
- "Overwrite? [y/N]: " % confpath)
- if result not in ['Y', 'y']:
- print("Leaving %s unchanged" % confpath)
- return
- try:
- open(confpath, "w").write(confdata)
- os.chmod(confpath, 0600)
- except Exception, e:
- print("Error %s occured while trying to write configuration "
- "file to '%s'\n" %
- (e, confpath))
- raise SystemExit(1)
-
-
-class Init(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = ("Interactively initialize a new repository.")
- __longhelp__ = __shorthelp__ + "\n\nbcfg2-admin init"
- __usage__ = "bcfg2-admin init"
- options = {
- 'configfile': Bcfg2.Options.CFILE,
- 'plugins' : Bcfg2.Options.SERVER_PLUGINS,
- 'proto' : Bcfg2.Options.SERVER_PROTOCOL,
- 'repo' : Bcfg2.Options.SERVER_REPOSITORY,
- 'sendmail' : Bcfg2.Options.SENDMAIL_PATH,
- }
- repopath = ""
- response = ""
- def __init__(self, configfile):
- Bcfg2.Server.Admin.Mode.__init__(self, configfile)
-
- def _set_defaults(self):
- """Set default parameters."""
- self.configfile = self.opts['configfile']
- self.repopath = self.opts['repo']
- self.password = gen_password(8)
- self.server_uri = "https://%s:6789" % socket.getfqdn()
- self.plugins = default_plugins
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
-
- # Parse options
- self.opts = Bcfg2.Options.OptionParser(self.options)
- self.opts.parse(args)
- self._set_defaults()
-
- # Prompt the user for input
- self._prompt_config()
- self._prompt_repopath()
- self._prompt_password()
- self._prompt_hostname()
- self._prompt_server()
- self._prompt_groups()
-
- # Initialize the repository
- self.init_repo()
-
- def _prompt_hostname(self):
- """Ask for the server hostname."""
- data = raw_input("What is the server's hostname [%s]: " % socket.getfqdn())
- if data != '':
- self.shostname = data
- else:
- self.shostname = socket.getfqdn()
-
- def _prompt_config(self):
- """Ask for the configuration file path."""
- newconfig = raw_input("Store bcfg2 configuration in [%s]: " %
- self.configfile)
- if newconfig != '':
- self.configfile = newconfig
-
- def _prompt_repopath(self):
- """Ask for the repository path."""
- while True:
- newrepo = raw_input("Location of bcfg2 repository [%s]: " %
- self.repopath)
- if newrepo != '':
- self.repopath = newrepo
- if os.path.isdir(self.repopath):
- response = raw_input("Directory %s exists. Overwrite? [y/N]:"\
- % self.repopath)
- if response.lower().strip() == 'y':
- break
- else:
- break
-
- def _prompt_password(self):
- """Ask for a password or generate one if none is provided."""
- newpassword = getpass.getpass(
- "Input password used for communication verification "
- "(without echoing; leave blank for a random): ").strip()
- if len(newpassword) != 0:
- self.password = newpassword
-
- def _prompt_server(self):
- """Ask for the server name."""
- newserver = raw_input("Input the server location [%s]: " % self.server_uri)
- if newserver != '':
- self.server_uri = newserver
-
- def _prompt_groups(self):
- """Create the groups.xml file."""
- prompt = '''Input base Operating System for clients:\n'''
- for entry in os_list:
- prompt += "%d: %s\n" % (os_list.index(entry) + 1, entry[0])
- prompt += ': '
- while True:
- try:
- self.os_sel = os_list[int(raw_input(prompt))-1][1]
- break
- except ValueError:
- continue
-
- def _prompt_plugins(self):
- default = raw_input("Use default plugins? (%s) [Y/n]: " % ''.join(default_plugins)).lower()
- if default != 'y' or default != '':
- while True:
- plugins_are_valid = True
- plug_str = raw_input("Specify plugins: ")
- plugins = plug_str.split(',')
- for plugin in plugins:
- plugin = plugin.strip()
- if not plugin in plugin_list:
- plugins_are_valid = False
- print "ERROR: plugin %s not recognized" % plugin
- if plugins_are_valid:
- break
-
- def _init_plugins(self):
- """Initialize each plugin-specific portion of the repository."""
- for plugin in self.plugins:
- if plugin == 'Metadata':
- Bcfg2.Server.Plugins.Metadata.Metadata.init_repo(self.repopath, groups, self.os_sel, clients)
- else:
- try:
- module = __import__("Bcfg2.Server.Plugins.%s" % plugin, '',
- '', ["Bcfg2.Server.Plugins"])
- cls = getattr(module, plugin)
- cls.init_repo(self.repopath)
- except Exception, e:
- print 'Plugin setup for %s failed: %s\n Check that dependencies are installed?' % (plugin, e)
-
- def init_repo(self):
- """Setup a new repo and create the content of the configuration file."""
- keypath = os.path.dirname(os.path.abspath(self.configfile))
- confdata = config % (
- self.repopath,
- ','.join(self.opts['plugins']),
- self.opts['sendmail'],
- self.opts['proto'],
- self.password,
- keypath, 'bcfg2.crt',
- keypath, 'bcfg2.key',
- keypath, 'bcfg2.crt',
- self.server_uri
- )
-
- # Create the configuration file and SSL key
- create_conf(self.configfile, confdata)
- kpath = keypath + '/bcfg2.key'
- cpath = keypath + '/bcfg2.crt'
- create_key(self.shostname, kpath, cpath)
-
- # Create the repository
- path = "%s/%s" % (self.repopath, 'etc')
- try:
- os.makedirs(path)
- self._init_plugins()
- print "Repository created successfuly in %s" % (self.repopath)
- except OSError:
- print("Failed to create %s." % path)
diff --git a/build/lib/Bcfg2/Server/Admin/Minestruct.py b/build/lib/Bcfg2/Server/Admin/Minestruct.py
deleted file mode 100644
index 02edf2b75..000000000
--- a/build/lib/Bcfg2/Server/Admin/Minestruct.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import getopt
-import lxml.etree
-import sys
-
-import Bcfg2.Server.Admin
-
-class Minestruct(Bcfg2.Server.Admin.StructureMode):
- """Pull extra entries out of statistics."""
- __shorthelp__ = "Extract extra entry lists from statistics"
- __longhelp__ = (__shorthelp__ +
- "\n\nbcfg2-admin minestruct [-f filename] "
- "[-g groups] client")
- __usage__ = ("bcfg2-admin minestruct [options] <client>\n\n"
- " %-25s%s\n"
- " %-25s%s\n" %
- ("-f <filename>",
- "build a particular file",
- "-g <groups>",
- "only build config for groups"))
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.StructureMode.__init__(self, configfile,
- self.__usage__)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin minestruct help for usage.")
- try:
- (opts, args) = getopt.getopt(args, 'f:g:h')
- except:
- self.log.error(self.__shorthelp__)
- raise SystemExit(1)
-
- client = args[0]
- output = sys.stdout
- groups = []
-
- for (opt, optarg) in opts:
- if opt == '-f':
- try:
- output = open(optarg, 'w')
- except IOError:
- self.log.error("Failed to open file: %s" % (optarg))
- raise SystemExit(1)
- elif opt == '-g':
- groups = optarg.split(':')
-
- try:
- extra = set()
- for source in self.bcore.pull_sources:
- for item in source.GetExtra(client):
- extra.add(item)
- except:
- self.log.error("Failed to find extra entry info for client %s" %
- client)
- raise SystemExit(1)
- root = lxml.etree.Element("Base")
- self.log.info("Found %d extra entries" % (len(extra)))
- add_point = root
- for g in groups:
- add_point = lxml.etree.SubElement(add_point, "Group", name=g)
- for tag, name in extra:
- self.log.info("%s: %s" % (tag, name))
- lxml.etree.SubElement(add_point, tag, name=name)
-
- tree = lxml.etree.ElementTree(root)
- tree.write(output, pretty_print=True)
diff --git a/build/lib/Bcfg2/Server/Admin/Perf.py b/build/lib/Bcfg2/Server/Admin/Perf.py
deleted file mode 100644
index 6f1cb8dbb..000000000
--- a/build/lib/Bcfg2/Server/Admin/Perf.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import Bcfg2.Options
-import Bcfg2.Proxy
-import Bcfg2.Server.Admin
-
-import sys
-
-class Perf(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = ("Query server for performance data")
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin perf")
- __usage__ = ("bcfg2-admin perf")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.Mode.__init__(self, configfile)
-
- def __call__(self, args):
- output = [('Name', 'Min', 'Max', 'Mean', 'Count')]
- optinfo = {
- 'ca': Bcfg2.Options.CLIENT_CA,
- 'certificate': Bcfg2.Options.CLIENT_CERT,
- 'key': Bcfg2.Options.SERVER_KEY,
- 'password': Bcfg2.Options.SERVER_PASSWORD,
- 'server': Bcfg2.Options.SERVER_LOCATION,
- 'user': Bcfg2.Options.CLIENT_USER,
- }
- setup = Bcfg2.Options.OptionParser(optinfo)
- setup.parse(sys.argv[2:])
- proxy = Bcfg2.Proxy.ComponentProxy(setup['server'],
- setup['user'],
- setup['password'],
- key = setup['key'],
- cert = setup['certificate'],
- ca = setup['ca'])
- data = proxy.get_statistics()
- for key, value in data.iteritems():
- data = tuple(["%.06f" % (item) for item in value[:-1]] + [value[-1]])
- output.append((key, ) + data)
- self.print_table(output)
diff --git a/build/lib/Bcfg2/Server/Admin/Pull.py b/build/lib/Bcfg2/Server/Admin/Pull.py
deleted file mode 100644
index aa732c67f..000000000
--- a/build/lib/Bcfg2/Server/Admin/Pull.py
+++ /dev/null
@@ -1,138 +0,0 @@
-import getopt
-import sys
-import Bcfg2.Server.Admin
-
-class Pull(Bcfg2.Server.Admin.MetadataCore):
- """Pull mode retrieves entries from clients and
- integrates the information into the repository.
- """
- __shorthelp__ = ("Integrate configuration information "
- "from clients into the server repository")
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin pull [-v] [-f][-I] [-s] "
- "<client> <entry type> <entry name>")
- __usage__ = ("bcfg2-admin pull [options] <client> <entry type> "
- "<entry name>\n\n"
- " %-25s%s\n"
- " %-25s%s\n"
- " %-25s%s\n"
- " %-25s%s\n" %
- ("-v",
- "be verbose",
- "-f",
- "force",
- "-I",
- "interactive",
- "-s",
- "stdin"))
- allowed = ['Metadata', 'BB', "DBStats", "Statistics", "Cfg", "SSHbase"]
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile,
- self.__usage__)
- self.log = False
- self.mode = 'interactive'
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- use_stdin = False
- try:
- opts, gargs = getopt.getopt(args, 'vfIs')
- except:
- print self.__shorthelp__
- raise SystemExit(1)
- for opt in opts:
- if opt[0] == '-v':
- self.log = True
- elif opt[0] == '-f':
- self.mode = 'force'
- elif opt[0] == '-I':
- self.mode == 'interactive'
- elif opt[0] == '-s':
- use_stdin = True
-
- if use_stdin:
- for line in sys.stdin:
- try:
- self.PullEntry(*line.split(None, 3))
- except SystemExit:
- print " for %s" % line
- except:
- print "Bad entry: %s" % line.strip()
- elif len(gargs) < 3:
- print self.__longhelp__
- raise SystemExit(1)
- else:
- self.PullEntry(gargs[0], gargs[1], gargs[2])
-
- def BuildNewEntry(self, client, etype, ename):
- """Construct a new full entry for given client/entry from statistics."""
- new_entry = {'type':etype, 'name':ename}
- for plugin in self.bcore.pull_sources:
- try:
- (owner, group, perms, contents) = \
- plugin.GetCurrentEntry(client, etype, ename)
- break
- except Bcfg2.Server.Plugin.PluginExecutionError:
- if plugin == self.bcore.pull_sources[-1]:
- print "Pull Source failure; could not fetch current state"
- raise SystemExit(1)
-
- try:
- data = {'owner':owner, 'group':group, 'perms':perms, 'text':contents}
- except UnboundLocalError:
- print("Unable to build entry. "
- "Do you have a statistics plugin enabled?")
- raise SystemExit(1)
- for k, v in data.iteritems():
- if v:
- new_entry[k] = v
- #print new_entry
- return new_entry
-
- def Choose(self, choices):
- """Determine where to put pull data."""
- if self.mode == 'interactive':
- for choice in choices:
- print "Plugin returned choice:"
- if id(choice) == id(choices[0]):
- print "(current entry)",
- if choice.all:
- print " => global entry"
- elif choice.group:
- print (" => group entry: %s (prio %d)" %
- (choice.group, choice.prio))
- else:
- print " => host entry: %s" % (choice.hostname)
- if raw_input("Use this entry? [yN]: ") in ['y', 'Y']:
- return choice
- return False
- else:
- # mode == 'force'
- if not choices:
- return False
- return choices[0]
-
- def PullEntry(self, client, etype, ename):
- """Make currently recorded client state correct for entry."""
- new_entry = self.BuildNewEntry(client, etype, ename)
-
- meta = self.bcore.build_metadata(client)
- # find appropriate plugin in bcore
- glist = [gen for gen in self.bcore.generators if
- ename in gen.Entries.get(etype, {})]
- if len(glist) != 1:
- self.errExit("Got wrong numbers of matching generators for entry:" \
- + "%s" % ([g.name for g in glist]))
- plugin = glist[0]
- if not isinstance(plugin, Bcfg2.Server.Plugin.PullTarget):
- self.errExit("Configuration upload not supported by plugin %s" \
- % (plugin.name))
- try:
- choices = plugin.AcceptChoices(new_entry, meta)
- specific = self.Choose(choices)
- if specific:
- plugin.AcceptPullData(specific, new_entry, self.log)
- except Bcfg2.Server.Plugin.PluginExecutionError:
- self.errExit("Configuration upload not supported by plugin %s" \
- % (plugin.name))
- # FIXME svn commit if running under svn
diff --git a/build/lib/Bcfg2/Server/Admin/Query.py b/build/lib/Bcfg2/Server/Admin/Query.py
deleted file mode 100644
index b5af9bad2..000000000
--- a/build/lib/Bcfg2/Server/Admin/Query.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import logging
-import Bcfg2.Logger
-import Bcfg2.Server.Admin
-
-class Query(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = "Query clients"
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin query [-n] [-c] "
- "[-f filename] g=group p=profile")
- __usage__ = ("bcfg2-admin query [options] <g=group> <p=profile>\n\n"
- " %-25s%s\n"
- " %-25s%s\n"
- " %-25s%s\n" %
- ("-n",
- "query results delimited with newlines",
- "-c",
- "query results delimited with commas",
- "-f filename",
- "write query to file"))
-
- def __init__(self, cfile):
- logging.root.setLevel(100)
- Bcfg2.Logger.setup_logging(100, to_console=False, to_syslog=False)
- Bcfg2.Server.Admin.Mode.__init__(self, cfile)
- try:
- self.bcore = Bcfg2.Server.Core.Core(self.get_repo_path(),
- ['Metadata', 'Probes'],
- 'foo', False, 'UTF-8')
- except Bcfg2.Server.Core.CoreInitError, msg:
- self.errExit("Core load failed because %s" % msg)
- self.bcore.fam.handle_events_in_interval(1)
- self.meta = self.bcore.metadata
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- clients = self.meta.clients.keys()
- filename_arg = False
- filename = None
- for arg in args:
- if filename_arg == True:
- filename = arg
- filename_arg = False
- continue
- if arg in ['-n', '-c']:
- continue
- if arg in ['-f']:
- filename_arg = True
- continue
- try:
- k, v = arg.split('=')
- except:
- print "Unknown argument %s" % arg
- continue
- if k == 'p':
- nc = self.meta.get_client_names_by_profiles(v.split(','))
- elif k == 'g':
- nc = self.meta.get_client_names_by_groups(v.split(','))
- # add probed groups (if present)
- for conn in self.bcore.connectors:
- if isinstance(conn, Bcfg2.Server.Plugins.Probes.Probes):
- for c, glist in conn.cgroups.items():
- for g in glist:
- if g in v.split(','):
- nc.append(c)
- else:
- print "One of g= or p= must be specified"
- raise SystemExit(1)
- clients = [c for c in clients if c in nc]
- if '-n' in args:
- for client in clients:
- print client
- else:
- print ','.join(clients)
- if '-f' in args:
- f = open(filename, "w")
- for client in clients:
- f.write(client + "\n")
- f.close()
- print "Wrote results to %s" % (filename)
diff --git a/build/lib/Bcfg2/Server/Admin/Reports.py b/build/lib/Bcfg2/Server/Admin/Reports.py
deleted file mode 100644
index a4dd19064..000000000
--- a/build/lib/Bcfg2/Server/Admin/Reports.py
+++ /dev/null
@@ -1,357 +0,0 @@
-'''Admin interface for dynamic reports'''
-import Bcfg2.Logger
-import Bcfg2.Server.Admin
-import ConfigParser
-import datetime
-import os
-import logging
-import pickle
-import platform
-import sys
-import traceback
-from Bcfg2.Server.Reports.importscript import load_stats
-from Bcfg2.Server.Reports.updatefix import update_database
-from Bcfg2.Server.Reports.utils import *
-from lxml.etree import XML, XMLSyntaxError
-
-# FIXME: Remove when server python dep is 2.5 or greater
-if sys.version_info >= (2, 5):
- from hashlib import md5
-else:
- from md5 import md5
-
-# Load django
-import django.core.management
-
-# FIXME - settings file uses a hardcoded path for /etc/bcfg2.conf
-try:
- import Bcfg2.Server.Reports.settings
-except Exception, e:
- sys.stderr.write("Failed to load configuration settings. %s\n" % e)
- sys.exit(1)
-
-project_directory = os.path.dirname(Bcfg2.Server.Reports.settings.__file__)
-project_name = os.path.basename(project_directory)
-sys.path.append(os.path.join(project_directory, '..'))
-project_module = __import__(project_name, '', '', [''])
-sys.path.pop()
-
-# Set DJANGO_SETTINGS_MODULE appropriately.
-os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
-from django.db import connection, transaction
-
-from Bcfg2.Server.Reports.reports.models import Client, Interaction, Entries, \
- Entries_interactions, Performance, \
- Reason, Ping, TYPE_CHOICES, InternalDatabaseVersion
-
-def printStats(fn):
- """
- Print db stats.
-
- Decorator for purging. Prints database statistics after a run.
- """
- def print_stats(*data):
- start_client = Client.objects.count()
- start_i = Interaction.objects.count()
- start_ei = Entries_interactions.objects.count()
- start_perf = Performance.objects.count()
- start_ping = Ping.objects.count()
-
- fn(*data)
-
- print "Clients removed: %s" % (start_client - Client.objects.count())
- print "Interactions removed: %s" % (start_i - Interaction.objects.count())
- print "Interactions->Entries removed: %s" % \
- (start_ei - Entries_interactions.objects.count())
- print "Metrics removed: %s" % (start_perf - Performance.objects.count())
- print "Ping metrics removed: %s" % (start_ping - Ping.objects.count())
-
- return print_stats
-
-class Reports(Bcfg2.Server.Admin.Mode):
- '''Admin interface for dynamic reports'''
- __shorthelp__ = "Manage dynamic reports"
- __longhelp__ = (__shorthelp__)
- __usage__ = ("bcfg2-admin reports [command] [options]\n"
- " -v|--verbose Be verbose\n"
- " -q|--quiet Print only errors\n"
- "\n"
- " Commands:\n"
- " init Initialize the database\n"
- " load_stats Load statistics data\n"
- " -s|--stats Path to statistics.xml file\n"
- " -c|--clients-file Path to clients.xml file\n"
- " -O3 Fast mode. Duplicates data!\n"
- " purge Purge records\n"
- " --client [n] Client to operate on\n"
- " --days [n] Records older then n days\n"
- " --expired Expired clients only\n"
- " scrub Scrub the database for duplicate reasons and orphaned entries\n"
- " update Apply any updates to the reporting database\n"
- "\n")
-
- def __init__(self, cfile):
- Bcfg2.Server.Admin.Mode.__init__(self, cfile)
- self.log.setLevel(logging.INFO)
- self.django_commands = [ 'syncdb', 'sqlall', 'validate' ]
- self.__usage__ = self.__usage__ + " Django commands:\n " + \
- "\n ".join(self.django_commands)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- if len(args) == 0 or args[0] == '-h':
- print(self.__usage__)
- raise SystemExit(0)
-
- verb = 0
-
- if '-v' in args or '--verbose' in args:
- self.log.setLevel(logging.DEBUG)
- verb = 1
- if '-q' in args or '--quiet' in args:
- self.log.setLevel(logging.WARNING)
-
- # FIXME - dry run
-
- if args[0] in self.django_commands:
- self.django_command_proxy(args[0])
- elif args[0] == 'scrub':
- self.scrub()
- elif args[0] == 'init':
- update_database()
- elif args[0] == 'update':
- update_database()
- elif args[0] == 'load_stats':
- quick = '-O3' in args
- stats_file=None
- clients_file=None
- i=1
- while i < len(args):
- if args[i] == '-s' or args[i] == '--stats':
- stats_file = args[i+1]
- if stats_file[0] == '-':
- self.errExit("Invalid statistics file: %s" % stats_file)
- elif args[i] == '-c' or args[i] == '--clients-file':
- clients_file = args[i+1]
- if clients_file[0] == '-':
- self.errExit("Invalid clients file: %s" % clients_file)
- i = i + 1
- self.load_stats(stats_file, clients_file, verb, quick)
- elif args[0] == 'purge':
- expired=False
- client=None
- maxdate=None
- state=None
- i=1
- while i < len(args):
- if args[i] == '-c' or args[i] == '--client':
- if client:
- self.errExit("Only one client per run")
- client = args[i+1]
- print client
- i = i + 1
- elif args[i] == '--days':
- if maxdate:
- self.errExit("Max date specified multiple times")
- try:
- maxdate = datetime.datetime.now() - datetime.timedelta(days=int(args[i+1]))
- except:
- self.log.error("Invalid number of days: %s" % args[i+1])
- raise SystemExit, -1
- i = i + 1
- elif args[i] == '--expired':
- expired=True
- i = i + 1
- if expired:
- if state:
- self.log.error("--state is not valid with --expired")
- raise SystemExit, -1
- self.purge_expired(maxdate)
- else:
- self.purge(client, maxdate, state)
- else:
- print "Unknown command: %s" % args[0]
-
- @transaction.commit_on_success
- def scrub(self):
- ''' Perform a thorough scrub and cleanup of the database '''
-
- # Currently only reasons are a problem
- try:
- start_count = Reason.objects.count()
- except Exception, e:
- self.log.error("Failed to load reason objects: %s" % e)
- return
- dup_reasons = []
-
- cmp_reasons = dict()
- batch_update = []
- for reason in BatchFetch(Reason.objects):
- ''' Loop through each reason and create a key out of the data. \
- This lets us take advantage of a fast hash lookup for \
- comparisons '''
- id = reason.id
- reason.id = None
- key=md5(pickle.dumps(reason)).hexdigest()
- reason.id = id
-
- if key in cmp_reasons:
- self.log.debug("Update interactions from %d to %d" \
- % (reason.id, cmp_reasons[key]))
- dup_reasons.append([reason.id])
- batch_update.append([cmp_reasons[key], reason.id])
- else:
- cmp_reasons[key] = reason.id
- self.log.debug("key %d" % reason.id)
-
- self.log.debug("Done with updates, deleting dupes")
- try:
- cursor = connection.cursor()
- cursor.executemany('update reports_entries_interactions set reason_id=%s where reason_id=%s', batch_update)
- cursor.executemany('delete from reports_reason where id = %s', dup_reasons)
- transaction.set_dirty()
- except Exception, ex:
- self.log.error("Failed to delete reasons: %s" % ex)
- raise
-
- self.log.info("Found %d dupes out of %d" % (len(dup_reasons), start_count))
-
- # Cleanup orphans
- start_count = Reason.objects.count()
- Reason.prune_orphans()
- self.log.info("Pruned %d Reason records" % (start_count - Reason.objects.count()))
-
- start_count = Entries.objects.count()
- Entries.prune_orphans()
- self.log.info("Pruned %d Entries records" % (start_count - Entries.objects.count()))
-
- def django_command_proxy(self, command):
- '''Call a django command'''
- if command == 'sqlall':
- django.core.management.call_command(command, 'reports')
- else:
- django.core.management.call_command(command)
-
- def load_stats(self, stats_file=None, clientspath=None, verb=0, quick=False):
- '''Load statistics data into the database'''
- location = ''
-
- if not stats_file:
- try:
- stats_file = "%s/etc/statistics.xml" % self.cfp.get('server', 'repository')
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- self.errExit("Could not read bcfg2.conf; exiting")
- try:
- statsdata = XML(open(stats_file).read())
- except (IOError, XMLSyntaxError):
- self.errExit("StatReports: Failed to parse %s"%(stats_file))
-
- if not clientspath:
- try:
- clientspath = "%s/Metadata/clients.xml" % \
- self.cfp.get('server', 'repository')
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- self.errExit("Could not read bcfg2.conf; exiting")
- try:
- clientsdata = XML(open(clientspath).read())
- except (IOError, XMLSyntaxError):
- self.errExit("StatReports: Failed to parse %s"%(clientspath))
-
- try:
- load_stats(clientsdata, statsdata, verb, self.log, quick=quick, location=platform.node())
- except:
- pass
-
- @printStats
- def purge(self, client=None, maxdate=None, state=None):
- '''Purge historical data from the database'''
-
- filtered = False # indicates whether or not a client should be deleted
-
- if not client and not maxdate and not state:
- self.errExit("Reports.prune: Refusing to prune all data")
-
- ipurge = Interaction.objects
- if client:
- try:
- cobj = Client.objects.get(name=client)
- ipurge = ipurge.filter(client=cobj)
- except Client.DoesNotExist:
- self.log.error("Client %s not in database" % client)
- raise SystemExit, -1
- self.log.debug("Filtering by client: %s" % client)
-
- if maxdate:
- filtered = True
- if not isinstance(maxdate, datetime.datetime):
- raise TypeError, "maxdate is not a DateTime object"
- self.log.debug("Filtering by maxdate: %s" % maxdate)
- ipurge = ipurge.filter(timestamp__lt=maxdate)
-
- # Handle ping data as well
- ping = Ping.objects.filter(endtime__lt=maxdate)
- if client:
- ping = ping.filter(client=cobj)
- ping.delete()
-
- if state:
- filtered = True
- if state not in ('dirty','clean','modified'):
- raise TypeError, "state is not one of the following values " + \
- "('dirty','clean','modified')"
- self.log.debug("Filtering by state: %s" % state)
- ipurge = ipurge.filter(state=state)
-
- count = ipurge.count()
- rnum = 0
- try:
- while rnum < count:
- grp = list(ipurge[:1000].values("id"))
- # just in case...
- if not grp:
- break
- Interaction.objects.filter(id__in=[x['id'] for x in grp]).delete()
- rnum += len(grp)
- self.log.debug("Deleted %s of %s" % (rnum, count))
- except:
- self.log.error("Failed to remove interactions")
- (a, b, c) = sys.exc_info()
- msg = traceback.format_exception(a, b, c, limit=2)[-1][:-1]
- del a, b, c
- self.log.error(msg)
-
- # bulk operations bypass the Interaction.delete method
- self.log.debug("Pruning orphan Performance objects")
- Performance.prune_orphans()
-
- if client and not filtered:
- '''Delete the client, ping data is automatic'''
- try:
- self.log.debug("Purging client %s" % client)
- cobj.delete()
- except:
- self.log.error("Failed to delete client %s" % client)
- (a, b, c) = sys.exc_info()
- msg = traceback.format_exception(a, b, c, limit=2)[-1][:-1]
- del a, b, c
- self.log.error(msg)
-
- @printStats
- def purge_expired(self, maxdate=None):
- '''Purge expired clients from the database'''
-
- if maxdate:
- if not isinstance(maxdate, datetime.datetime):
- raise TypeError, "maxdate is not a DateTime object"
- self.log.debug("Filtering by maxdate: %s" % maxdate)
- clients = Client.objects.filter(expiration__lt=maxdate)
- else:
- clients = Client.objects.filter(expiration__isnull=False)
-
- for client in clients:
- self.log.debug("Purging client %s" % client)
- Interaction.objects.filter(client=client).delete()
- client.delete()
- self.log.debug("Pruning orphan Performance objects")
- Performance.prune_orphans()
-
diff --git a/build/lib/Bcfg2/Server/Admin/Snapshots.py b/build/lib/Bcfg2/Server/Admin/Snapshots.py
deleted file mode 100644
index 004de0ddb..000000000
--- a/build/lib/Bcfg2/Server/Admin/Snapshots.py
+++ /dev/null
@@ -1,163 +0,0 @@
-from datetime import date
-import sys
-
-# prereq issues can be signaled with ImportError, so no try needed
-import sqlalchemy, sqlalchemy.orm
-import Bcfg2.Server.Admin
-import Bcfg2.Server.Snapshots
-import Bcfg2.Server.Snapshots.model
-from Bcfg2.Server.Snapshots.model import Snapshot, Client, Metadata, Base, \
- File, Group, Package, Service
-
-class Snapshots(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = "Interact with the Snapshots system"
- __longhelp__ = (__shorthelp__)
- __usage__ = ("bcfg2-admin snapshots [init|query qtype]")
-
- q_dispatch = {'client':Client,
- 'group':Group,
- 'metadata':Metadata,
- 'package':Package,
- 'snapshot':Snapshot}
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.Mode.__init__(self, configfile)
- #self.session = Bcfg2.Server.Snapshots.setup_session(debug=True)
- self.session = Bcfg2.Server.Snapshots.setup_session(configfile)
- self.cfile = configfile
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- if len(args) == 0 or args[0] == '-h':
- print(self.__usage__)
- raise SystemExit(0)
-
- if args[0] == 'query':
- if args[1] in self.q_dispatch:
- q_obj = self.q_dispatch[args[1]]
- if q_obj == Client:
- rows = []
- labels = ('Client', 'Active')
- for host in \
- self.session.query(q_obj).filter(q_obj.active == False):
- rows.append([host.name, 'No'])
- for host in \
- self.session.query(q_obj).filter(q_obj.active == True):
- rows.append([host.name, 'Yes'])
- self.print_table([labels]+rows,
- justify='left',
- hdr=True,
- vdelim=" ",
- padding=1)
- elif q_obj == Group:
- print("Groups:")
- for group in self.session.query(q_obj).all():
- print(" %s" % group.name)
- else:
- results = self.session.query(q_obj).all()
- else:
- print('error')
- raise SystemExit(1)
- elif args[0] == 'init':
- # Initialize the Snapshots database
- dbpath = Bcfg2.Server.Snapshots.db_from_config(self.cfile)
- engine = sqlalchemy.create_engine(dbpath, echo=True)
- metadata = Base.metadata
- metadata.create_all(engine)
- Session = sqlalchemy.orm.sessionmaker()
- Session.configure(bind=engine)
- session = Session()
- session.commit()
- elif args[0] == 'dump':
- client = args[1]
- snap = Snapshot.get_current(self.session, unicode(client))
- if not snap:
- print("Current snapshot for %s not found" % client)
- sys.exit(1)
- print("Client %s last run at %s" % (client, snap.timestamp))
- for pkg in snap.packages:
- print("C:", pkg.correct, 'M:', pkg.modified)
- print("start", pkg.start.name, pkg.start.version)
- print("end", pkg.end.name, pkg.end.version)
- elif args[0] == 'reports':
- # bcfg2-admin reporting interface for Snapshots
- if '-a' in args[1:]:
- # Query all hosts for Name, Status, Revision, Timestamp
- q = self.session.query(Client.name,
- Snapshot.correct,
- Snapshot.revision,
- Snapshot.timestamp)\
- .filter(Client.id==Snapshot.client_id)\
- .group_by(Client.id)
- rows = []
- labels = ('Client', 'Correct', 'Revision', 'Time')
- for item in q.all():
- cli, cor, time, rev = item
- rows.append([cli, cor, time, rev])
- self.print_table([labels]+rows,
- justify='left',
- hdr=True, vdelim=" ",
- padding=1)
- elif '-b' in args[1:]:
- # Query a single host for bad entries
- if len(args) < 3:
- print("Usage: bcfg2-admin snapshots -b <client>")
- return
- client = args[2]
- snap = Snapshot.get_current(self.session, unicode(client))
- if not snap:
- print("Current snapshot for %s not found" % client)
- sys.exit(1)
- print("Bad entries:")
- bad_pkgs = [self.session.query(Package)
- .filter(Package.id==p.start_id).one().name \
- for p in snap.packages if p.correct == False]
- for p in bad_pkgs:
- print(" Package:%s" % p)
- bad_files = [self.session.query(File)
- .filter(File.id==f.start_id).one().name \
- for f in snap.files if f.correct == False]
- for filename in bad_files:
- print(" File:%s" % filename)
- bad_svcs = [self.session.query(Service)
- .filter(Service.id==s.start_id).one().name \
- for s in snap.services if s.correct == False]
- for svc in bad_svcs:
- print(" Service:%s" % svc)
- elif '-e' in args[1:]:
- # Query a single host for extra entries
- client = args[2]
- snap = Snapshot.get_current(self.session, unicode(client))
- if not snap:
- print("Current snapshot for %s not found" % client)
- sys.exit(1)
- print("Extra entries:")
- for pkg in snap.extra_packages:
- print(" Package:%s" % pkg.name)
- # FIXME: Do we know about extra files yet?
- for f in snap.extra_files:
- print(" File:%s" % f.name)
- for svc in snap.extra_services:
- print(" Service:%s" % svc.name)
- elif '--date' in args[1:]:
- year, month, day = args[2:]
- timestamp = date(int(year), int(month), int(day))
- snaps = []
- for client in self.session.query(Client).filter(Client.active == True):
- snaps.append(Snapshot.get_by_date(self.session,
- client.name,
- timestamp))
- rows = []
- labels = ('Client', 'Correct', 'Revision', 'Time')
- for snap in snaps:
- rows.append([snap.client.name,
- snap.correct,
- snap.revision,
- snap.timestamp])
- self.print_table([labels]+rows,
- justify='left',
- hdr=True,
- vdelim=" ",
- padding=1)
- else:
- print("Unknown options: ", args[1:])
diff --git a/build/lib/Bcfg2/Server/Admin/Tidy.py b/build/lib/Bcfg2/Server/Admin/Tidy.py
deleted file mode 100644
index c02ddf110..000000000
--- a/build/lib/Bcfg2/Server/Admin/Tidy.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import os
-import re
-import socket
-
-import Bcfg2.Server.Admin
-
-class Tidy(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = "Clean up useless files in the repo"
- __longhelp__ = __shorthelp__ + "\n\nbcfg2-admin tidy [-f] [-I]"
- __usage__ = ("bcfg2-admin tidy [options]\n\n"
- " %-25s%s\n"
- " %-25s%s\n" %
- ("-f",
- "force",
- "-I",
- "interactive"))
-
- def __init__(self, cfile):
- Bcfg2.Server.Admin.Mode.__init__(self, cfile)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- badfiles = self.buildTidyList()
- if '-f' in args or '-I' in args:
- if '-I' in args:
- for name in badfiles[:]:
- answer = raw_input("Unlink file %s? [yN] " % name)
- if answer not in ['y', 'Y']:
- badfiles.remove(name)
- for name in badfiles:
- try:
- os.unlink(name)
- except IOError:
- print "Failed to unlink %s" % name
- else:
- for name in badfiles:
- print name
-
- def buildTidyList(self):
- """Clean up unused or unusable files from the repository."""
- hostmatcher = re.compile('.*\.H_(\S+)$')
- to_remove = []
- good = []
- bad = []
-
- # clean up unresolvable hosts in SSHbase
- for name in os.listdir("%s/SSHbase" % (self.get_repo_path())):
- if hostmatcher.match(name):
- hostname = hostmatcher.match(name).group(1)
- if hostname in good + bad:
- continue
- try:
- socket.gethostbyname(hostname)
- good.append(hostname)
- except:
- bad.append(hostname)
- for name in os.listdir("%s/SSHbase" % (self.get_repo_path())):
- if not hostmatcher.match(name):
- to_remove.append("%s/SSHbase/%s" % (self.get_repo_path(), name))
- else:
- if hostmatcher.match(name).group(1) in bad:
- to_remove.append("%s/SSHbase/%s" %
- (self.get_repo_path(), name))
- # clean up file~
- # clean up files without parsable names in Cfg
- return to_remove
diff --git a/build/lib/Bcfg2/Server/Admin/Viz.py b/build/lib/Bcfg2/Server/Admin/Viz.py
deleted file mode 100644
index 245ca8398..000000000
--- a/build/lib/Bcfg2/Server/Admin/Viz.py
+++ /dev/null
@@ -1,101 +0,0 @@
-import getopt
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Admin
-
-class Viz(Bcfg2.Server.Admin.MetadataCore):
- __shorthelp__ = "Produce graphviz diagrams of metadata structures"
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin viz [--includehosts] "
- "[--includebundles] [--includekey] "
- "[-o output.png] [--raw]")
- __usage__ = ("bcfg2-admin viz [options]\n\n"
- " %-25s%s\n"
- " %-25s%s\n"
- " %-25s%s\n"
- " %-25s%s\n" %
- ("-H, --includehosts",
- "include hosts in the viz output",
- "-b, --includebundles",
- "include bundles in the viz output",
- "-k, --includekey",
- "show a key for different digraph shapes",
- "-o, --outfile <file>",
- "write viz output to an output file"))
-
- colors = ['steelblue1', 'chartreuse', 'gold', 'magenta',
- 'indianred1', 'limegreen', 'orange1', 'lightblue2',
- 'green1', 'blue1', 'yellow1', 'darkturquoise', 'gray66']
- plugin_blacklist = ['DBStats', 'Snapshots', 'Cfg', 'Pkgmgr', 'Packages',
- 'Rules', 'Account', 'Decisions', 'Deps', 'Git', 'Svn',
- 'Fossil', 'Bzr', 'Bundler', 'TGenshi', 'SGenshi', 'Base']
-
- def __init__(self, cfile):
-
- Bcfg2.Server.Admin.MetadataCore.__init__(self, cfile,
- self.__usage__,
- pblacklist=self.plugin_blacklist)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
- # First get options to the 'viz' subcommand
- try:
- opts, args = getopt.getopt(args, 'Hbko:',
- ['includehosts', 'includebundles',
- 'includekey', 'outfile='])
- except getopt.GetoptError, msg:
- print msg
-
- #FIXME: is this for --raw?
- #rset = False
- hset = False
- bset = False
- kset = False
- outputfile = False
- for opt, arg in opts:
- if opt in ("-H", "--includehosts"):
- hset = True
- elif opt in ("-b", "--includebundles"):
- bset = True
- elif opt in ("-k", "--includekey"):
- kset = True
- elif opt in ("-o", "--outfile"):
- outputfile = arg
-
- data = self.Visualize(self.get_repo_path(), hset, bset,
- kset, outputfile)
- print data
- raise SystemExit, 0
-
- def Visualize(self, repopath, hosts=False,
- bundles=False, key=False, output=False):
- """Build visualization of groups file."""
- if output:
- format = output.split('.')[-1]
- else:
- format = 'png'
-
- cmd = "dot -T%s" % (format)
- if output:
- cmd += " -o %s" % output
- dotpipe = Popen(cmd, shell=True, stdin=PIPE,
- stdout=PIPE, close_fds=True)
- try:
- dotpipe.stdin.write("digraph groups {\n")
- except:
- print "write to dot process failed. Is graphviz installed?"
- raise SystemExit(1)
- dotpipe.stdin.write('\trankdir="LR";\n')
- dotpipe.stdin.write(self.metadata.viz(hosts, bundles,
- key, self.colors))
- if key:
- dotpipe.stdin.write("\tsubgraph cluster_key {\n")
- dotpipe.stdin.write('''\tstyle="filled";\n''')
- dotpipe.stdin.write('''\tcolor="lightblue";\n''')
- dotpipe.stdin.write('''\tBundle [ shape="septagon" ];\n''')
- dotpipe.stdin.write('''\tGroup [shape="ellipse"];\n''')
- dotpipe.stdin.write('''\tProfile [style="bold", shape="ellipse"];\n''')
- dotpipe.stdin.write('''\tHblock [label="Host1|Host2|Host3", shape="record"];\n''')
- dotpipe.stdin.write('''\tlabel="Key";\n''')
- dotpipe.stdin.write("\t}\n")
- dotpipe.stdin.write("}\n")
- dotpipe.stdin.close()
- return dotpipe.stdout.read()
diff --git a/build/lib/Bcfg2/Server/Admin/Web.py b/build/lib/Bcfg2/Server/Admin/Web.py
deleted file mode 100644
index 5ad14f2b9..000000000
--- a/build/lib/Bcfg2/Server/Admin/Web.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import os
-import sys
-import BaseHTTPServer
-import SimpleHTTPServer
-import daemon
-import Bcfg2.Server.Admin
-import Bcfg2.Options
-
-# For debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Server.Admin.Web')
-
-class Web(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = "A simple webserver to display the content of the Bcfg2 repos."
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin web start\n"
- "\n\nbcfg2-admin web stop")
- __usage__ = ("bcfg2-admin web [start|stop]")
-
- def __init__(self, configfile):
- Bcfg2.Server.Admin.Mode.__init__(self, configfile)
-
- def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
- opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY}
- setup = Bcfg2.Options.OptionParser(opts)
- setup.parse(sys.argv[1:])
- repo = setup['repo']
-
- if len(args) == 0 or args[0] == '-h':
- print(self.__usage__)
- raise SystemExit(0)
-
- if len(args) == 0:
- self.errExit("No argument specified.\n"
- "Please see bcfg2-admin web help for usage.")
-
- if args[0] in ['start', 'up']:
- # Change directory to the Bcfg2 repo
- if not os.path.exists(repo):
- #print "Path '%s' doesn't exisit" % repo
- logger.error("%s doesn't exist" % repo)
- else:
- os.chdir(repo)
- self.start_web()
-
- elif args[0] in ['stop', 'down']:
- self.stop_web()
-
- else:
- print "No command specified"
- raise SystemExit(1)
-
- # The web server part with hardcoded port number
- def start_web(self, port=6788):
- """Starts the webserver for directory listing of the Bcfg2 repo."""
- try:
- server_class = BaseHTTPServer.HTTPServer
- handler_class = SimpleHTTPServer.SimpleHTTPRequestHandler
- server_address = ('', port)
- server = server_class(server_address, handler_class)
- #server.serve_forever()
- # Make the context manager for becoming a daemon process
- daemon_context = daemon.DaemonContext()
- daemon_context.files_preserve = [server.fileno()]
-
- # Become a daemon process
- with daemon_context:
- server.serve_forever()
- except:
- logger.error("Failed to start webserver")
- #raise Bcfg2.Server.Admin.AdminInitError
-
- def stop_web(self):
- """Stops the webserver."""
-# self.shutdown = 1
- self.shutdown()
- # self.stopped = True
-# self.serve_forever()
-
diff --git a/build/lib/Bcfg2/Server/Admin/Xcmd.py b/build/lib/Bcfg2/Server/Admin/Xcmd.py
deleted file mode 100644
index 80d5cfb25..000000000
--- a/build/lib/Bcfg2/Server/Admin/Xcmd.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import Bcfg2.Options
-import Bcfg2.Proxy
-import Bcfg2.Server.Admin
-
-import sys
-import xmlrpclib
-
-class Xcmd(Bcfg2.Server.Admin.Mode):
- __shorthelp__ = ("XML-RPC Command Interface")
- __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin xcmd command")
- __usage__ = ("bcfg2-admin xcmd <command>")
-
- def __call__(self, args):
- optinfo = {
- 'server': Bcfg2.Options.SERVER_LOCATION,
- 'user': Bcfg2.Options.CLIENT_USER,
- 'password': Bcfg2.Options.SERVER_PASSWORD,
- 'key': Bcfg2.Options.SERVER_KEY,
- 'certificate' : Bcfg2.Options.CLIENT_CERT,
- 'ca' : Bcfg2.Options.CLIENT_CA
- }
- setup = Bcfg2.Options.OptionParser(optinfo)
- setup.parse(sys.argv[2:])
- Bcfg2.Proxy.RetryMethod.max_retries = 1
- proxy = Bcfg2.Proxy.ComponentProxy(setup['server'],
- setup['user'],
- setup['password'],
- key = setup['key'],
- cert = setup['certificate'],
- ca = setup['ca'], timeout=180)
- if len(setup['args']) == 0:
- print("Usage: xcmd <xmlrpc method> <optional arguments>")
- return
- cmd = setup['args'][0]
- args = ()
- if len(setup['args']) > 1:
- args = tuple(setup['args'][1:])
- try:
- data = apply(getattr(proxy, cmd), args)
- except xmlrpclib.Fault, flt:
- if flt.faultCode == 7:
- print("Unknown method %s" % cmd)
- return
- elif flt.faultCode == 20:
- return
- else:
- raise
- if data != None:
- print data
diff --git a/build/lib/Bcfg2/Server/Admin/__init__.py b/build/lib/Bcfg2/Server/Admin/__init__.py
deleted file mode 100644
index bb5c41895..000000000
--- a/build/lib/Bcfg2/Server/Admin/__init__.py
+++ /dev/null
@@ -1,114 +0,0 @@
-__revision__ = '$Revision$'
-
-__all__ = ['Mode', 'Client', 'Compare', 'Init', 'Minestruct', 'Perf',
- 'Pull', 'Query', 'Reports', 'Snapshots', 'Tidy', 'Viz',
- 'Xcmd', 'Group', 'Backup']
-
-import ConfigParser
-import logging
-import lxml.etree
-import sys
-
-import Bcfg2.Server.Core
-import Bcfg2.Options
-
-class ModeOperationError(Exception):
- pass
-
-class Mode(object):
- """Help message has not yet been added for mode."""
- __shorthelp__ = 'Shorthelp not defined yet'
- __longhelp__ = 'Longhelp not defined yet'
- __args__ = []
- def __init__(self, configfile):
- self.configfile = configfile
- self.__cfp = False
- self.log = logging.getLogger('Bcfg2.Server.Admin.Mode')
-
- def getCFP(self):
- if not self.__cfp:
- self.__cfp = ConfigParser.ConfigParser()
- self.__cfp.read(self.configfile)
- return self.__cfp
-
- cfp = property(getCFP)
-
- def __call__(self, args):
- if len(args) > 0 and args[0] == 'help':
- print self.__longhelp__
- raise SystemExit(0)
-
- def errExit(self, emsg):
- print emsg
- raise SystemExit(1)
-
- def get_repo_path(self):
- """Return repository path"""
- return self.cfp.get('server', 'repository')
-
- def load_stats(self, client):
- stats = lxml.etree.parse("%s/etc/statistics.xml" %
- (self.get_repo_path()))
- hostent = stats.xpath('//Node[@name="%s"]' % client)
- if not hostent:
- self.errExit("Could not find stats for client %s" % (client))
- return hostent[0]
-
- def print_table(self, rows, justify='left', hdr=True, vdelim=" ", padding=1):
- """Pretty print a table
-
- rows - list of rows ([[row 1], [row 2], ..., [row n]])
- hdr - if True the first row is treated as a table header
- vdelim - vertical delimiter between columns
- padding - # of spaces around the longest element in the column
- justify - may be left,center,right
-
- """
- hdelim = "="
- justify = {'left':str.ljust,
- 'center':str.center,
- 'right':str.rjust}[justify.lower()]
-
- """
- Calculate column widths (longest item in each column
- plus padding on both sides)
-
- """
- cols = list(zip(*rows))
- colWidths = [max([len(str(item))+2*padding for \
- item in col]) for col in cols]
- borderline = vdelim.join([w*hdelim for w in colWidths])
-
- # print out the table
- print(borderline)
- for row in rows:
- print(vdelim.join([justify(str(item), width) for \
- (item, width) in zip(row, colWidths)]))
- if hdr:
- print(borderline)
- hdr = False
-
-class MetadataCore(Mode):
- """Base class for admin-modes that handle metadata."""
- def __init__(self, configfile, usage, pwhitelist=None, pblacklist=None):
- Mode.__init__(self, configfile)
- options = {'plugins': Bcfg2.Options.SERVER_PLUGINS,
- 'configfile': Bcfg2.Options.CFILE}
- setup = Bcfg2.Options.OptionParser(options)
- setup.hm = usage
- setup.parse(sys.argv[1:])
- if pwhitelist is not None:
- setup['plugins'] = [x for x in setup['plugins'] if x in pwhitelist]
- elif pblacklist is not None:
- setup['plugins'] = [x for x in setup['plugins'] if x not in pblacklist]
- try:
- self.bcore = Bcfg2.Server.Core.Core(self.get_repo_path(),
- setup['plugins'],
- 'foo', 'UTF-8')
- except Bcfg2.Server.Core.CoreInitError, msg:
- self.errExit("Core load failed because %s" % msg)
- self.bcore.fam.handle_events_in_interval(5)
- self.metadata = self.bcore.metadata
-
-class StructureMode(MetadataCore):
- pass
diff --git a/build/lib/Bcfg2/Server/Admin/test.py b/build/lib/Bcfg2/Server/Admin/test.py
deleted file mode 100644
index 06271b186..000000000
--- a/build/lib/Bcfg2/Server/Admin/test.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import os
-import time
-import tarfile
-import sys
-datastore = '/var/lib/bcfg2'
-
-#Popen(['git', 'clone', 'https://github.com/solj/bcfg2-repo.git', datastore])
-#timestamp = time.strftime('%Y%m%d%H%M%S')
-#format = 'gz'
-#mode = 'w:' + format
-#filename = timestamp + '.tar' + '.' + format
-#out = tarfile.open('/home/fab/' + filename, mode=mode)
-
-
-#content = os.listdir(os.getcwd())
-#for item in content:
-# out.add(item)
-#out.close()
-#print "Archive %s was stored.\nLocation: %s" % (filename, datastore)
-
-#print os.getcwd()
-#print os.listdir(os.getcwd())
-
-#import shlex
-#args = shlex.split('env LC_ALL=C git clone https://github.com/solj/bcfg2-repo.git datastore')
-#print args
-
-#Popen("env LC_ALL=C git clone https://github.com/solj/bcfg2-repo.git datastore")
-
-#timestamp = time.strftime('%Y%m%d%H%M%S')
-#format = 'gz'
-#mode = 'w:' + format
-#filename = timestamp + '.tar' + '.' + format
-#out = tarfile.open(name = filename, mode = mode)
-##content = os.listdir(datastore)
-##for item in content:
-## out.add(item)
-##out.close()
-
-###t = tarfile.open(name = destination, mode = 'w:gz')
-#out.add(datastore, os.path.basename(datastore))
-#out.close()
-
-#print datastore, os.path.basename(datastore)
-
-#content = os.listdir(datastore)
-#for item in content:
-# #out.add(item)
-# print item
-
-#timestamp = time.strftime('%Y%m%d%H%M%S')
-#format = 'gz'
-#mode = 'w:' + format
-#filename = timestamp + '.tar' + '.' + format
-
-if len(sys.argv) == 0:
- destination = datastore + '/'
-else:
- destination = sys.argv[1]
-
-print destination
-#out = tarfile.open(destination + filename, mode=mode)
-#out.add(self.datastore, os.path.basename(self.datastore))
-#out.close()
-#print "Archive %s was stored at %s" % (filename, destination)
-
-#print 'Die Kommandozeilenparameter sind:'
-##for i in sys.argv:
-## print i
-
-#print sys.argv[0]
-#print sys.argv[1]
-##print sys.argv[2]
diff --git a/build/lib/Bcfg2/Server/Core.py b/build/lib/Bcfg2/Server/Core.py
deleted file mode 100644
index ac67b8a69..000000000
--- a/build/lib/Bcfg2/Server/Core.py
+++ /dev/null
@@ -1,439 +0,0 @@
-"""Bcfg2.Server.Core provides the runtime support for Bcfg2 modules."""
-__revision__ = '$Revision$'
-
-import atexit
-import logging
-import lxml.etree
-import select
-import threading
-import time
-import xmlrpclib
-
-from Bcfg2.Component import Component, exposed
-from Bcfg2.Server.Plugin import PluginInitError, PluginExecutionError
-import Bcfg2.Server.FileMonitor
-import Bcfg2.Server.Plugins.Metadata
-
-logger = logging.getLogger('Bcfg2.Server.Core')
-
-def critical_error(operation):
- """Log and err, traceback and return an xmlrpc fault to client."""
- logger.error(operation, exc_info=1)
- raise xmlrpclib.Fault(7, "Critical unexpected failure: %s" % (operation))
-
-try:
- import psyco
- psyco.full()
-except:
- pass
-
-class CoreInitError(Exception):
- """This error is raised when the core cannot be initialized."""
- pass
-
-class Core(Component):
- """The Core object is the container for all Bcfg2 Server logic and modules."""
- name = 'bcfg2-server'
- implementation = 'bcfg2-server'
-
- def __init__(self, repo, plugins, password, encoding,
- cfile='/etc/bcfg2.conf', ca=None,
- filemonitor='default', start_fam_thread=False):
- Component.__init__(self)
- self.datastore = repo
- if filemonitor not in Bcfg2.Server.FileMonitor.available:
- logger.error("File monitor driver %s not available; forcing to default" % filemonitor)
- filemonitor = 'default'
- try:
- self.fam = Bcfg2.Server.FileMonitor.available[filemonitor]()
- except IOError:
- logger.error("Failed to instantiate fam driver %s" % filemonitor,
- exc_info=1)
- raise CoreInitError, "failed to instantiate fam driver (used %s)" % \
- filemonitor
- self.pubspace = {}
- self.cfile = cfile
- self.cron = {}
- self.plugins = {}
- self.plugin_blacklist = {}
- self.revision = '-1'
- self.password = password
- self.encoding = encoding
- atexit.register(self.shutdown)
- # Create an event to signal worker threads to shutdown
- self.terminate = threading.Event()
-
- if '' in plugins:
- plugins.remove('')
-
- for plugin in plugins:
- if not plugin in self.plugins:
- self.init_plugins(plugin)
- # Remove blacklisted plugins
- for p, bl in self.plugin_blacklist.items():
- if len(bl) > 0:
- logger.error("The following plugins conflict with %s;"
- "Unloading %s" % (p, bl))
- for plug in bl:
- del self.plugins[plug]
- # This section loads the experimental plugins
- expl = [plug for (name, plug) in self.plugins.iteritems()
- if plug.experimental]
- if expl:
- logger.info("Loading experimental plugin(s): %s" % \
- (" ".join([x.name for x in expl])))
- logger.info("NOTE: Interfaces subject to change")
- depr = [plug for (name, plug) in self.plugins.iteritems()
- if plug.deprecated]
- # This section loads the deprecated plugins
- if depr:
- logger.info("Loading deprecated plugin(s): %s" % \
- (" ".join([x.name for x in depr])))
-
-
- mlist = [p for p in self.plugins.values() if \
- isinstance(p, Bcfg2.Server.Plugin.Metadata)]
- if len(mlist) == 1:
- self.metadata = mlist[0]
- else:
- logger.error("No Metadata Plugin loaded; failed to instantiate Core")
- raise CoreInitError, "No Metadata Plugin"
- self.statistics = [plugin for plugin in self.plugins.values() if \
- isinstance(plugin, Bcfg2.Server.Plugin.Statistics)]
- self.pull_sources = [plugin for plugin in self.statistics if \
- isinstance(plugin, Bcfg2.Server.Plugin.PullSource)]
- self.generators = [plugin for plugin in self.plugins.values() if \
- isinstance(plugin, Bcfg2.Server.Plugin.Generator)]
- self.structures = [plugin for plugin in self.plugins.values() if \
- isinstance(plugin, Bcfg2.Server.Plugin.Structure)]
- self.connectors = [plugin for plugin in self.plugins.values() if \
- isinstance(plugin, Bcfg2.Server.Plugin.Connector)]
- self.ca = ca
- self.fam_thread = threading.Thread(target=self._file_monitor_thread)
- if start_fam_thread:
- self.fam_thread.start()
-
- def _file_monitor_thread(self):
- """The thread for monitor the files."""
- famfd = self.fam.fileno()
- terminate = self.terminate
- while not terminate.isSet():
- try:
- if famfd:
- select.select([famfd], [], [], 2)
- else:
- if not self.fam.pending():
- terminate.wait(15)
- self.fam.handle_event_set(self.lock)
- except:
- continue
- # VCS plugin periodic updates
- for plugin in self.plugins.values():
- if isinstance(plugin, Bcfg2.Server.Plugin.Version):
- self.revision = plugin.get_revision()
-
- def init_plugins(self, plugin):
- """Handling for the plugins."""
- try:
- mod = getattr(__import__("Bcfg2.Server.Plugins.%s" %
- (plugin)).Server.Plugins, plugin)
- except ImportError, e:
- try:
- mod = __import__(plugin)
- except:
- logger.error("Failed to load plugin %s" % (plugin))
- return
- plug = getattr(mod, plugin)
- # Blacklist conflicting plugins
- cplugs = [conflict for conflict in plug.conflicts
- if conflict in self.plugins]
- self.plugin_blacklist[plug.name] = cplugs
- try:
- self.plugins[plugin] = plug(self, self.datastore)
- except PluginInitError:
- logger.error("Failed to instantiate plugin %s" % (plugin))
- except:
- logger.error("Unexpected instantiation failure for plugin %s" %
- (plugin), exc_info=1)
-
- def shutdown(self):
- """Shuting down the plugins."""
- if not self.terminate.isSet():
- self.terminate.set()
- for plugin in self.plugins.values():
- plugin.shutdown()
-
- def validate_data(self, metadata, data, base_cls):
- """Checks the data structure."""
- for plugin in self.plugins.values():
- if isinstance(plugin, base_cls):
- try:
- if base_cls == Bcfg2.Server.Plugin.StructureValidator:
- plugin.validate_structures(metadata, data)
- elif base_cls == Bcfg2.Server.Plugin.GoalValidator:
- plugin.validate_goals(metadata, data)
- except Bcfg2.Server.Plugin.ValidationError, err:
- logger.error("Plugin %s structure validation failed: %s" \
- % (plugin.name, err.message))
- raise
- except:
- logger.error("Plugin %s: unexpected structure validation failure" \
- % (plugin.name), exc_info=1)
-
- def GetStructures(self, metadata):
- """Get all structures for client specified by metadata."""
- structures = reduce(lambda x, y:x+y,
- [struct.BuildStructures(metadata) for struct \
- in self.structures], [])
- sbundles = [b.get('name') for b in structures if b.tag == 'Bundle']
- missing = [b for b in metadata.bundles if b not in sbundles]
- if missing:
- logger.error("Client %s configuration missing bundles: %s" \
- % (metadata.hostname, ':'.join(missing)))
- return structures
-
- def BindStructure(self, structure, metadata):
- """Bind a complete structure."""
- for entry in structure.getchildren():
- if entry.tag.startswith("Bound"):
- entry.tag = entry.tag[5:]
- continue
- try:
- self.Bind(entry, metadata)
- except PluginExecutionError:
- if 'failure' not in entry.attrib:
- entry.set('failure', 'bind error')
- logger.error("Failed to bind entry: %s %s" % \
- (entry.tag, entry.get('name')))
- except:
- logger.error("Unexpected failure in BindStructure: %s %s" \
- % (entry.tag, entry.get('name')), exc_info=1)
-
- def Bind(self, entry, metadata):
- """Bind an entry using the appropriate generator."""
- if 'altsrc' in entry.attrib:
- oldname = entry.get('name')
- entry.set('name', entry.get('altsrc'))
- entry.set('realname', oldname)
- del entry.attrib['altsrc']
- try:
- ret = self.Bind(entry, metadata)
- entry.set('name', oldname)
- del entry.attrib['realname']
- return ret
- except:
- entry.set('name', oldname)
- logger.error("Failed binding entry %s:%s with altsrc %s" \
- % (entry.tag, entry.get('name'),
- entry.get('altsrc')))
- logger.error("Falling back to %s:%s" % (entry.tag,
- entry.get('name')))
-
- glist = [gen for gen in self.generators if
- entry.get('name') in gen.Entries.get(entry.tag, {})]
- if len(glist) == 1:
- return glist[0].Entries[entry.tag][entry.get('name')](entry, metadata)
- elif len(glist) > 1:
- generators = ", ".join([gen.name for gen in glist])
- logger.error("%s %s served by multiple generators: %s" % \
- (entry.tag, entry.get('name'), generators))
- g2list = [gen for gen in self.generators if
- gen.HandlesEntry(entry, metadata)]
- if len(g2list) == 1:
- return g2list[0].HandleEntry(entry, metadata)
- entry.set('failure', 'no matching generator')
- raise PluginExecutionError, (entry.tag, entry.get('name'))
-
- def BuildConfiguration(self, client):
- """Build configuration for clients."""
- start = time.time()
- config = lxml.etree.Element("Configuration", version='2.0', \
- revision=self.revision)
- try:
- meta = self.build_metadata(client)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- logger.error("Metadata consistency error for client %s" % client)
- return lxml.etree.Element("error", type='metadata error')
-
- try:
- structures = self.GetStructures(meta)
- except:
- logger.error("error in GetStructures", exc_info=1)
- return lxml.etree.Element("error", type='structure error')
-
- self.validate_data(meta, structures,
- Bcfg2.Server.Plugin.StructureValidator)
-
- # Perform altsrc consistency checking
- esrcs = {}
- for struct in structures:
- for entry in struct:
- key = (entry.tag, entry.get('name'))
- if key in esrcs:
- if esrcs[key] != entry.get('altsrc'):
- logger.error("Found inconsistent altsrc mapping for entry %s:%s" % key)
- else:
- esrcs[key] = entry.get('altsrc', None)
- del esrcs
-
- for astruct in structures:
- try:
- self.BindStructure(astruct, meta)
- config.append(astruct)
- except:
- logger.error("error in BindStructure", exc_info=1)
- self.validate_data(meta, config, Bcfg2.Server.Plugin.GoalValidator)
- logger.info("Generated config for %s in %.03fs" % \
- (client, time.time() - start))
- return config
-
- def GetDecisions(self, metadata, mode):
- """Get data for the decision list."""
- result = []
- for plugin in self.plugins.values():
- try:
- if isinstance(plugin, Bcfg2.Server.Plugin.Decision):
- result += plugin.GetDecisions(metadata, mode)
- except:
- logger.error("Plugin: %s failed to generate decision list" \
- % plugin.name, exc_info=1)
- return result
-
- def build_metadata(self, client_name):
- """Build the metadata structure."""
- if not hasattr(self, 'metadata'):
- # some threads start before metadata is even loaded
- raise Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError
- imd = self.metadata.get_initial_metadata(client_name)
- for conn in self.connectors:
- grps = conn.get_additional_groups(imd)
- self.metadata.merge_additional_groups(imd, grps)
- for conn in self.connectors:
- data = conn.get_additional_data(imd)
- self.metadata.merge_additional_data(imd, conn.name, data)
- imd.query.by_name = self.build_metadata
- return imd
-
- def process_statistics(self, client_name, statistics):
- """Proceed statistics for client."""
- meta = self.build_metadata(client_name)
- state = statistics.find(".//Statistics")
- if state.get('version') >= '2.0':
- for plugin in self.statistics:
- try:
- plugin.process_statistics(meta, statistics)
- except:
- logger.error("Plugin %s failed to process stats from %s" \
- % (plugin.name, meta.hostname),
- exc_info=1)
-
- logger.info("Client %s reported state %s" % (client_name,
- state.get('state')))
- # XMLRPC handlers start here
-
- @exposed
- def GetProbes(self, address):
- """Fetch probes for a particular client."""
- resp = lxml.etree.Element('probes')
- try:
- name = self.metadata.resolve_client(address)
- meta = self.build_metadata(name)
-
- for plugin in [p for p in list(self.plugins.values()) \
- if isinstance(p, Bcfg2.Server.Plugin.Probing)]:
- for probe in plugin.GetProbes(meta):
- resp.append(probe)
- return lxml.etree.tostring(resp, encoding='UTF-8',
- xml_declaration=True)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- warning = 'Client metadata resolution error for %s; check server log' % address[0]
- self.logger.warning(warning)
- raise xmlrpclib.Fault(6, warning)
- except Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError:
- err_msg = 'Metadata system runtime failure'
- self.logger.error(err_msg)
- raise xmlrpclib.Fault(6, err_msg)
- except:
- critical_error("Error determining client probes")
-
- @exposed
- def RecvProbeData(self, address, probedata):
- """Receive probe data from clients."""
- try:
- name = self.metadata.resolve_client(address)
- meta = self.build_metadata(name)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- warning = 'Metadata consistency error'
- self.logger.warning(warning)
- raise xmlrpclib.Fault(6, warning)
- # clear dynamic groups
- self.metadata.cgroups[meta.hostname] = []
- try:
- xpdata = lxml.etree.XML(probedata)
- except:
- self.logger.error("Failed to parse probe data from client %s" % \
- (address[0]))
- return False
-
- sources = []
- [sources.append(data.get('source')) for data in xpdata
- if data.get('source') not in sources]
- for source in sources:
- if source not in self.plugins:
- self.logger.warning("Failed to locate plugin %s" % (source))
- continue
- dl = [data for data in xpdata if data.get('source') == source]
- try:
- self.plugins[source].ReceiveData(meta, dl)
- except:
- logger.error("Failed to process probe data from client %s" % \
- (address[0]), exc_info=1)
- return True
-
- @exposed
- def AssertProfile(self, address, profile):
- """Set profile for a client."""
- try:
- client = self.metadata.resolve_client(address)
- self.metadata.set_profile(client, profile, address)
- except (Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError,
- Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError):
- warning = 'Metadata consistency error'
- self.logger.warning(warning)
- raise xmlrpclib.Fault(6, warning)
- return True
-
- @exposed
- def GetConfig(self, address, checksum=False):
- """Build config for a client."""
- try:
- client = self.metadata.resolve_client(address)
- config = self.BuildConfiguration(client)
- return lxml.etree.tostring(config, encoding='UTF-8',
- xml_declaration=True)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- self.logger.warning("Metadata consistency failure for %s" % (address))
- raise xmlrpclib.Fault(6, "Metadata consistency failure")
-
- @exposed
- def RecvStats(self, address, stats):
- """Act on statistics upload."""
- sdata = lxml.etree.XML(stats)
- client = self.metadata.resolve_client(address)
- self.process_statistics(client, sdata)
- return "<ok/>"
-
- def authenticate(self, cert, user, password, address):
- if self.ca:
- acert = cert
- else:
- # No ca, so no cert validation can be done
- acert = None
- return self.metadata.AuthenticateConnection(acert, user, password, address)
-
- @exposed
- def GetDecisionList(self, address, mode):
- """Get the data of the decision list."""
- client = self.metadata.resolve_client(address)
- meta = self.build_metadata(client)
- return self.GetDecisions(meta, mode)
diff --git a/build/lib/Bcfg2/Server/FileMonitor.py b/build/lib/Bcfg2/Server/FileMonitor.py
deleted file mode 100644
index 0f09f7751..000000000
--- a/build/lib/Bcfg2/Server/FileMonitor.py
+++ /dev/null
@@ -1,307 +0,0 @@
-"""Bcfg2.Server.FileMonitor provides the support for monitorung files."""
-
-import logging
-import os
-import stat
-from time import sleep, time
-
-logger = logging.getLogger('Bcfg2.Server.FileMonitor')
-
-def ShouldIgnore(event):
- """Test if the event should be suppresed."""
- # FIXME should move event suppression out of the core
- if event.filename.split('/')[-1] == '.svn':
- return True
- if event.filename.endswith('~') or \
- event.filename.startswith('#') or event.filename.startswith('.#'):
- #logger.error("Suppressing event for file %s" % (event.filename))
- return True
- return False
-
-class Event(object):
- def __init__(self, request_id, filename, code):
- self.requestID = request_id
- self.filename = filename
- self.action = code
-
- def code2str(self):
- """return static code for event"""
- return self.action
-
-available = {}
-class FileMonitor(object):
- """File Monitor baseclass."""
- def __init__(self, debug=False):
- object.__init__(self)
- self.debug = debug
- self.handles = dict()
-
- def get_event(self):
- return None
-
- def pending(self):
- return False
-
- def fileno(self):
- return 0
-
- def handle_one_event(self, event):
- if ShouldIgnore(event):
- return
- if event.requestID not in self.handles:
- logger.info("Got event for unexpected id %s, file %s" %
- (event.requestID, event.filename))
- return
- if self.debug:
- logger.info("Dispatching event %s %s to obj %s" \
- % (event.code2str(), event.filename,
- self.handles[event.requestID]))
- try:
- self.handles[event.requestID].HandleEvent(event)
- except:
- logger.error("error in handling of gamin event for %s" % \
- (event.filename), exc_info=1)
-
- def handle_event_set(self, lock=None):
- count = 1
- event = self.get_event()
- start = time()
- if lock:
- lock.acquire()
- try:
- self.handle_one_event(event)
- while self.pending():
- self.handle_one_event(self.get_event())
- count += 1
- except:
- pass
- if lock:
- lock.release()
- end = time()
- logger.info("Handled %d events in %.03fs" % (count, (end-start)))
-
- def handle_events_in_interval(self, interval):
- end = time() + interval
- while time() < end:
- if self.pending():
- self.handle_event_set()
- end = time() + interval
- else:
- sleep(0.5)
-
-
-class FamFam(object):
- """The fam object is a set of callbacks for file alteration events (FAM support)."""
-
- def __init__(self):
- object.__init__(self)
- self.fm = _fam.open()
- self.users = {}
- self.handles = {}
- self.debug = False
-
- def fileno(self):
- """Return fam file handle number."""
- return self.fm.fileno()
-
- def handle_event_set(self, _):
- self.Service()
-
- def handle_events_in_interval(self, interval):
- now = time()
- while (time() - now) < interval:
- if self.Service():
- now = time()
-
- def AddMonitor(self, path, obj):
- """Add a monitor to path, installing a callback to obj.HandleEvent."""
- mode = os.stat(path)[stat.ST_MODE]
- if stat.S_ISDIR(mode):
- handle = self.fm.monitorDirectory(path, None)
- else:
- handle = self.fm.monitorFile(path, None)
- self.handles[handle.requestID()] = handle
- if obj != None:
- self.users[handle.requestID()] = obj
- return handle.requestID()
-
- def Service(self, interval=0.50):
- """Handle all fam work."""
- count = 0
- collapsed = 0
- rawevents = []
- start = time()
- now = time()
- while (time() - now) < interval:
- if self.fm.pending():
- while self.fm.pending():
- count += 1
- rawevents.append(self.fm.nextEvent())
- now = time()
- unique = []
- bookkeeping = []
- for event in rawevents:
- if ShouldIgnore(event):
- continue
- if event.code2str() != 'changed':
- # process all non-change events
- unique.append(event)
- else:
- if (event.filename, event.requestID) not in bookkeeping:
- bookkeeping.append((event.filename, event.requestID))
- unique.append(event)
- else:
- collapsed += 1
- for event in unique:
- if event.requestID in self.users:
- try:
- self.users[event.requestID].HandleEvent(event)
- except:
- logger.error("handling event for file %s" % (event.filename), exc_info=1)
- end = time()
- logger.info("Processed %s fam events in %03.03f seconds. %s coalesced" %
- (count, (end - start), collapsed))
- return count
-
-
-
-class Fam(FileMonitor):
- """
- The fam object is a set of callbacks for
- file alteration events (FAM support).
- """
-
- def __init__(self, debug=False):
- FileMonitor.__init__(self, debug)
- self.fm = _fam.open()
-
- def fileno(self):
- return self.fm.fileno()
-
- def AddMonitor(self, path, obj):
- """Add a monitor to path, installing a callback to obj.HandleEvent."""
- mode = os.stat(path)[stat.ST_MODE]
- if stat.S_ISDIR(mode):
- handle = self.fm.monitorDirectory(path, None)
- else:
- handle = self.fm.monitorFile(path, None)
- if obj != None:
- self.handles[handle.requestID()] = obj
- return handle.requestID()
-
- def pending(self):
- return self.fm.pending()
-
- def get_event(self):
- return self.fm.nextEvent()
-
-class Pseudo(FileMonitor):
- """
- The fam object is a set of callbacks for
- file alteration events (static monitor support).
- """
-
- def __init__(self, debug=False):
- FileMonitor.__init__(self, debug=False)
- self.pending_events = []
-
- def pending(self):
- return len(self.pending_events) != 0
-
- def get_event(self):
- return self.pending_events.pop()
-
- def AddMonitor(self, path, obj):
- """add a monitor to path, installing a callback to obj.HandleEvent"""
- handleID = len(self.handles.keys())
- mode = os.stat(path)[stat.ST_MODE]
- handle = Event(handleID, path, 'exists')
- if stat.S_ISDIR(mode):
- dirList = os.listdir(path)
- self.pending_events.append(handle)
- for includedFile in dirList:
- self.pending_events.append(Event(handleID, includedFile, 'exists'))
- self.pending_events.append(Event(handleID, path, 'endExist'))
- else:
- self.pending_events.append(Event(handleID, path, 'exists'))
- if obj != None:
- self.handles[handleID] = obj
- return handleID
-
-
-try:
- from gamin import WatchMonitor, GAMCreated, GAMExists, GAMEndExist, \
- GAMChanged, GAMDeleted, GAMMoved
-
- class GaminEvent(Event):
- """
- This class provides an event analogous to
- python-fam events based on gamin sources.
- """
- def __init__(self, request_id, filename, code):
- Event.__init__(self, request_id, filename, code)
- action_map = {GAMCreated: 'created', GAMExists: 'exists',
- GAMChanged: 'changed', GAMDeleted: 'deleted',
- GAMEndExist: 'endExist', GAMMoved: 'moved'}
- if code in action_map:
- self.action = action_map[code]
-
- class Gamin(FileMonitor):
- """
- The fam object is a set of callbacks for
- file alteration events (Gamin support)
- """
- def __init__(self, debug=False):
- FileMonitor.__init__(self, debug)
- self.mon = WatchMonitor()
- self.counter = 0
- self.events = []
-
- def fileno(self):
- return self.mon.get_fd()
-
- def queue(self, path, action, request_id):
- """queue up the event for later handling"""
- self.events.append(GaminEvent(request_id, path, action))
-
- def AddMonitor(self, path, obj):
- """Add a monitor to path, installing a callback to obj.HandleEvent."""
- handle = self.counter
- self.counter += 1
- mode = os.stat(path)[stat.ST_MODE]
-
- # Flush queued gamin events
- while self.mon.event_pending():
- self.mon.handle_one_event()
-
- if stat.S_ISDIR(mode):
- self.mon.watch_directory(path, self.queue, handle)
- else:
- self.mon.watch_file(path, self.queue, handle)
- self.handles[handle] = obj
- return handle
-
- def pending(self):
- return len(self.events) > 0 or self.mon.event_pending()
-
- def get_event(self):
- if self.mon.event_pending():
- self.mon.handle_one_event()
- return self.events.pop(0)
-
- available['gamin'] = Gamin
-except ImportError:
- # fall back to _fam
- pass
-
-try:
- import _fam
- available['fam'] = FamFam
-except ImportError:
- pass
-available['pseudo'] = Pseudo
-
-for fdrv in ['gamin', 'fam', 'pseudo']:
- if fdrv in available:
- available['default'] = available[fdrv]
- break
diff --git a/build/lib/Bcfg2/Server/Hostbase/__init__.py b/build/lib/Bcfg2/Server/Hostbase/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/__init__.py
+++ /dev/null
diff --git a/build/lib/Bcfg2/Server/Hostbase/backends.py b/build/lib/Bcfg2/Server/Hostbase/backends.py
deleted file mode 100644
index aa822409c..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/backends.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from django.contrib.auth.models import User
-#from ldapauth import *
-from nisauth import *
-
-__revision__ = '$Revision$'
-
-## class LDAPBackend(object):
-
-## def authenticate(self,username=None,password=None):
-## try:
-
-## l = ldapauth(username,password)
-## temp_pass = User.objects.make_random_password(100)
-## ldap_user = dict(username=l.sAMAccountName,
-## )
-## user_session_obj = dict(
-## email=l.email,
-## first_name=l.name_f,
-## last_name=l.name_l,
-## uid=l.badge_no
-## )
-## #fixme: need to add this user session obj to session
-## #print str(ldap_user)
-## user,created = User.objects.get_or_create(username=username)
-## #print user
-## #print "created " + str(created)
-## return user
-
-## except LDAPAUTHError,e:
-## #print str(e)
-## return None
-
-## def get_user(self,user_id):
-## try:
-## return User.objects.get(pk=user_id)
-## except User.DoesNotExist, e:
-## print str(e)
-## return None
-
-
-class NISBackend(object):
-
- def authenticate(self, username=None, password=None):
- try:
- n = nisauth(username, password)
- temp_pass = User.objects.make_random_password(100)
- nis_user = dict(username=username,
- )
-
- user_session_obj = dict(
- email = username + "@mcs.anl.gov",
- first_name = None,
- last_name = None,
- uid = n.uid
- )
- user, created = User.objects.get_or_create(username=username)
-
- return user
-
- except NISAUTHError, e:
- return None
-
-
- def get_user(self, user_id):
- try:
- return User.objects.get(pk=user_id)
- except User.DoesNotExist, e:
- return None
diff --git a/build/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py b/build/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py
+++ /dev/null
diff --git a/build/lib/Bcfg2/Server/Hostbase/hostbase/admin.py b/build/lib/Bcfg2/Server/Hostbase/hostbase/admin.py
deleted file mode 100644
index 70a2233cc..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/hostbase/admin.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from django.contrib import admin
-
-from models import Host, Interface, IP, MX, Name, CName, Nameserver, ZoneAddress, Zone, Log, ZoneLog
-
-admin.site.register(Host)
-admin.site.register(Interface)
-admin.site.register(IP)
-admin.site.register(MX)
-admin.site.register(Name)
-admin.site.register(CName)
-admin.site.register(Nameserver)
-admin.site.register(ZoneAddress)
-admin.site.register(Zone)
-admin.site.register(Log)
-admin.site.register(ZoneLog)
diff --git a/build/lib/Bcfg2/Server/Hostbase/hostbase/models.py b/build/lib/Bcfg2/Server/Hostbase/hostbase/models.py
deleted file mode 100644
index 3f08a09a0..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/hostbase/models.py
+++ /dev/null
@@ -1,210 +0,0 @@
-from django.db import models
-
-# Create your models here.
-class Host(models.Model):
- NETGROUP_CHOICES = (
- ('none', 'none'),('cave', 'cave'),('ccst', 'ccst'),('mcs', 'mcs'),
- ('mmlab', 'mmlab'),('sp', 'sp'),('red', 'red'),('virtual', 'virtual'),
- ('win', 'win'),('xterm', 'xterm'),('lcrc', 'lcrc'),('anlext', 'anlext'),
- ('teragrid', 'teragrid')
- )
- STATUS_CHOICES = (
- ('active','active'),('dormant','dormant')
- )
- SUPPORT_CHOICES = (
- ('green','green'),('yellow','yellow'),('red','red')
- )
- CLASS_CHOICES = (
- ('scientific','scientific'),
- ('operations','operations'),('guest','guest'),
- ('confidential','confidential'),('public','public')
- )
- WHATAMI_CHOICES = (
- ('aix-3', 'aix-3'), ('aix-4', 'aix-4'),
- ('aix-5', 'aix-5'), ('baytech', 'baytech'),
- ('decserver', 'decserver'), ('dialup', 'dialup'),
- ('dos', 'dos'), ('freebsd', 'freebsd'),
- ('hpux', 'hpux'), ('irix-5', 'irix-5'),
- ('irix-6', 'irix-6'), ('linux', 'linux'),
- ('linux-2', 'linux-2'), ('linux-rh73', 'linux-rh73'),
- ('linux-rh8', 'linux-rh8'), ('linux-sles8', 'linux-sles8'),
- ('linux-sles8-64', 'linux-sles8-64'), ('linux-sles8-ia32', 'linux-sles8-ia32'),
- ('linux-sles8-ia64', 'linux-sles8-ia64'), ('mac', 'mac'),
- ('network', 'network'), ('next', 'next'),
- ('none', 'none'), ('osf', 'osf'), ('printer', 'printer'),
- ('robot', 'robot'), ('solaris-2', 'solaris-2'),
- ('sun4', 'sun4'), ('unknown', 'unknown'), ('virtual', 'virtual'),
- ('win31', 'win31'), ('win95', 'win95'),
- ('winNTs', 'winNTs'), ('winNTw', 'winNTw'),
- ('win2k', 'win2k'), ('winXP', 'winXP'), ('xterm', 'xterm')
- )
- hostname = models.CharField(max_length=64)
- whatami = models.CharField(max_length=16)
- netgroup = models.CharField(max_length=32, choices=NETGROUP_CHOICES)
- security_class = models.CharField('class', max_length=16)
- support = models.CharField(max_length=8, choices=SUPPORT_CHOICES)
- csi = models.CharField(max_length=32, blank=True)
- printq = models.CharField(max_length=32, blank=True)
- outbound_smtp = models.BooleanField()
- primary_user = models.EmailField()
- administrator = models.EmailField(blank=True)
- location = models.CharField(max_length=16)
- comments = models.TextField(blank=True)
- expiration_date = models.DateField(null=True, blank=True)
- last = models.DateField(auto_now=True, auto_now_add=True)
- status = models.CharField(max_length=7, choices=STATUS_CHOICES)
- dirty = models.BooleanField()
-
- class Admin:
- list_display = ('hostname', 'last')
- search_fields = ['hostname']
-
- def __str__(self):
- return self.hostname
-
- def get_logs(self):
- """
- Get host's log.
- """
- return Log.objects.filter(hostname=self.hostname)
-
-class Interface(models.Model):
- TYPE_CHOICES = (
- ('eth', 'ethernet'), ('wl', 'wireless'), ('virtual', 'virtual'), ('myr', 'myr'),
- ('mgmt', 'mgmt'), ('tape', 'tape'), ('fe', 'fe'), ('ge', 'ge'),
- )
- # FIXME: The new admin interface has change a lot.
- #host = models.ForeignKey(Host, edit_inline=models.TABULAR, num_in_admin=2)
- host = models.ForeignKey(Host)
- # FIXME: The new admin interface has change a lot.
- #mac_addr = models.CharField(max_length=32, core=True)
- mac_addr = models.CharField(max_length=32)
- hdwr_type = models.CharField('type', max_length=16, choices=TYPE_CHOICES, blank=True)
- # FIXME: The new admin interface has change a lot.
- # radio_admin=True, blank=True)
- dhcp = models.BooleanField()
-
- def __str__(self):
- return self.mac_addr
-
- class Admin:
- list_display = ('mac_addr', 'host')
- search_fields = ['mac_addr']
-
-class IP(models.Model):
- interface = models.ForeignKey(Interface)
- # FIXME: The new admin interface has change a lot.
- # edit_inline=models.TABULAR, num_in_admin=1)
- #ip_addr = models.IPAddressField(core=True)
- ip_addr = models.IPAddressField()
-
- def __str__(self):
- return self.ip_addr
-
- class Admin:
- pass
-
- class Meta:
- ordering = ('ip_addr', )
-
-class MX(models.Model):
- priority = models.IntegerField(blank=True)
- # FIXME: The new admin interface has change a lot.
- #mx = models.CharField(max_length=64, blank=True, core=True)
- mx = models.CharField(max_length=64, blank=True)
-
- def __str__(self):
- return (" ".join([str(self.priority), self.mx]))
-
- class Admin:
- pass
-
-class Name(models.Model):
- DNS_CHOICES = (
- ('global','global'),('internal','ANL internal'),
- ('private','private')
- )
- # FIXME: The new admin interface has change a lot.
- #ip = models.ForeignKey(IP, edit_inline=models.TABULAR, num_in_admin=1)
- ip = models.ForeignKey(IP)
- # FIXME: The new admin interface has change a lot.
- #name = models.CharField(max_length=64, core=True)
- name = models.CharField(max_length=64)
- dns_view = models.CharField(max_length=16, choices=DNS_CHOICES)
- only = models.BooleanField(blank=True)
- mxs = models.ManyToManyField(MX)
-
- def __str__(self):
- return self.name
-
- class Admin:
- pass
-
-class CName(models.Model):
- # FIXME: The new admin interface has change a lot.
- #name = models.ForeignKey(Name, edit_inline=models.TABULAR, num_in_admin=1)
- name = models.ForeignKey(Name)
- # FIXME: The new admin interface has change a lot.
- #cname = models.CharField(max_length=64, core=True)
- cname = models.CharField(max_length=64)
-
- def __str__(self):
- return self.cname
-
- class Admin:
- pass
-
-class Nameserver(models.Model):
- name = models.CharField(max_length=64, blank=True)
-
- def __str__(self):
- return self.name
-
- class Admin:
- pass
-
-class ZoneAddress(models.Model):
- ip_addr = models.IPAddressField(blank=True)
-
- def __str__(self):
- return self.ip_addr
-
- class Admin:
- pass
-
-class Zone(models.Model):
- zone = models.CharField(max_length=64)
- serial = models.IntegerField()
- admin = models.CharField(max_length=64)
- primary_master = models.CharField(max_length=64)
- expire = models.IntegerField()
- retry = models.IntegerField()
- refresh = models.IntegerField()
- ttl = models.IntegerField()
- nameservers = models.ManyToManyField(Nameserver, blank=True)
- mxs = models.ManyToManyField(MX, blank=True)
- addresses = models.ManyToManyField(ZoneAddress, blank=True)
- aux = models.TextField(blank=True)
-
- def __str__(self):
- return self.zone
-
- class Admin:
- pass
-
-class Log(models.Model):
- # FIXME: Proposal hostname = models.ForeignKey(Host)
- hostname = models.CharField(max_length=64)
- date = models.DateTimeField(auto_now=True, auto_now_add=True)
- log = models.TextField()
-
- def __str__(self):
- return self.hostname
-
-class ZoneLog(models.Model):
- zone = models.CharField(max_length=64)
- date = models.DateTimeField(auto_now=True, auto_now_add=True)
- log = models.TextField()
-
- def __str__(self):
- return self.zone
diff --git a/build/lib/Bcfg2/Server/Hostbase/hostbase/urls.py b/build/lib/Bcfg2/Server/Hostbase/hostbase/urls.py
deleted file mode 100644
index 0ee204abe..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/hostbase/urls.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# -*- coding: utf-8 -*-
-from django.conf.urls.defaults import *
-from django.contrib.auth.decorators import login_required
-from django.core.urlresolvers import reverse
-from django.views.generic.create_update import create_object, update_object, delete_object
-from django.views.generic.list_detail import object_detail, object_list
-
-from models import Host, Zone, Log
-
-host_detail_dict = {
- 'queryset':Host.objects.all(),
- 'template_name':'host.html',
- 'template_object_name':'host',
-}
-
-host_delete_dict = {
- 'model':Host,
- 'post_delete_redirect':'/',
-}
-
-host_log_detail_dict = host_detail_dict.copy()
-host_log_detail_dict['template_name'] = 'logviewer.html'
-
-host_dns_detail_dict = host_detail_dict.copy()
-host_dns_detail_dict['template_name'] = 'dns.html'
-
-zone_new_dict = {
- 'model':Zone,
- 'template_name':'zonenew.html',
- 'post_save_redirect':'../%(id)s',
-}
-
-zones_list_dict = {
- 'queryset':Zone.objects.all(),
- 'template_name':'zones.html',
- 'template_object_name':'zone',
-}
-
-zone_detail_dict = {
- 'queryset':Zone.objects.all(),
- 'template_name':'zoneview.html',
- 'template_object_name':'zone',
-}
-
-urlpatterns = patterns('',
- (r'^(?P<object_id>\d+)/$', object_detail, host_detail_dict, 'host_detail'),
- (r'^zones/new/$', login_required(create_object), zone_new_dict, 'zone_new'),
- (r'^zones/(?P<object_id>\d+)/edit', login_required(update_object), zone_new_dict, 'zone_edit'),
- (r'^zones/$', object_list, zones_list_dict, 'zone_list'),
- (r'^zones/(?P<object_id>\d+)/$', object_detail, zone_detail_dict, 'zone_detail'),
- (r'^zones/(?P<object_id>\d+)/$', object_detail, zone_detail_dict, 'zone_detail'),
- (r'^\d+/logs/(?P<object_id>\d+)/', object_detail, { 'queryset':Log.objects.all() }, 'log_detail'),
- (r'^(?P<object_id>\d+)/logs/', object_detail, host_log_detail_dict, 'host_log_list'),
- (r'^(?P<object_id>\d+)/dns', object_detail, host_dns_detail_dict, 'host_dns_list'),
- (r'^(?P<object_id>\d+)/remove', login_required(delete_object), host_delete_dict, 'host_delete'),
-)
-
-urlpatterns += patterns('Bcfg2.Server.Hostbase.hostbase.views',
- (r'^$', 'search'),
- (r'^(?P<host_id>\d+)/edit', 'edit'),
- (r'^(?P<host_id>\d+)/(?P<item>\D+)/(?P<item_id>\d+)/confirm', 'confirm'),
- (r'^(?P<host_id>\d+)/(?P<item>\D+)/(?P<item_id>\d+)/(?P<name_id>\d+)/confirm', 'confirm'),
- (r'^(?P<host_id>\d+)/dns/edit', 'dnsedit'),
- (r'^new', 'new'),
- (r'^(?P<host_id>\d+)/copy', 'copy'),
-# (r'^hostinfo', 'hostinfo'),
- (r'^zones/(?P<zone_id>\d+)/(?P<item>\D+)/(?P<item_id>\d+)/confirm', 'confirm'),
-)
diff --git a/build/lib/Bcfg2/Server/Hostbase/hostbase/views.py b/build/lib/Bcfg2/Server/Hostbase/hostbase/views.py
deleted file mode 100644
index ff1d4710d..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/hostbase/views.py
+++ /dev/null
@@ -1,972 +0,0 @@
-"""Views.py
-Contains all the views associated with the hostbase app
-Also has does form validation
-"""
-__revision__ = "$Revision: $"
-
-from django.http import HttpResponse, HttpResponseRedirect
-
-from django.contrib.auth.decorators import login_required
-from django.contrib.auth import logout
-from django.template import RequestContext
-from Bcfg2.Server.Hostbase.hostbase.models import *
-from datetime import date
-from django.db import connection
-from django.shortcuts import render_to_response
-from django import forms
-from Bcfg2.Server.Hostbase import settings, regex
-import re, copy
-
-attribs = ['hostname', 'whatami', 'netgroup', 'security_class', 'support',
- 'csi', 'printq', 'primary_user', 'administrator', 'location',
- 'status', 'comments']
-
-zoneattribs = ['zone', 'admin', 'primary_master', 'expire', 'retry',
- 'refresh', 'ttl', 'aux']
-
-dispatch = {'mac_addr':'i.mac_addr LIKE \'%%%%%s%%%%\'',
- 'ip_addr':'p.ip_addr LIKE \'%%%%%s%%%%\'',
- 'name':'n.name LIKE \'%%%%%s%%%%\'',
-## 'hostname':'n.name LIKE \'%%%%%s%%%%\'',
-## 'cname':'n.name LIKE \'%%%%%s%%%%\'',
- 'mx':'m.mx LIKE \'%%%%%s%%%%\'',
- 'dns_view':'n.dns_view = \'%s\'',
- 'hdwr_type':'i.hdwr_type = \'%s\'',
- 'dhcp':'i.dhcp = \'%s\''}
-
-def search(request):
- """Search for hosts in the database
- If more than one field is entered, logical AND is used
- """
- if 'sub' in request.GET:
- querystring = """SELECT DISTINCT h.hostname, h.id, h.status
- 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 n.id = x.name_id)
- INNER JOIN hostbase_mx m ON m.id = x.mx_id)
- LEFT JOIN hostbase_cname c ON n.id = c.name_id
- WHERE """
-
- _and = False
- for field in request.POST:
- if request.POST[field] and field == 'hostname':
- if _and:
- querystring += ' AND '
- querystring += 'n.name LIKE \'%%%%%s%%%%\' or c.cname LIKE \'%%%%%s%%%%\'' % (request.POST[field], request.POST[field])
- _and = True
- elif request.POST[field] and field in dispatch:
- if _and:
- querystring += ' AND '
- querystring += dispatch[field] % request.POST[field]
- _and = True
- elif request.POST[field]:
- if _and:
- querystring += ' AND '
- querystring += "h.%s LIKE \'%%%%%s%%%%\'" % (field, request.POST[field])
- _and = True
-
- if not _and:
- cursor = connection.cursor()
- cursor.execute("""SELECT hostname, id, status
- FROM hostbase_host ORDER BY hostname""")
- results = cursor.fetchall()
- else:
- querystring += " ORDER BY h.hostname"
- cursor = connection.cursor()
- cursor.execute(querystring)
- results = cursor.fetchall()
-
- return render_to_response('results.html',
- {'hosts': results,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
- else:
- return render_to_response('search.html',
- {'TYPE_CHOICES': Interface.TYPE_CHOICES,
- 'DNS_CHOICES': Name.DNS_CHOICES,
- 'yesno': [(1, 'yes'), (0, 'no')],
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
-
-def gethostdata(host_id, dnsdata=False):
- """Grabs the necessary data about a host
- Replaces a lot of repeated code"""
- hostdata = {}
- hostdata['ips'] = {}
- hostdata['names'] = {}
- hostdata['cnames'] = {}
- hostdata['mxs'] = {}
- hostdata['host'] = Host.objects.get(id=host_id)
- hostdata['interfaces'] = hostdata['host'].interface_set.all()
- for interface in hostdata['interfaces']:
- hostdata['ips'][interface.id] = interface.ip_set.all()
- if dnsdata:
- for ip in hostdata['ips'][interface.id]:
- hostdata['names'][ip.id] = ip.name_set.all()
- for name in hostdata['names'][ip.id]:
- hostdata['cnames'][name.id] = name.cname_set.all()
- hostdata['mxs'][name.id] = name.mxs.all()
- return hostdata
-
-def fill(template, hostdata, dnsdata=False):
- """Fills a generic template
- Replaces a lot of repeated code"""
- if dnsdata:
- template.names = hostdata['names']
- template.cnames = hostdata['cnames']
- template.mxs = hostdata['mxs']
- template.host = hostdata['host']
- template.interfaces = hostdata['interfaces']
- template.ips = hostdata['ips']
- return template
-
-def edit(request, host_id):
- """edit general host information"""
- manipulator = Host.ChangeManipulator(host_id)
- changename = False
- if request.method == 'POST':
- host = Host.objects.get(id=host_id)
- before = host.__dict__.copy()
- if request.POST['hostname'] != host.hostname:
- oldhostname = host.hostname.split(".")[0]
- changename = True
- interfaces = host.interface_set.all()
- old_interfaces = [interface.__dict__.copy() for interface in interfaces]
-
- new_data = request.POST.copy()
-
- errors = manipulator.get_validation_errors(new_data)
- if not errors:
-
- # somehow keep track of multiple interface change manipulators
- # as well as multiple ip chnage manipulators??? (add manipulators???)
- # change to many-to-many??????
-
- # dynamically look up mx records?
- text = ''
-
- for attrib in attribs:
- if host.__dict__[attrib] != request.POST[attrib]:
- text = do_log(text, attrib, host.__dict__[attrib], request.POST[attrib])
- host.__dict__[attrib] = request.POST[attrib]
-
- if 'expiration_date' in request.POST:
- ymd = request.POST['expiration_date'].split("-")
- if date(int(ymd[0]), int(ymd[1]), int(ymd[2])) != host.__dict__['expiration_date']:
- text = do_log(text, 'expiration_date', host.__dict__['expiration_date'],
- request.POST['expiration_date'])
- host.__dict__['expiration_date'] = date(int(ymd[0]), int(ymd[1]), int(ymd[2]))
-
- for inter in interfaces:
- changetype = False
- ips = IP.objects.filter(interface=inter.id)
- if inter.mac_addr != request.POST['mac_addr%d' % inter.id]:
- text = do_log(text, 'mac_addr', inter.mac_addr, request.POST['mac_addr%d' % inter.id])
- inter.mac_addr = request.POST['mac_addr%d' % inter.id].lower().replace('-',':')
- if inter.hdwr_type != request.POST['hdwr_type%d' % inter.id]:
- oldtype = inter.hdwr_type
- text = do_log(text, 'hdwr_type', oldtype, request.POST['hdwr_type%d' % inter.id])
- inter.hdwr_type = request.POST['hdwr_type%d' % inter.id]
- changetype = True
- if (('dhcp%d' % inter.id) in request.POST and not inter.dhcp or
- not ('dhcp%d' % inter.id) in request.POST and inter.dhcp):
- text = do_log(text, 'dhcp', inter.dhcp, int(not inter.dhcp))
- inter.dhcp = not inter.dhcp
- for ip in ips:
- names = ip.name_set.all()
- if not ip.ip_addr == request.POST['ip_addr%d' % ip.id]:
- oldip = ip.ip_addr
- oldsubnet = oldip.split(".")[2]
- ip.ip_addr = request.POST['ip_addr%d' % ip.id]
- ip.save()
- text = do_log(text, 'ip_addr', oldip, ip.ip_addr)
- for name in names:
- if name.name.split(".")[0].endswith('-%s' % oldsubnet):
- name.name = name.name.replace('-%s' % oldsubnet, '-%s' % ip.ip_addr.split(".")[2])
- name.save()
- if changetype:
- for name in names:
- if name.name.split(".")[0].endswith('-%s' % oldtype):
- name.name = name.name.replace('-%s' % oldtype, '-%s' % inter.hdwr_type)
- name.save()
- if changename:
- for name in names:
- if name.name.startswith(oldhostname):
- name.name = name.name.replace(oldhostname, host.hostname.split(".")[0])
- name.save()
- if request.POST['%dip_addr' % inter.id]:
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_ip = IP(interface=inter, ip_addr=request.POST['%dip_addr' % inter.id])
- new_ip.save()
- text = do_log(text, '*new*', 'ip_addr', new_ip.ip_addr)
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- inter.save()
- if request.POST['mac_addr_new']:
- new_inter = Interface(host=host,
- mac_addr=request.POST['mac_addr_new'].lower().replace('-',':'),
- hdwr_type=request.POST['hdwr_type_new'],
- dhcp=request.POST['dhcp_new'])
- text = do_log(text, '*new*', 'mac_addr', new_inter.mac_addr)
- new_inter.save()
- if request.POST['mac_addr_new'] and request.POST['ip_addr_new']:
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
- new_ip.save()
- text = do_log(text, '*new*', 'ip_addr', new_ip.ip_addr)
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['ip_addr_new'] and not request.POST['mac_addr_new']:
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_inter = Interface(host=host, mac_addr="",
- hdwr_type=request.POST['hdwr_type_new'],
- dhcp=False)
- new_inter.save()
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
- new_ip.save()
- text = do_log(text, '*new*', 'ip_addr', new_ip.ip_addr)
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if text:
- log = Log(hostname=host.hostname, log=text)
- log.save()
- host.save()
- return HttpResponseRedirect('/hostbase/%s/' % host.id)
- else:
- return render_to_response('errors.html',
- {'failures': errors,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
- else:
- host = Host.objects.get(id=host_id)
- interfaces = []
- for interface in host.interface_set.all():
- interfaces.append([interface, interface.ip_set.all()])
- return render_to_response('edit.html',
- {'host': host,
- 'interfaces': interfaces,
- 'TYPE_CHOICES': Interface.TYPE_CHOICES,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
-def confirm(request, item, item_id, host_id=None, name_id=None, zone_id=None):
- """Asks if the user is sure he/she wants to remove an item"""
- if 'sub' in request.GET:
- if item == 'interface':
- for ip in Interface.objects.get(id=item_id).ip_set.all():
- for name in ip.name_set.all():
- name.cname_set.all().delete()
- ip.name_set.all().delete()
- Interface.objects.get(id=item_id).ip_set.all().delete()
- Interface.objects.get(id=item_id).delete()
- elif item=='ip':
- for name in IP.objects.get(id=item_id).name_set.all():
- name.cname_set.all().delete()
- IP.objects.get(id=item_id).name_set.all().delete()
- IP.objects.get(id=item_id).delete()
- elif item=='cname':
- CName.objects.get(id=item_id).delete()
- elif item=='mx':
- mx = MX.objects.get(id=item_id)
- Name.objects.get(id=name_id).mxs.remove(mx)
- elif item=='name':
- Name.objects.get(id=item_id).cname_set.all().delete()
- Name.objects.get(id=item_id).delete()
- elif item=='nameserver':
- nameserver = Nameserver.objects.get(id=item_id)
- Zone.objects.get(id=zone_id).nameservers.remove(nameserver)
- elif item=='zonemx':
- mx = MX.objects.get(id=item_id)
- Zone.objects.get(id=zone_id).mxs.remove(mx)
- elif item=='address':
- address = ZoneAddress.objects.get(id=item_id)
- Zone.objects.get(id=zone_id).addresses.remove(address)
- if item == 'cname' or item == 'mx' or item == 'name':
- return HttpResponseRedirect('/hostbase/%s/dns/edit' % host_id)
- elif item == 'nameserver' or item == 'zonemx' or item == 'address':
- return HttpResponseRedirect('/hostbase/zones/%s/edit' % zone_id)
- else:
- return HttpResponseRedirect('/hostbase/%s/edit' % host_id)
- else:
- interface = None
- ips = []
- names = []
- cnames = []
- mxs = []
- zonemx = None
- nameserver = None
- address = None
- if item == 'interface':
- interface = Interface.objects.get(id=item_id)
- ips = interface.ip_set.all()
- for ip in ips:
- for name in ip.name_set.all():
- names.append((ip.id, name))
- for cname in name.cname_set.all():
- cnames.append((name.id, cname))
- for mx in name.mxs.all():
- mxs.append((name.id, mx))
- elif item=='ip':
- ips = [IP.objects.get(id=item_id)]
- for name in ips[0].name_set.all():
- names.append((ips[0].id, name))
- for cname in name.cname_set.all():
- cnames.append((name.id, cname))
- for mx in name.mxs.all():
- mxs.append((name.id, mx))
- elif item=='name':
- names = [Name.objects.get(id=item_id)]
- for cname in names[0].cname_set.all():
- cnames.append((names[0].id, cname))
- for mx in names[0].mxs.all():
- mxs.append((names[0].id, mx))
- elif item=='cname':
- cnames = [CName.objects.get(id=item_id)]
- elif item=='mx':
- mxs = [MX.objects.get(id=item_id)]
- elif item=='zonemx':
- zonemx = MX.objects.get(id=item_id)
- elif item=='nameserver':
- nameserver = Nameserver.objects.get(id=item_id)
- elif item=='address':
- address = ZoneAddress.objects.get(id=item_id)
- return render_to_response('confirm.html',
- {'interface': interface,
- 'ips': ips,
- 'names': names,
- 'cnames': cnames,
- 'id': item_id,
- 'type': item,
- 'host_id': host_id,
- 'mxs': mxs,
- 'zonemx': zonemx,
- 'nameserver': nameserver,
- 'address': address,
- 'zone_id': zone_id,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
-def dnsedit(request, host_id):
- """Edits specific DNS information
- Data is validated before committed to the database"""
- text = ''
- if 'sub' in request.GET:
- hostdata = gethostdata(host_id, True)
- for ip in hostdata['names']:
- ipaddr = IP.objects.get(id=ip)
- ipaddrstr = ipaddr.__str__()
- for name in hostdata['cnames']:
- for cname in hostdata['cnames'][name]:
- if regex.host.match(request.POST['cname%d' % cname.id]):
- text = do_log(text, 'cname', cname.cname, request.POST['cname%d' % cname.id])
- cname.cname = request.POST['cname%d' % cname.id]
- cname.save()
- for name in hostdata['mxs']:
- for mx in hostdata['mxs'][name]:
- if (mx.priority != request.POST['priority%d' % mx.id] and mx.mx != request.POST['mx%d' % mx.id]):
- text = do_log(text, 'mx', ' '.join([str(mx.priority), str(mx.mx)]),
- ' '.join([request.POST['priority%d' % mx.id], request.POST['mx%d' % mx.id]]))
- nameobject = Name.objects.get(id=name)
- nameobject.mxs.remove(mx)
- newmx, created = MX.objects.get_or_create(priority=request.POST['priority%d' % mx.id], mx=request.POST['mx%d' % mx.id])
- if created:
- newmx.save()
- nameobject.mxs.add(newmx)
- nameobject.save()
- for name in hostdata['names'][ip]:
- name.name = request.POST['name%d' % name.id]
- name.dns_view = request.POST['dns_view%d' % name.id]
- if (request.POST['%dcname' % name.id] and
- regex.host.match(request.POST['%dcname' % name.id])):
- cname = CName(name=name,
- cname=request.POST['%dcname' % name.id])
- text = do_log(text, '*new*', 'cname', cname.cname)
- cname.save()
- if (request.POST['%dpriority' % name.id] and
- request.POST['%dmx' % name.id]):
- mx, created = MX.objects.get_or_create(priority=request.POST['%dpriority' % name.id],
- mx=request.POST['%dmx' % name.id])
- if created:
- mx.save()
- text = do_log(text, '*new*', 'mx',
- ' '.join([request.POST['%dpriority' % name.id],
- request.POST['%dmx' % name.id]]))
- name.mxs.add(mx)
- name.save()
- if request.POST['%sname' % ipaddrstr]:
- name = Name(ip=ipaddr,
- dns_view=request.POST['%sdns_view' % ipaddrstr],
- name=request.POST['%sname' % ipaddrstr], only=False)
- text = do_log(text, '*new*', 'name', name.name)
- name.save()
- if (request.POST['%scname' % ipaddrstr] and
- regex.host.match(request.POST['%scname' % ipaddrstr])):
- cname = CName(name=name,
- cname=request.POST['%scname' % ipaddrstr])
- text = do_log(text, '*new*', 'cname', cname.cname)
- cname.save()
- if (request.POST['%smx' % ipaddrstr] and
- request.POST['%spriority' % ipaddrstr]):
- mx, created = MX.objects.get_or_create(priority=request.POST['%spriority' % ipaddrstr],
- mx=request.POST['%smx' % ipaddrstr])
- if created:
- mx.save()
- text = do_log(text, '*new*', 'mx',
- ' '.join([request.POST['%spriority' % ipaddrstr], request.POST['%smx' % ipaddrstr]]))
- name.mxs.add(mx)
- if text:
- log = Log(hostname=hostdata['host'].hostname, log=text)
- log.save()
- return HttpResponseRedirect('/hostbase/%s/dns' % host_id)
- else:
- host = Host.objects.get(id=host_id)
- ips = []
- info = []
- cnames = []
- mxs = []
- interfaces = host.interface_set.all()
- for interface in host.interface_set.all():
- ips.extend(interface.ip_set.all())
- for ip in ips:
- info.append([ip, ip.name_set.all()])
- for name in ip.name_set.all():
- cnames.extend(name.cname_set.all())
- mxs.append((name.id, name.mxs.all()))
- return render_to_response('dnsedit.html',
- {'host': host,
- 'info': info,
- 'cnames': cnames,
- 'mxs': mxs,
- 'request': request,
- 'interfaces': interfaces,
- 'DNS_CHOICES': Name.DNS_CHOICES,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
-def new(request):
- """Function for creating a new host in hostbase
- Data is validated before committed to the database"""
- if 'sub' in request.GET:
- try:
- Host.objects.get(hostname=request.POST['hostname'].lower())
- return render_to_response('errors.html',
- {'failures': ['%s already exists in hostbase' % request.POST['hostname']],
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
- except:
- pass
- if not validate(request, True):
- if not request.POST['ip_addr_new'] and not request.POST['ip_addr_new2']:
- return render_to_response('errors.html',
- {'failures': ['ip_addr: You must enter an ip address'],
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
- host = Host()
- # this is the stuff that validate() should take care of
- # examine the check boxes for any changes
- host.outbound_smtp = 'outbound_smtp' in request.POST
- for attrib in attribs:
- if attrib in request.POST:
- host.__dict__[attrib] = request.POST[attrib].lower()
- if 'comments' in request.POST:
- host.comments = request.POST['comments']
- if 'expiration_date' in request.POST:
-# ymd = request.POST['expiration_date'].split("-")
-# host.__dict__['expiration_date'] = date(int(ymd[0]), int(ymd[1]), int(ymd[2]))
- host.__dict__['expiration_date'] = date(2000, 1, 1)
- host.status = 'active'
- host.save()
- else:
- return render_to_response('errors.html',
- {'failures': validate(request, True),
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
- if request.POST['mac_addr_new']:
- new_inter = Interface(host=host,
- mac_addr = request.POST['mac_addr_new'].lower().replace('-',':'),
- hdwr_type = request.POST['hdwr_type_new'],
- dhcp = 'dhcp_new' in request.POST)
- new_inter.save()
- if request.POST['mac_addr_new'] and request.POST['ip_addr_new']:
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
-# Change all this things. Use a "post_save" signal handler for model Host to create all sociate models
-# and use a generi view.
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name, dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['ip_addr_new'] and not request.POST['mac_addr_new']:
- new_inter = Interface(host=host,
- mac_addr="",
- hdwr_type=request.POST['hdwr_type_new'],
- dhcp=False)
- new_inter.save()
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['mac_addr_new2']:
- new_inter = Interface(host=host,
- mac_addr = request.POST['mac_addr_new2'].lower().replace('-',':'),
- hdwr_type = request.POST['hdwr_type_new2'],
- dhcp = 'dhcp_new2' in request.POST)
- new_inter.save()
- if request.POST['mac_addr_new2'] and request.POST['ip_addr_new2']:
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['ip_addr_new2'] and not request.POST['mac_addr_new2']:
- new_inter = Interface(host=host,
- mac_addr="",
- hdwr_type=request.POST['hdwr_type_new2'],
- dhcp=False)
- new_inter.save()
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- host.save()
- return HttpResponseRedirect('/hostbase/%s/' % host.id)
- else:
- return render_to_response('new.html',
- {'TYPE_CHOICES': Interface.TYPE_CHOICES,
- 'NETGROUP_CHOICES': Host.NETGROUP_CHOICES,
- 'CLASS_CHOICES': Host.CLASS_CHOICES,
- 'SUPPORT_CHOICES': Host.SUPPORT_CHOICES,
- 'WHATAMI_CHOICES': Host.WHATAMI_CHOICES,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
-def copy(request, host_id):
- """Function for creating a new host in hostbase
- Data is validated before committed to the database"""
- if 'sub' in request.GET:
- try:
- Host.objects.get(hostname=request.POST['hostname'].lower())
- return render_to_response('errors.html',
- {'failures': ['%s already exists in hostbase' % request.POST['hostname']],
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
- except:
- pass
- if not validate(request, True):
- if not request.POST['ip_addr_new'] and not request.POST['ip_addr_new2']:
- return render_to_response('errors.html',
- {'failures': ['ip_addr: You must enter an ip address'],
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
- host = Host()
- # this is the stuff that validate() should take care of
- # examine the check boxes for any changes
- host.outbound_smtp = 'outbound_smtp' in request.POST
- for attrib in attribs:
- if attrib in request.POST:
- host.__dict__[attrib] = request.POST[attrib].lower()
- if 'comments' in request.POST:
- host.comments = request.POST['comments']
- if 'expiration_date' in request.POST:
-# ymd = request.POST['expiration_date'].split("-")
-# host.__dict__['expiration_date'] = date(int(ymd[0]), int(ymd[1]), int(ymd[2]))
- host.__dict__['expiration_date'] = date(2000, 1, 1)
- host.status = 'active'
- host.save()
- else:
- return render_to_response('errors.html',
- {'failures': validate(request, True),
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
- if request.POST['mac_addr_new']:
- new_inter = Interface(host=host,
- mac_addr = request.POST['mac_addr_new'].lower().replace('-',':'),
- hdwr_type = request.POST['hdwr_type_new'],
- dhcp = 'dhcp_new' in request.POST)
- new_inter.save()
- if request.POST['mac_addr_new'] and request.POST['ip_addr_new']:
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name, dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['ip_addr_new'] and not request.POST['mac_addr_new']:
- new_inter = Interface(host=host,
- mac_addr="",
- hdwr_type=request.POST['hdwr_type_new'],
- dhcp=False)
- new_inter.save()
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['mac_addr_new2']:
- new_inter = Interface(host=host,
- mac_addr = request.POST['mac_addr_new2'].lower().replace('-',':'),
- hdwr_type = request.POST['hdwr_type_new2'],
- dhcp = 'dhcp_new2' in request.POST)
- new_inter.save()
- if request.POST['mac_addr_new2'] and request.POST['ip_addr_new2']:
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- if request.POST['ip_addr_new2'] and not request.POST['mac_addr_new2']:
- new_inter = Interface(host=host,
- mac_addr="",
- hdwr_type=request.POST['hdwr_type_new2'],
- dhcp=False)
- new_inter.save()
- new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
- new_ip.save()
- mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
- if created:
- mx.save()
- new_name = "-".join([host.hostname.split(".")[0],
- new_ip.ip_addr.split(".")[2]])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- new_name = "-".join([host.hostname.split(".")[0],
- new_inter.hdwr_type])
- new_name += "." + host.hostname.split(".", 1)[1]
- name = Name(ip=new_ip, name=new_name,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- name = Name(ip=new_ip, name=host.hostname,
- dns_view='global', only=False)
- name.save()
- name.mxs.add(mx)
- host.save()
- return HttpResponseRedirect('/hostbase/%s/' % host.id)
- else:
- host = Host.objects.get(id=host_id)
- return render_to_response('copy.html',
- {'host': host,
- 'TYPE_CHOICES': Interface.TYPE_CHOICES,
- 'NETGROUP_CHOICES': Host.NETGROUP_CHOICES,
- 'CLASS_CHOICES': Host.CLASS_CHOICES,
- 'SUPPORT_CHOICES': Host.SUPPORT_CHOICES,
- 'WHATAMI_CHOICES': Host.WHATAMI_CHOICES,
- 'logged_in': request.session.get('_auth_user_id', False)},
- context_instance = RequestContext(request))
-
-# FIXME: delete all this things in a signal handler "pre_delete"
-#def remove(request, host_id):
-# host = Host.objects.get(id=host_id)
-# if 'sub' in request:
-# for interface in host.interface_set.all():
-# for ip in interface.ip_set.all():
-# for name in ip.name_set.all():
-# name.cname_set.all().delete()
-# ip.name_set.all().delete()
-# interface.ip_set.all().delete()
-# interface.delete()
-# host.delete()
-
-def validate(request, new=False, host_id=None):
- """Function for checking form data"""
- failures = []
- if (request.POST['expiration_date']
- and regex.date.match(request.POST['expiration_date'])):
- try:
- (year, month, day) = request.POST['expiration_date'].split("-")
- date(int(year), int(month), int(day))
- except (ValueError):
- failures.append('expiration_date')
- elif request.POST['expiration_date']:
- failures.append('expiration_date')
-
- if not (request.POST['hostname']
- and regex.host.match(request.POST['hostname'])):
- failures.append('hostname')
-
-## if not regex.printq.match(request.POST['printq']) and request.POST['printq']:
-## failures.append('printq')
-
-## if not regex.user.match(request.POST['primary_user']):
-## failures.append('primary_user')
-
-## if (not regex.user.match(request.POST['administrator'])
-## and request.POST['administrator']):
-## failures.append('administrator')
-
-## if not (request.POST['location']
-## and regex.location.match(request.POST['location'])):
-## failures.append('location')
-
- if new:
- if (not regex.macaddr.match(request.POST['mac_addr_new'])
- and request.POST['mac_addr_new']):
- failures.append('mac_addr (#1)')
- if ((request.POST['mac_addr_new'] or request.POST['ip_addr_new']) and
- not 'hdwr_type_new' in request.REQUEST):
- failures.append('hdwr_type (#1)')
- if ((request.POST['mac_addr_new2'] or request.POST['ip_addr_new2']) and
- not 'hdwr_type_new2' in request.REQUEST):
- failures.append('hdwr_type (#2)')
-
- if (not regex.macaddr.match(request.POST['mac_addr_new2'])
- and request.POST['mac_addr_new2']):
- failures.append('mac_addr (#2)')
-
- if (not regex.ipaddr.match(request.POST['ip_addr_new'])
- and request.POST['ip_addr_new']):
- failures.append('ip_addr (#1)')
- if (not regex. ipaddr.match(request.POST['ip_addr_new2'])
- and request.POST['ip_addr_new2']):
- failures.append('ip_addr (#2)')
-
- [failures.append('ip_addr (#1)') for number in
- request.POST['ip_addr_new'].split(".")
- if number.isdigit() and int(number) > 255
- and 'ip_addr (#1)' not in failures]
- [failures.append('ip_addr (#2)') for number in
- request.POST['ip_addr_new2'].split(".")
- if number.isdigit() and int(number) > 255
- and 'ip_addr (#2)' not in failures]
-
- elif host_id:
- interfaces = Interface.objects.filter(host=host_id)
- for interface in interfaces:
- if (not regex.macaddr.match(request.POST['mac_addr%d' % interface.id])
- and request.POST['mac_addr%d' % interface.id]):
- failures.append('mac_addr (%s)' % request.POST['mac_addr%d' % interface.id])
- for ip in interface.ip_set.all():
- if not regex.ipaddr.match(request.POST['ip_addr%d' % ip.id]):
- failures.append('ip_addr (%s)' % request.POST['ip_addr%d' % ip.id])
- [failures.append('ip_addr (%s)' % request.POST['ip_addr%d' % ip.id])
- for number in request.POST['ip_addr%d' % ip.id].split(".")
- if (number.isdigit() and int(number) > 255 and
- 'ip_addr (%s)' % request.POST['ip_addr%d' % ip.id] not in failures)]
- if (request.POST['%dip_addr' % interface.id]
- and not regex.ipaddr.match(request.POST['%dip_addr' % interface.id])):
- failures.append('ip_addr (%s)' % request.POST['%dip_addr' % interface.id])
- if (request.POST['mac_addr_new']
- and not regex.macaddr.match(request.POST['mac_addr_new'])):
- failures.append('mac_addr (%s)' % request.POST['mac_addr_new'])
- if (request.POST['ip_addr_new']
- and not regex.ipaddr.match(request.POST['ip_addr_new'])):
- failures.append('ip_addr (%s)' % request.POST['ip_addr_new'])
-
- if not failures:
- return 0
- return failures
-
-def do_log(text, attribute, previous, new):
- if previous != new:
- text += "%-20s%-20s -> %s\n" % (attribute, previous, new)
- return text
-
-## login required stuff
-## uncomment the views below that you would like to restrict access to
-
-## uncomment the lines below this point to restrict access to pages that modify the database
-## anonymous users can still view data in Hostbase
-
-edit = login_required(edit)
-confirm = login_required(confirm)
-dnsedit = login_required(dnsedit)
-new = login_required(new)
-copy = login_required(copy)
-#remove = login_required(remove)
-#zoneedit = login_required(zoneedit)
-#zonenew = login_required(zonenew)
-
-## uncomment the lines below this point to restrict access to all of hostbase
-
-## search = login_required(search)
-## look = login_required(look)
-## dns = login_required(dns)
-## zones = login_required(zones)
-## zoneview = login_required(zoneview)
-
diff --git a/build/lib/Bcfg2/Server/Hostbase/ldapauth.py b/build/lib/Bcfg2/Server/Hostbase/ldapauth.py
deleted file mode 100644
index f2148181f..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/ldapauth.py
+++ /dev/null
@@ -1,172 +0,0 @@
-"""Checks with LDAP (ActiveDirectory) to see if the current user is an LDAP(AD) user,
-and returns a subset of the user's profile that is needed by Argonne/CIS to
-to set user level privleges in Django"""
-
-__revision__ = '$Revision: 2456 $'
-
-import os
-import ldap
-
-class LDAPAUTHError(Exception):
- """LDAPAUTHError is raised when somehting goes boom."""
- pass
-
-class ldapauth(object):
- group_test = False
- check_member_of = os.environ['LDAP_CHECK_MBR_OF_GRP']
- securitylevel = 0
- distinguishedName = None
- sAMAccountName = None
- telephoneNumber = None
- title = None
- memberOf = None
- department = None #this will be a list
- mail = None
- extensionAttribute1 = None #badgenumber
- badge_no = None
-
- def __init__(self,login,passwd):
- """get username (if using ldap as auth the
- apache env var REMOTE_USER should be used)
- from username get user profile from AD/LDAP
- """
- #p = self.user_profile(login,passwd)
- d = self.user_dn(login) #success, distname
- print d[1]
- if d[0] == 'success':
- pass
- p = self.user_bind(d[1],passwd)
- if p[0] == 'success':
- #parse results
- parsed = self.parse_results(p[2])
- print self.department
- self.group_test = self.member_of()
- securitylevel = self.security_level()
- print "ACCESS LEVEL: " + str(securitylevel)
- else:
- raise LDAPAUTHError(p[2])
- else:
- raise LDAPAUTHError(p[2])
-
- def user_profile(self,login,passwd=None):
- """NOT USED RIGHT NOW"""
- ldap_login = "CN=%s" % login
- svc_acct = os.environ['LDAP_SVC_ACCT_NAME']
- svc_pass = os.environ['LDAP_SVC_ACCT_PASS']
- #svc_acct = 'CN=%s,DC=anl,DC=gov' % login
- #svc_pass = passwd
-
- search_pth = os.environ['LDAP_SEARCH_PTH']
-
- try:
- conn = ldap.initialize(os.environ['LDAP_URI'])
- conn.bind(svc_acct,svc_pass,ldap.AUTH_SIMPLE)
- result_id = conn.search(search_pth,
- ldap.SCOPE_SUBTREE,
- ldap_login,None)
- result_type,result_data = conn.result(result_id,0)
- return ('success','User profile found',result_data,)
- except ldap.LDAPError,e:
- #connection failed
- return ('error','LDAP connect failed',e,)
-
- def user_bind(self,distinguishedName,passwd):
- """Binds to LDAP Server"""
- search_pth = os.environ['LDAP_SEARCH_PTH']
- try:
- conn = ldap.initialize(os.environ['LDAP_URI'])
- conn.bind(distinguishedName,passwd,ldap.AUTH_SIMPLE)
- cn = distinguishedName.split(",")
- result_id = conn.search(search_pth,
- ldap.SCOPE_SUBTREE,
- cn[0],None)
- result_type,result_data = conn.result(result_id,0)
- return ('success','User profile found',result_data,)
- except ldap.LDAPError,e:
- #connection failed
- return ('error','LDAP connect failed',e,)
-
- def user_dn(self,cn):
- """Uses Service Account to get distinguishedName"""
- ldap_login = "CN=%s" % cn
- svc_acct = os.environ['LDAP_SVC_ACCT_NAME']
- svc_pass = os.environ['LDAP_SVC_ACCT_PASS']
- search_pth = os.environ['LDAP_SEARCH_PTH']
-
- try:
- conn = ldap.initialize(os.environ['LDAP_URI'])
- conn.bind(svc_acct,svc_pass,ldap.AUTH_SIMPLE)
- result_id = conn.search(search_pth,
- ldap.SCOPE_SUBTREE,
- ldap_login,None)
- result_type,result_data = conn.result(result_id,0)
- raw_obj = result_data[0][1]
- distinguishedName = raw_obj['distinguishedName']
- return ('success',distinguishedName[0],)
- except ldap.LDAPError,e:
- #connection failed
- return ('error','LDAP connect failed',e,)
-
- def parse_results(self,user_obj):
- """Clean up the huge ugly object handed to us in the LDAP query"""
- #user_obj is a list formatted like this:
- #[('LDAP_DN',{user_dict},),]
- try:
- raw_obj = user_obj[0][1]
- self.memberOf = raw_obj['memberOf']
- self.sAMAccountName = raw_obj['sAMAccountName'][0]
- self.distinguishedName = raw_obj['distinguishedName'][0]
- self.telephoneNumber = raw_obj['telephoneNumber'][0]
- self.title = raw_obj['title'][0]
- self.department = raw_obj['department'][0]
- self.mail = raw_obj['mail'][0]
- self.badge_no = raw_obj['extensionAttribute1'][0]
- self.email = raw_obj['extensionAttribute2'][0]
- display_name = raw_obj['displayName'][0].split(",")
- self.name_f = raw_obj['givenName'][0]
- self.name_l = display_name[0]
- self.is_staff = False
- self.is_superuser = False
-
- return
- except KeyError, e:
- raise LDAPAUTHError("Portions of the LDAP User profile not present")
-
- def member_of(self):
- """See if this user is in our group that is allowed to login"""
- m = [g for g in self.memberOf if g == self.check_member_of]
- #print m
- if len(m) == 1:
- return True
- else:
- return False
-
- def security_level(self):
- level = self.securitylevel
-
- user = os.environ['LDAP_GROUP_USER']
- m = [g for g in self.memberOf if g == user]
- if len(m) == 1:
- if level < 1:
- level = 1
-
- cspr = os.environ['LDAP_GROUP_SECURITY_LOW']
- m = [g for g in self.memberOf if g == cspr]
- if len(m) == 1:
- if level < 2:
- level = 2
-
- cspo = os.environ['LDAP_GROUP_SECURITY_HIGH']
- m = [g for g in self.memberOf if g == cspo]
- if len(m) == 1:
- if level < 3:
- level = 3
-
- admin = os.environ['LDAP_GROUP_ADMIN']
- m = [g for g in self.memberOf if g == admin]
- if len(m) == 1:
- if level < 4:
- level = 4
-
- return level
-
diff --git a/build/lib/Bcfg2/Server/Hostbase/manage.py b/build/lib/Bcfg2/Server/Hostbase/manage.py
deleted file mode 100644
index 5e78ea979..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/manage.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-from django.core.management import execute_manager
-try:
- import settings # Assumed to be in the same directory.
-except ImportError:
- import sys
- sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
- sys.exit(1)
-
-if __name__ == "__main__":
- execute_manager(settings)
diff --git a/build/lib/Bcfg2/Server/Hostbase/nisauth.py b/build/lib/Bcfg2/Server/Hostbase/nisauth.py
deleted file mode 100644
index 9c7da8c0a..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/nisauth.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import os
-import crypt, nis
-from Bcfg2.Server.Hostbase.settings import AUTHORIZED_GROUP
-
-"""Checks with NIS to see if the current user is in the support group"""
-
-__revision__ = "$Revision: $"
-
-class NISAUTHError(Exception):
- """NISAUTHError is raised when somehting goes boom."""
- pass
-
-class nisauth(object):
- group_test = False
-# check_member_of = os.environ['LDAP_CHECK_MBR_OF_GRP']
- samAcctName = None
- distinguishedName = None
- sAMAccountName = None
- telephoneNumber = None
- title = None
- memberOf = None
- department = None #this will be a list
- mail = None
- extensionAttribute1 = None #badgenumber
- badge_no = None
- uid = None
-
- def __init__(self,login,passwd=None):
- """get user profile from NIS"""
- try:
- p = nis.match(login, 'passwd.byname').split(":")
- except:
- raise NISAUTHError('username')
- # check user password using crypt and 2 character salt from passwd file
- if p[1] == crypt.crypt(passwd, p[1][:2]):
- # check to see if user is in valid support groups
- # will have to include these groups in a settings file eventually
- if not login in nis.match(AUTHORIZED_GROUP, 'group.byname').split(':')[-1].split(',') and p[3] != nis.match(AUTHORIZED_GROUP, 'group.byname').split(':')[2]:
- raise NISAUTHError('group')
- self.uid = p[2]
- else:
- raise NISAUTHError('password')
diff --git a/build/lib/Bcfg2/Server/Hostbase/regex.py b/build/lib/Bcfg2/Server/Hostbase/regex.py
deleted file mode 100644
index 41cc0f6f0..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/regex.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import re
-
-date = re.compile('^[0-9]{4}-[0-9]{2}-[0-9]{2}$')
-host = re.compile('^[a-z0-9-_]+(\.[a-z0-9-_]+)+$')
-macaddr = re.compile('^[0-9abcdefABCDEF]{2}(:[0-9abcdefABCDEF]{2}){5}$|virtual')
-ipaddr = re.compile('^[0-9]{1,3}(\.[0-9]{1,3}){3}$')
diff --git a/build/lib/Bcfg2/Server/Hostbase/settings.py b/build/lib/Bcfg2/Server/Hostbase/settings.py
deleted file mode 100644
index a42fd5b2e..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/settings.py
+++ /dev/null
@@ -1,142 +0,0 @@
-from ConfigParser import ConfigParser, NoSectionError, NoOptionError
-import os.path
-
-PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
-
-c = ConfigParser()
-#This needs to be configurable one day somehow
-c.read(['./bcfg2.conf'])
-
-defaults = {'database_engine':'sqlite3',
- 'database_name':'./dev.db',
- 'database_user':'',
- 'database_password':'',
- 'database_host':'',
- 'database_port':3306,
- 'default_mx':'localhost',
- 'priority':10,
- 'authorized_group':'admins',
- }
-
-if c.has_section('hostbase'):
- options = dict(c.items('hostbase'))
-else:
- options = defaults
-
-# Django settings for Hostbase project.
-DEBUG = True
-TEMPLATE_DEBUG = DEBUG
-ADMINS = (
- # ('Your Name', 'your_email@domain.com'),
-)
-MANAGERS = ADMINS
-
-# 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
-DATABASE_ENGINE = options['database_engine']
-# Or path to database file if using sqlite3.
-DATABASE_NAME = options['database_name']
-# Not used with sqlite3.
-DATABASE_USER = options['database_user']
-# Not used with sqlite3.
-DATABASE_PASSWORD = options['database_password']
-# Set to empty string for localhost. Not used with sqlite3.
-DATABASE_HOST = options['database_host']
-# Set to empty string for default. Not used with sqlite3.
-DATABASE_PORT = int(options['database_port'])
-# Local time zone for this installation. All choices can be found here:
-# http://docs.djangoproject.com/en/dev/ref/settings/#time-zone
-try:
- TIME_ZONE = c.get('statistics', 'time_zone')
-except:
- TIME_ZONE = None
-
-# enter the defauly MX record machines will get in Hostbase
-# this setting may move elsewhere eventually
-DEFAULT_MX = options['default_mx']
-PRIORITY = int(options['priority'])
-
-SESSION_EXPIRE_AT_BROWSER_CLOSE = True
-
-# Uncomment a backend below if you would like to use it for authentication
-AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
- 'Bcfg2.Server.Hostbase.backends.NISBackend',
- #'Bcfg2.Server.Hostbase.backends.LDAPBacken',
- )
-# enter an NIS group name you'd like to give access to edit hostbase records
-AUTHORIZED_GROUP = options['authorized_group']
-
-#create login url area:
-import django.contrib.auth
-django.contrib.auth.LOGIN_URL = '/login'
-# Absolute path to the directory that holds media.
-# Example: "/home/media/media.lawrence.com/"
-MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')
-# Just for development
-SERVE_MEDIA = DEBUG
-
-# Language code for this installation. All choices can be found here:
-# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
-# http://blogs.law.harvard.edu/tech/stories/storyReader$15
-LANGUAGE_CODE = 'en-us'
-SITE_ID = 1
-# URL that handles the media served from MEDIA_ROOT.
-# Example: "http://media.lawrence.com"
-MEDIA_URL = '/site_media/'
-# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
-# trailing slash.
-# Examples: "http://foo.com/media/", "/media/".
-ADMIN_MEDIA_PREFIX = '/media/'
-# Make this unique, and don't share it with anybody.
-SECRET_KEY = '*%=fv=yh9zur&gvt4&*d#84o(cy^-*$ox-v1e9%32pzf2*qu#s'
-# List of callables that know how to import templates from various sources.
-TEMPLATE_LOADERS = (
- 'django.template.loaders.filesystem.load_template_source',
- 'django.template.loaders.app_directories.load_template_source',
-# 'django.template.loaders.eggs.load_template_source',
-)
-
-TEMPLATE_CONTEXT_PROCESSORS = (
- "django.core.context_processors.auth",
- "django.core.context_processors.debug",
- "django.core.context_processors.i18n",
- "django.core.context_processors.request",
- "django.core.context_processors.media",
-# Django development version.
-# "django.core.context_processors.csrf",
-)
-
-
-MIDDLEWARE_CLASSES = (
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.locale.LocaleMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.middleware.doc.XViewMiddleware',
-)
-
-ROOT_URLCONF = 'Bcfg2.Server.Hostbase.urls'
-
-TEMPLATE_DIRS = (
- # Put strings here, like "/home/html/django_templates".
- # Always use forward slashes, even on Windows.
- '/usr/lib/python2.3/site-packages/Bcfg2/Server/Hostbase/hostbase/webtemplates',
- '/usr/lib/python2.4/site-packages/Bcfg2/Server/Hostbase/hostbase/webtemplates',
- '/usr/lib/python2.3/site-packages/Bcfg2/Server/Hostbase/templates',
- '/usr/lib/python2.4/site-packages/Bcfg2/Server/Hostbase/templates',
- '/usr/share/bcfg2/Hostbase/templates',
- os.path.join(PROJECT_ROOT, 'templates'),
- os.path.join(PROJECT_ROOT, 'hostbase/webtemplates'),
-)
-
-INSTALLED_APPS = (
- 'django.contrib.admin',
- 'django.contrib.admindocs',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.sites',
- 'django.contrib.humanize',
- 'Bcfg2.Server.Hostbase.hostbase',
-)
-
-LOGIN_URL = '/login/'
diff --git a/build/lib/Bcfg2/Server/Hostbase/urls.py b/build/lib/Bcfg2/Server/Hostbase/urls.py
deleted file mode 100644
index 01fe97d4f..000000000
--- a/build/lib/Bcfg2/Server/Hostbase/urls.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from django.conf.urls.defaults import *
-from django.conf import settings
-from django.views.generic.simple import direct_to_template
-from django.contrib import admin
-
-
-admin.autodiscover()
-
-
-urlpatterns = patterns('',
- # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
- # to INSTALLED_APPS to enable admin documentation:
- (r'^admin/doc/', include('django.contrib.admindocs.urls')),
-
- # Uncomment the next line to enable the admin:
- (r'^admin/', include(admin.site.urls)),
-
- (r'^$',direct_to_template, {'template':'index.html'}, 'index'),
- (r'^hostbase/', include('hostbase.urls')),
- (r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
- (r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'})
-)
-
-if settings.SERVE_MEDIA:
- urlpatterns += patterns('',
- (r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
- dict(document_root=settings.MEDIA_ROOT)),)
diff --git a/build/lib/Bcfg2/Server/Plugin.py b/build/lib/Bcfg2/Server/Plugin.py
deleted file mode 100644
index 95569e3ac..000000000
--- a/build/lib/Bcfg2/Server/Plugin.py
+++ /dev/null
@@ -1,886 +0,0 @@
-"""This module provides the baseclass for Bcfg2 Server Plugins."""
-__revision__ = '$Revision$'
-
-import copy
-import logging
-import lxml.etree
-import os
-import pickle
-import posixpath
-import re
-import Queue
-import threading
-
-from lxml.etree import XML, XMLSyntaxError
-
-import Bcfg2.Options
-
-# grab default metadata info from bcfg2.conf
-opts = {'owner': Bcfg2.Options.MDATA_OWNER,
- 'group': Bcfg2.Options.MDATA_GROUP,
- 'important': Bcfg2.Options.MDATA_IMPORTANT,
- 'perms': Bcfg2.Options.MDATA_PERMS,
- 'paranoid': Bcfg2.Options.MDATA_PARANOID}
-mdata_setup = Bcfg2.Options.OptionParser(opts)
-mdata_setup.parse([])
-del mdata_setup['args']
-
-logger = logging.getLogger('Bcfg2.Plugin')
-
-default_file_metadata = mdata_setup
-
-info_regex = re.compile( \
- 'encoding:(\s)*(?P<encoding>\w+)|' +
- 'group:(\s)*(?P<group>\S+)|' +
- 'important:(\s)*(?P<important>\S+)|' +
- 'mtime:(\s)*(?P<mtime>\w+)|' +
- 'owner:(\s)*(?P<owner>\S+)|' +
- 'paranoid:(\s)*(?P<paranoid>\S+)|' +
- 'perms:(\s)*(?P<perms>\w+)|')
-
-class PluginInitError(Exception):
- """Error raised in cases of Plugin initialization errors."""
- pass
-
-class PluginExecutionError(Exception):
- """Error raised in case of Plugin execution errors."""
- pass
-
-class Plugin(object):
- """This is the base class for all Bcfg2 Server plugins.
- Several attributes must be defined in the subclass:
- name : the name of the plugin
- __version__ : a version string
- __author__ : the author/contact for the plugin
-
- Plugins can provide three basic types of functionality:
- - Structure creation (overloading BuildStructures)
- - Configuration entry binding (overloading HandlesEntry, or loads the Entries table)
- - Data collection (overloading GetProbes/ReceiveData)
- """
- name = 'Plugin'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- __rmi__ = ['toggle_debug']
- experimental = False
- deprecated = False
- conflicts = []
-
- def __init__(self, core, datastore):
- object.__init__(self)
- self.Entries = {}
- self.core = core
- self.data = "%s/%s" % (datastore, self.name)
- self.logger = logging.getLogger('Bcfg2.Plugins.%s' % (self.name))
- self.running = True
- self.debug_flag = False
-
- def toggle_debug(self):
- self.debug_flag = not self.debug_flag
-
- def debug_log(self, message, flag=None):
- if (flag is None) and self.debug_flag or flag:
- self.logger.error(message)
-
- @classmethod
- def init_repo(cls, repo):
- path = "%s/%s" % (repo, cls.name)
- os.makedirs(path)
-
- def shutdown(self):
- self.running = False
-
-class Generator(object):
- """Generator plugins contribute to literal client configurations."""
- def HandlesEntry(self, entry, metadata):
- """This is the slow path method for routing configuration binding requests."""
- return False
-
- def HandleEntry(self, entry, metadata):
- """This is the slow-path handler for configuration entry binding."""
- raise PluginExecutionError
-
-class Structure(object):
- """Structure Plugins contribute to abstract client configurations."""
- def BuildStructures(self, metadata):
- """Return a list of abstract goal structures for client."""
- raise PluginExecutionError
-
-class Metadata(object):
- """Signal metadata capabilities for this plugin"""
- def add_client(self, client_name, attribs):
- """Add client."""
- pass
- def remove_client(self, client_name):
- """Remove client."""
- pass
- def viz(self, hosts, bundles, key, colors):
- """Create viz str for viz admin mode."""
- pass
-
- def get_initial_metadata(self, client_name):
- raise PluginExecutionError
-
- def merge_additional_data(self, imd, source, groups, data):
- raise PluginExecutionError
-
-class Connector(object):
- """Connector Plugins augment client metadata instances."""
- def get_additional_groups(self, metadata):
- """Determine additional groups for metadata."""
- return list()
-
- def get_additional_data(self, metadata):
- """Determine additional data for metadata instances."""
- return dict()
-
-class Probing(object):
- """Signal probe capability for this plugin."""
- def GetProbes(self, _):
- """Return a set of probes for execution on client."""
- return []
-
- def ReceiveData(self, _, dummy):
- """Receive probe results pertaining to client."""
- pass
-
-class Statistics(object):
- """Signal statistics handling capability."""
- def process_statistics(self, client, xdata):
- pass
-
-class ThreadedStatistics(Statistics,
- threading.Thread):
- """Threaded statistics handling capability."""
- def __init__(self, core, datastore):
- Statistics.__init__(self)
- threading.Thread.__init__(self)
- # Event from the core signaling an exit
- self.terminate = core.terminate
- self.work_queue = Queue.Queue(100000)
- self.pending_file = "%s/etc/%s.pending" % (datastore, self.__class__.__name__)
- self.daemon = True
- self.start()
-
- def save(self):
- """Save any pending data to a file."""
- pending_data = []
- try:
- while not self.work_queue.empty():
- (metadata, data) = self.work_queue.get_nowait()
- try:
- pending_data.append( ( metadata.hostname, lxml.etree.tostring(data) ) )
- except:
- self.logger.warning("Dropping interaction for %s" % metadata.hostname)
- except Queue.Empty:
- pass
-
- try:
- savefile = open(self.pending_file, 'w')
- pickle.dump(pending_data, savefile)
- savefile.close()
- self.logger.info("Saved pending %s data" % self.__class__.__name__)
- except:
- self.logger.warning("Failed to save pending data")
-
- def load(self):
- """Load any pending data to a file."""
- if not os.path.exists(self.pending_file):
- return True
- pending_data = []
- try:
- savefile = open(self.pending_file, 'r')
- pending_data = pickle.load(savefile)
- savefile.close()
- except Exception, e:
- self.logger.warning("Failed to load pending data: %s" % e)
- for (pmetadata, pdata) in pending_data:
- # check that shutdown wasnt called early
- if self.terminate.isSet():
- return False
-
- try:
- while True:
- try:
- metadata = self.core.build_metadata(pmetadata)
- break
- except Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError:
- pass
-
- self.terminate.wait(5)
- if self.terminate.isSet():
- return False
-
- self.work_queue.put_nowait( (metadata, lxml.etree.fromstring(pdata)) )
- except Queue.Full:
- self.logger.warning("Queue.Full: Failed to load queue data")
- break
- except lxml.etree.LxmlError, lxml_error:
- self.logger.error("Unable to load save interaction: %s" % lxml_error)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- self.logger.error("Unable to load metadata for save interaction: %s" % pmetadata)
- try:
- os.unlink(self.pending_file)
- except:
- self.logger.error("Failed to unlink save file: %s" % self.pending_file)
- self.logger.info("Loaded pending %s data" % self.__class__.__name__)
- return True
-
- def run(self):
- if not self.load():
- return
- while not self.terminate.isSet():
- try:
- (xdata, client) = self.work_queue.get(block=True, timeout=2)
- except Queue.Empty:
- continue
- except Exception, e:
- self.logger.error("ThreadedStatistics: %s" % e)
- continue
- self.handle_statistic(xdata, client)
- if not self.work_queue.empty():
- self.save()
-
- def process_statistics(self, metadata, data):
- warned = False
- try:
- self.work_queue.put_nowait((metadata, copy.deepcopy(data)))
- warned = False
- except Queue.Full:
- if not warned:
- self.logger.warning("%s: Queue is full. Dropping interactions." % self.__class__.__name__)
- warned = True
-
- def handle_statistics(self, metadata, data):
- """Handle stats here."""
- pass
-
-class PullSource(object):
- def GetExtra(self, client):
- return []
-
- def GetCurrentEntry(self, client, e_type, e_name):
- raise PluginExecutionError
-
-class PullTarget(object):
- def AcceptChoices(self, entry, metadata):
- raise PluginExecutionError
-
- def AcceptPullData(self, specific, new_entry, verbose):
- """This is the null per-plugin implementation
- of bcfg2-admin pull."""
- raise PluginExecutionError
-
-class Decision(object):
- """Signal decision handling capability."""
- def GetDecisions(self, metadata, mode):
- return []
-
-class ValidationError(Exception):
- pass
-
-class StructureValidator(object):
- """Validate/modify goal structures."""
- def validate_structures(self, metadata, structures):
- raise ValidationError, "not implemented"
-
-class GoalValidator(object):
- """Validate/modify configuration goals."""
- def validate_goals(self, metadata, goals):
- raise ValidationError, "not implemented"
-
-class Version(object):
- """Interact with various version control systems."""
- def get_revision(self):
- return []
- def commit_data(self):
- pass
-
-# the rest of the file contains classes for coherent file caching
-
-class FileBacked(object):
- """This object caches file data in memory.
- HandleEvent is called whenever fam registers an event.
- Index can parse the data into member data as required.
- This object is meant to be used as a part of DirectoryBacked.
- """
-
- def __init__(self, name):
- object.__init__(self)
- self.data = ''
- self.name = name
-
- def HandleEvent(self, event=None):
- """Read file upon update."""
- if event and event.code2str() not in ['exists', 'changed', 'created']:
- return
- try:
- self.data = file(self.name).read()
- self.Index()
- except IOError:
- logger.error("Failed to read file %s" % (self.name))
-
- def Index(self):
- """Update local data structures based on current file state"""
- pass
-
-class DirectoryBacked(object):
- """This object is a coherent cache for a filesystem hierarchy of files."""
- __child__ = FileBacked
- patterns = re.compile('.*')
-
- def __init__(self, name, fam):
- object.__init__(self)
- self.name = name
- self.fam = fam
- self.entries = {}
- self.inventory = False
- fam.AddMonitor(name, self)
-
- def __getitem__(self, key):
- return self.entries[key]
-
- def __iter__(self):
- return self.entries.iteritems()
-
- def AddEntry(self, name):
- """Add new entry to data structures upon file creation."""
- if name == '':
- logger.info("got add for empty name")
- elif name in self.entries:
- self.entries[name].HandleEvent()
- else:
- if ((name[-1] == '~') or
- (name[:2] == '.#') or
- (name[-4:] == '.swp') or
- (name in ['SCCS', '.svn'])):
- return
- if not self.patterns.match(name):
- return
- self.entries[name] = self.__child__('%s/%s' % (self.name, name))
- self.entries[name].HandleEvent()
-
- def HandleEvent(self, event):
- """Propagate fam events to underlying objects."""
- action = event.code2str()
- if event.filename == '':
- logger.info("Got event for blank filename")
- return
- if action == 'exists':
- if event.filename != self.name:
- self.AddEntry(event.filename)
- elif action == 'created':
- self.AddEntry(event.filename)
- elif action == 'changed':
- if event.filename in self.entries:
- self.entries[event.filename].HandleEvent(event)
- elif action == 'deleted':
- if event.filename in self.entries:
- del self.entries[event.filename]
- elif action in ['endExist']:
- pass
- else:
- print "Got unknown event %s %s %s" % (event.requestID,
- event.code2str(),
- event.filename)
-
-class XMLFileBacked(FileBacked):
- """
- This object is a coherent cache for an XML file to be used as a
- part of DirectoryBacked.
- """
- __identifier__ = 'name'
-
- def __init__(self, filename):
- self.label = "dummy"
- self.entries = []
- FileBacked.__init__(self, filename)
-
- def Index(self):
- """Build local data structures."""
- try:
- xdata = XML(self.data)
- except XMLSyntaxError:
- logger.error("Failed to parse %s"%(self.name))
- return
- self.label = xdata.attrib[self.__identifier__]
- self.entries = xdata.getchildren()
-
- def __iter__(self):
- return iter(self.entries)
-
-class SingleXMLFileBacked(XMLFileBacked):
- """This object is a coherent cache for an independent XML file."""
- def __init__(self, filename, fam):
- XMLFileBacked.__init__(self, filename)
- fam.AddMonitor(filename, self)
-
-class StructFile(XMLFileBacked):
- """This file contains a set of structure file formatting logic."""
- def __init__(self, name):
- XMLFileBacked.__init__(self, name)
- self.fragments = {}
-
- def Index(self):
- """Build internal data structures."""
- try:
- xdata = lxml.etree.XML(self.data)
- except lxml.etree.XMLSyntaxError:
- logger.error("Failed to parse file %s" % self.name)
- return
- self.fragments = {}
- work = {lambda x:True: xdata.getchildren()}
- while work:
- (predicate, worklist) = work.popitem()
- self.fragments[predicate] = [item for item in worklist if item.tag != 'Group'
- and not isinstance(item, lxml.etree._Comment)]
- for group in [item for item in worklist if item.tag == 'Group']:
- # if only python had forceable early-binding
- if group.get('negate', 'false') in ['true', 'True']:
- cmd = "lambda x:'%s' not in x.groups and predicate(x)"
- else:
- cmd = "lambda x:'%s' in x.groups and predicate(x)"
-
- newpred = eval(cmd % (group.get('name')), {'predicate':predicate})
- work[newpred] = group.getchildren()
-
- def Match(self, metadata):
- """Return matching fragments of independent."""
- matching = [frag for (pred, frag) in self.fragments.iteritems() if pred(metadata)]
- if matching:
- return reduce(lambda x, y:x+y, matching)
- logger.error("File %s got null match" % (self.name))
- return []
-
-class INode:
- """
- LNodes provide lists of things available at a particular
- group intersection.
- """
- raw = {'Client':"lambda x:'%s' == x.hostname and predicate(x)",
- 'Group':"lambda x:'%s' in x.groups and predicate(x)"}
- nraw = {'Client':"lambda x:'%s' != x.hostname and predicate(x)",
- 'Group':"lambda x:'%s' not in x.groups and predicate(x)"}
- containers = ['Group', 'Client']
- ignore = []
-
- def __init__(self, data, idict, parent=None):
- self.data = data
- self.contents = {}
- if parent == None:
- self.predicate = lambda x:True
- else:
- predicate = parent.predicate
- if data.get('negate', 'false') in ['true', 'True']:
- psrc = self.nraw
- else:
- psrc = self.raw
- if data.tag in psrc.keys():
- self.predicate = eval(psrc[data.tag] % (data.get('name')),
- {'predicate':predicate})
- else:
- raise Exception
- mytype = self.__class__
- self.children = []
- for item in data.getchildren():
- if item.tag in self.ignore:
- continue
- elif item.tag in self.containers:
- self.children.append(mytype(item, idict, self))
- else:
- try:
- self.contents[item.tag][item.get('name')] = item.attrib
- except KeyError:
- self.contents[item.tag] = {item.get('name'):item.attrib}
- if item.text:
- self.contents[item.tag]['__text__'] = item.text
- try:
- idict[item.tag].append(item.get('name'))
- except KeyError:
- idict[item.tag] = [item.get('name')]
-
- def Match(self, metadata, data):
- """Return a dictionary of package mappings."""
- if self.predicate(metadata):
- for key in self.contents:
- try:
- data[key].update(self.contents[key])
- except:
- data[key] = {}
- data[key].update(self.contents[key])
- for child in self.children:
- child.Match(metadata, data)
-
-class XMLSrc(XMLFileBacked):
- """XMLSrc files contain a LNode hierarchy that returns matching entries."""
- __node__ = INode
- __cacheobj__ = dict
-
- def __init__(self, filename, noprio=False):
- XMLFileBacked.__init__(self, filename)
- self.items = {}
- self.cache = None
- self.pnode = None
- self.priority = -1
- self.noprio = noprio
-
- def HandleEvent(self, _=None):
- """Read file upon update."""
- try:
- data = file(self.name).read()
- except IOError:
- logger.error("Failed to read file %s" % (self.name))
- return
- self.items = {}
- try:
- xdata = lxml.etree.XML(data)
- except lxml.etree.XMLSyntaxError:
- logger.error("Failed to parse file %s" % (self.name))
- return
- self.pnode = self.__node__(xdata, self.items)
- self.cache = None
- try:
- self.priority = int(xdata.get('priority'))
- except (ValueError, TypeError):
- if not self.noprio:
- logger.error("Got bogus priority %s for file %s" % (xdata.get('priority'), self.name))
- del xdata, data
-
- def Cache(self, metadata):
- """Build a package dict for a given host."""
- if self.cache == None or self.cache[0] != metadata:
- cache = (metadata, self.__cacheobj__())
- if self.pnode == None:
- logger.error("Cache method called early for %s; forcing data load" % (self.name))
- self.HandleEvent()
- return
- self.pnode.Match(metadata, cache[1])
- self.cache = cache
-
-class XMLDirectoryBacked(DirectoryBacked):
- """Directorybacked for *.xml."""
- patterns = re.compile('.*\.xml')
-
-class PrioDir(Plugin, Generator, XMLDirectoryBacked):
- """This is a generator that handles package assignments."""
- name = 'PrioDir'
- __child__ = XMLSrc
-
- def __init__(self, core, datastore):
- Plugin.__init__(self, core, datastore)
- Generator.__init__(self)
- try:
- XMLDirectoryBacked.__init__(self, self.data, self.core.fam)
- except OSError:
- self.logger.error("Failed to load %s indices" % (self.name))
- raise PluginInitError
-
- def HandleEvent(self, event):
- """Handle events and update dispatch table."""
- XMLDirectoryBacked.HandleEvent(self, event)
- self.Entries = {}
- for src in self.entries.values():
- for itype, children in src.items.iteritems():
- for child in children:
- try:
- self.Entries[itype][child] = self.BindEntry
- except KeyError:
- self.Entries[itype] = {child: self.BindEntry}
-
- def BindEntry(self, entry, metadata):
- """Check package lists of package entries."""
- [src.Cache(metadata) for src in self.entries.values()]
- name = entry.get('name')
- if not src.cache:
- self.logger.error("Called before data loaded")
- raise PluginExecutionError
- matching = [src for src in self.entries.values()
- if src.cache and entry.tag in src.cache[1]
- and src.cache[1][entry.tag].has_key(name)]
- if len(matching) == 0:
- raise PluginExecutionError
- elif len(matching) == 1:
- index = 0
- else:
- prio = [int(src.priority) for src in matching]
- if prio.count(max(prio)) > 1:
- self.logger.error("Found conflicting sources with "
- "same priority for %s, %s %s" %
- (metadata.hostname,
- entry.tag.lower(), entry.get('name')))
- self.logger.error([item.name for item in matching])
- self.logger.error("Priority was %s" % max(prio))
- raise PluginExecutionError
- index = prio.index(max(prio))
-
- data = matching[index].cache[1][entry.tag][name]
- if '__text__' in data:
- entry.text = data['__text__']
- if '__children__' in data:
- [entry.append(copy.deepcopy(item)) for item in data['__children__']]
- [entry.attrib.__setitem__(key, data[key]) for key in data.keys() \
- if not key.startswith('__')]
-
-# new unified EntrySet backend
-
-class SpecificityError(Exception):
- """Thrown in case of filename parse failure."""
- pass
-
-class Specificity:
-
- def __init__(self, all=False, group=False, hostname=False, prio=0, delta=False):
- self.hostname = hostname
- self.all = all
- self.group = group
- self.prio = prio
- self.delta = delta
-
- def matches(self, metadata):
- return self.all or \
- self.hostname == metadata.hostname or \
- self.group in metadata.groups
-
- def __cmp__(self, other):
- """Sort most to least specific."""
- if self.all:
- return 1
- if self.group:
- if other.hostname:
- return 1
- if other.group and other.prio > self.prio:
- return 1
- if other.group and other.prio == self.prio:
- return 0
- return -1
-
- def more_specific(self, other):
- """Test if self is more specific than other."""
- if self.all:
- True
- elif self.group:
- if other.hostname:
- return True
- elif other.group and other.prio > self.prio:
- return True
- return False
-
-class SpecificData(object):
- def __init__(self, name, specific, encoding):
- self.name = name
- self.specific = specific
-
- def handle_event(self, event):
- if event.code2str() == 'deleted':
- return
- try:
- self.data = open(self.name).read()
- except:
- logger.error("Failed to read file %s" % self.name)
-
-class EntrySet:
- """Entry sets deal with the host- and group-specific entries."""
- ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px]))$")
- def __init__(self, basename, path, entry_type, encoding):
- self.path = path
- self.entry_type = entry_type
- self.entries = {}
- self.metadata = default_file_metadata.copy()
- self.infoxml = None
- self.encoding = encoding
- pattern = '(.*/)?%s(\.((H_(?P<hostname>\S+))|' % basename
- pattern += '(G(?P<prio>\d+)_(?P<group>\S+))))?$'
- self.specific = re.compile(pattern)
-
- def get_matching(self, metadata):
- return [item for item in self.entries.values() \
- if item.specific.matches(metadata)]
-
- def handle_event(self, event):
- """Handle FAM events for the TemplateSet."""
- action = event.code2str()
-
- if event.filename in ['info', 'info.xml', ':info']:
- if action in ['exists', 'created', 'changed']:
- self.update_metadata(event)
- elif action == 'deleted':
- self.reset_metadata(event)
- return
-
- if action in ['exists', 'created']:
- self.entry_init(event)
- else:
- if event.filename not in self.entries:
- return
- if action == 'changed':
- self.entries[event.filename].handle_event(event)
- elif action == 'deleted':
- del self.entries[event.filename]
-
- def entry_init(self, event):
- """Handle template and info file creation."""
- if event.filename in self.entries:
- logger.warn("Got duplicate add for %s" % event.filename)
- else:
- fpath = "%s/%s" % (self.path, event.filename)
- try:
- spec = self.specificity_from_filename(event.filename)
- except SpecificityError:
- if not self.ignore.match(event.filename):
- logger.error("Could not process filename %s; ignoring" % fpath)
- return
- self.entries[event.filename] = self.entry_type(fpath,
- spec, self.encoding)
- self.entries[event.filename].handle_event(event)
-
- def specificity_from_filename(self, fname):
- """Construct a specificity instance from a filename and regex."""
- data = self.specific.match(fname)
- if not data:
- raise SpecificityError(fname)
- kwargs = {}
- if data.group('hostname'):
- kwargs['hostname'] = data.group('hostname')
- elif data.group('group'):
- kwargs['group'] = data.group('group')
- kwargs['prio'] = int(data.group('prio'))
- else:
- kwargs['all'] = True
- if 'delta' in data.groupdict():
- kwargs['delta'] = data.group('delta')
- return Specificity(**kwargs)
-
- def update_metadata(self, event):
- """Process info and info.xml files for the templates."""
- fpath = "%s/%s" % (self.path, event.filename)
- if event.filename == 'info.xml':
- if not self.infoxml:
- self.infoxml = XMLSrc(fpath, True)
- self.infoxml.HandleEvent(event)
- elif event.filename in [':info', 'info']:
- for line in open(fpath).readlines():
- match = info_regex.match(line)
- if not match:
- logger.warning("Failed to match line: %s"%line)
- continue
- else:
- mgd = match.groupdict()
- for key, value in mgd.iteritems():
- if value:
- self.metadata[key] = value
- if len(self.metadata['perms']) == 3:
- self.metadata['perms'] = "0%s" % \
- (self.metadata['perms'])
-
- def reset_metadata(self, event):
- """Reset metadata to defaults if info or info.xml removed."""
- if event.filename == 'info.xml':
- self.infoxml = None
- elif event.filename == 'info':
- self.metadata = default_file_metadata.copy()
-
- def group_sortfunc(self, x, y):
- """sort groups by their priority"""
- return cmp(x.specific.prio, y.specific.prio)
-
- def bind_info_to_entry(self, entry, metadata):
- if not self.infoxml:
- for key in self.metadata:
- entry.set(key, self.metadata[key])
- else:
- mdata = {}
- self.infoxml.pnode.Match(metadata, mdata)
- if 'Info' not in mdata:
- logger.error("Failed to set metadata for file %s" % \
- (entry.get('name')))
- raise PluginExecutionError
- [entry.attrib.__setitem__(key, value) \
- for (key, value) in mdata['Info'][None].iteritems()]
-
- def bind_entry(self, entry, metadata):
- """Return the appropriate interpreted template from the set of available templates."""
- self.bind_info_to_entry(entry, metadata)
- matching = self.get_matching(metadata)
-
- hspec = [ent for ent in matching if ent.specific.hostname]
- if hspec:
- return hspec[0].bind_entry(entry, metadata)
-
- gspec = [ent for ent in matching if ent.specific.group]
- if gspec:
- gspec.sort(self.group_sortfunc)
- return gspec[-1].bind_entry(entry, metadata)
-
- aspec = [ent for ent in matching if ent.specific.all]
- if aspec:
- return aspec[0].bind_entry(entry, metadata)
-
- raise PluginExecutionError
-
-class GroupSpool(Plugin, Generator):
- """Unified interface for handling group-specific data (e.g. .G## files)."""
- name = 'GroupSpool'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- filename_pattern = ""
- es_child_cls = object
- es_cls = EntrySet
-
- def __init__(self, core, datastore):
- Plugin.__init__(self, core, datastore)
- Generator.__init__(self)
- if self.data[-1] == '/':
- self.data = self.data[:-1]
- self.Entries['Path'] = {}
- self.entries = {}
- self.handles = {}
- self.AddDirectoryMonitor('')
- self.encoding = core.encoding
-
- def HandleEvent(self, event):
- """Unified FAM event handler for DirShadow."""
- action = event.code2str()
- if event.filename[0] == '/':
- return
- epath = "".join([self.data, self.handles[event.requestID],
- event.filename])
- if posixpath.isdir(epath):
- ident = self.handles[event.requestID] + event.filename
- else:
- ident = self.handles[event.requestID][:-1]
-
- if action in ['exists', 'created']:
- if posixpath.isdir(epath):
- self.AddDirectoryMonitor(epath[len(self.data):])
- if ident not in self.entries and posixpath.isfile(epath):
- dirpath = "".join([self.data, ident])
- self.entries[ident] = self.es_cls(self.filename_pattern,
- dirpath,
- self.es_child_cls,
- self.encoding)
- self.Entries['Path'][ident] = self.entries[ident].bind_entry
- if not posixpath.isdir(epath):
- # do not pass through directory events
- self.entries[ident].handle_event(event)
- if action == 'changed':
- self.entries[ident].handle_event(event)
- elif action == 'deleted':
- fbase = self.handles[event.requestID] + event.filename
- if fbase in self.entries:
- # a directory was deleted
- del self.entries[fbase]
- del self.Entries['Path'][fbase]
- else:
- self.entries[ident].handle_event(event)
-
- def AddDirectoryMonitor(self, relative):
- """Add new directory to FAM structures."""
- if not relative.endswith('/'):
- relative += '/'
- name = self.data + relative
- if relative not in self.handles.values():
- if not posixpath.isdir(name):
- print "Failed to open directory %s" % (name)
- return
- reqid = self.core.fam.AddMonitor(name, self)
- self.handles[reqid] = relative
diff --git a/build/lib/Bcfg2/Server/Plugins/Account.py b/build/lib/Bcfg2/Server/Plugins/Account.py
deleted file mode 100644
index e3ea58761..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Account.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""This handles authentication setup."""
-__revision__ = '$Revision$'
-
-import Bcfg2.Server.Plugin
-
-class Account(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Generator):
- """This module generates account config files,
- based on an internal data repo:
- static.(passwd|group|limits.conf) -> static entries
- dyn.(passwd|group) -> dynamic entries (usually acquired from yp or somesuch)
- useraccess -> users to be granted login access on some hosts
- superusers -> users to be granted root privs on all hosts
- rootlike -> users to be granted root privs on some hosts
-
- """
- name = 'Account'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- self.Entries = {'ConfigFile':{'/etc/passwd':self.from_yp_cb,
- '/etc/group':self.from_yp_cb,
- '/etc/security/limits.conf':self.gen_limits_cb,
- '/root/.ssh/authorized_keys':self.gen_root_keys_cb,
- '/etc/sudoers':self.gen_sudoers}}
- try:
- self.repository = Bcfg2.Server.Plugin.DirectoryBacked(self.data, self.core.fam)
- except:
- self.logger.error("Failed to load repos: %s, %s" % \
- (self.data, "%s/ssh" % (self.data)))
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def from_yp_cb(self, entry, metadata):
- """Build password file from cached yp data."""
- fname = entry.attrib['name'].split('/')[-1]
- entry.text = self.repository.entries["static.%s" % (fname)].data
- entry.text += self.repository.entries["dyn.%s" % (fname)].data
- perms = {'owner':'root', 'group':'root', 'perms':'0644'}
- [entry.attrib.__setitem__(key, value) for (key, value) in \
- perms.iteritems()]
-
- def gen_limits_cb(self, entry, metadata):
- """Build limits entries based on current ACLs."""
- entry.text = self.repository.entries["static.limits.conf"].data
- superusers = self.repository.entries["superusers"].data.split()
- useraccess = [line.split(':') for line in \
- self.repository.entries["useraccess"].data.split()]
- users = [user for (user, host) in \
- useraccess if host == metadata.hostname.split('.')[0]]
- perms = {'owner':'root', 'group':'root', 'perms':'0600'}
- [entry.attrib.__setitem__(key, value) for (key, value) in \
- perms.iteritems()]
- entry.text += "".join(["%s hard maxlogins 1024\n" % uname for uname in superusers + users])
- if "*" not in users:
- entry.text += "* hard maxlogins 0\n"
-
- def gen_root_keys_cb(self, entry, metadata):
- """Build root authorized keys file based on current ACLs."""
- superusers = self.repository.entries['superusers'].data.split()
- try:
- rootlike = [line.split(':', 1) for line in \
- self.repository.entries['rootlike'].data.split()]
- superusers += [user for (user, host) in rootlike \
- if host == metadata.hostname.split('.')[0]]
- except:
- pass
- rdata = self.repository.entries
- entry.text = "".join([rdata["%s.key" % user].data for user \
- in superusers if \
- ("%s.key" % user) in rdata])
- perms = {'owner':'root', 'group':'root', 'perms':'0600'}
- [entry.attrib.__setitem__(key, value) for (key, value) \
- in perms.iteritems()]
-
- def gen_sudoers(self, entry, metadata):
- """Build root authorized keys file based on current ACLs."""
- superusers = self.repository.entries['superusers'].data.split()
- try:
- rootlike = [line.split(':', 1) for line in \
- self.repository.entries['rootlike'].data.split()]
- superusers += [user for (user, host) in rootlike \
- if host == metadata.hostname.split('.')[0]]
- except:
- pass
- entry.text = self.repository.entries['static.sudoers'].data
- entry.text += "".join(["%s ALL=(ALL) ALL\n" % uname \
- for uname in superusers])
- perms = {'owner':'root', 'group':'root', 'perms':'0440'}
- [entry.attrib.__setitem__(key, value) for (key, value) \
- in perms.iteritems()]
diff --git a/build/lib/Bcfg2/Server/Plugins/BB.py b/build/lib/Bcfg2/Server/Plugins/BB.py
deleted file mode 100644
index 137142b66..000000000
--- a/build/lib/Bcfg2/Server/Plugins/BB.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import lxml.etree
-import Bcfg2.Server.Plugin
-import glob
-import os
-import socket
-
-#manage boot symlinks
- #add statistics check to do build->boot mods
-
-#map profiles: first array is not empty we replace the -p with a determined profile.
-logger = Bcfg2.Server.Plugin.logger
-
-class BBfile(Bcfg2.Server.Plugin.XMLFileBacked):
- """Class for bb files."""
- def Index(self):
- """Build data into an xml object."""
-
- try:
- self.data = lxml.etree.XML(self.data)
- except lxml.etree.XMLSyntaxError:
- Bcfg2.Server.Plugin.logger.error("Failed to parse %s" % self.name)
- return
- self.tftppath = self.data.get('tftp', '/tftpboot')
- self.macs = {}
- self.users = {}
- self.actions = {}
- self.bootlinks = []
-
- for node in self.data.findall('Node'):
- iface = node.find('Interface')
- if iface != None:
- mac = "01-%s" % (iface.get('mac'.replace(':','-').lower()))
- self.actions[node.get('name')] = node.get('action')
- self.bootlinks.append((mac, node.get('action')))
- try:
- ip = socket.gethostbyname(node.get('name'))
- except:
- logger.error("failed host resolution for %s" % node.get('name'))
-
- self.macs[node.get('name')] = (iface.get('mac'), ip)
- else:
- logger.error("%s" % lxml.etree.tostring(node))
- self.users[node.get('name')] = node.get('user',"").split(':')
-
- def enforce_bootlinks(self):
- for mac, target in self.bootlinks:
- path = self.tftppath + '/' + mac
- if not os.path.islink(path):
- logger.error("Boot file %s not a link" % path)
- if target != os.readlink(path):
- try:
- os.unlink(path)
- os.symlink(target, path)
- except:
- logger.error("Failed to modify link %s" % path)
-
-class BBDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked):
- __child__ = BBfile
-
-
-class BB(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Connector):
- """The BB plugin maps users to machines and metadata to machines."""
- name = 'BB'
- version = '$Revision$'
- deprecated = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- self.store = BBDirectoryBacked(self.data, core.fam)
-
- def get_additional_data(self, metadata):
-
- users = {}
- for user in self.store.entries['bb.xml'].users.get(metadata.hostname.split(".")[0], []):
- pubkeys = []
- for fname in glob.glob('/home/%s/.ssh/*.pub'%user):
- pubkeys.append(open(fname).read())
-
- users[user] = pubkeys
-
- return dict([('users', users),
- ('macs', self.store.entries['bb.xml'].macs)])
diff --git a/build/lib/Bcfg2/Server/Plugins/Base.py b/build/lib/Bcfg2/Server/Plugins/Base.py
deleted file mode 100644
index 8e5ca1cd9..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Base.py
+++ /dev/null
@@ -1,38 +0,0 @@
-"""This module sets up a base list of configuration entries."""
-__revision__ = '$Revision$'
-
-import Bcfg2.Server.Plugin
-import copy
-import lxml.etree
-
-class Base(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Structure,
- Bcfg2.Server.Plugin.XMLDirectoryBacked):
- """This Structure is good for the pile of independent configs
- needed for most actual systems.
- """
- name = 'Base'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- __child__ = Bcfg2.Server.Plugin.StructFile
-
- """Base creates independent clauses based on client metadata."""
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Structure.__init__(self)
- try:
- Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self,
- self.data,
- self.core.fam)
- except OSError:
- self.logger.error("Failed to load Base repository")
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def BuildStructures(self, metadata):
- """Build structures for client described by metadata."""
- ret = lxml.etree.Element("Independent", version='2.0')
- fragments = reduce(lambda x, y: x+y,
- [base.Match(metadata) for base
- in self.entries.values()], [])
- [ret.append(copy.deepcopy(frag)) for frag in fragments]
- return [ret]
diff --git a/build/lib/Bcfg2/Server/Plugins/Bundler.py b/build/lib/Bcfg2/Server/Plugins/Bundler.py
deleted file mode 100644
index 47cd7e2c4..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Bundler.py
+++ /dev/null
@@ -1,76 +0,0 @@
-"""This provides bundle clauses with translation functionality."""
-__revision__ = '$Revision$'
-
-import copy
-import lxml.etree
-import re
-
-import Bcfg2.Server.Plugin
-
-try:
- import genshi.template
- import genshi.template.base
- import Bcfg2.Server.Plugins.SGenshi
- have_genshi = True
-except:
- have_genshi = False
-
-class BundleFile(Bcfg2.Server.Plugin.StructFile):
- def get_xml_value(self, metadata):
- bundlename = self.name.split('/')[-1][:-4]
- bundle = lxml.etree.Element('Bundle', name=bundlename)
- [bundle.append(copy.deepcopy(item)) for item in self.Match(metadata)]
- return bundle
-
-class Bundler(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Structure,
- Bcfg2.Server.Plugin.XMLDirectoryBacked):
- """The bundler creates dependent clauses based on the bundle/translation scheme from Bcfg1."""
- name = 'Bundler'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- patterns = re.compile('^(?P<name>.*)\.(xml|genshi)$')
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Structure.__init__(self)
- self.encoding = core.encoding
- self.__child__ = self.template_dispatch
- try:
- Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self, self.data, self.core.fam)
- except OSError:
- self.logger.error("Failed to load Bundle repository")
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def template_dispatch(self, name):
- if name.endswith('.xml'):
- return BundleFile(name)
- elif name.endswith('.genshi'):
- if have_genshi:
- spec = Bcfg2.Server.Plugin.Specificity()
- return Bcfg2.Server.Plugins.SGenshi.SGenshiTemplateFile(name,
- spec,
- self.encoding)
-
- def BuildStructures(self, metadata):
- """Build all structures for client (metadata)."""
- bundleset = []
- for bundlename in metadata.bundles:
- entries = [item for (key, item) in self.entries.iteritems() if \
- self.patterns.match(key).group('name') == bundlename]
- if len(entries) == 0:
- continue
- elif len(entries) == 1:
- try:
- bundleset.append(entries[0].get_xml_value(metadata))
- except genshi.template.base.TemplateError, t:
- self.logger.error("Bundler: Failed to template genshi bundle %s" \
- % (bundlename))
- self.logger.error(t)
- except:
- self.logger.error("Bundler: Unexpected bundler error for %s" \
- % (bundlename), exc_info=1)
- else:
- self.logger.error("Got multiple matches for bundle %s" \
- % (bundlename))
- return bundleset
diff --git a/build/lib/Bcfg2/Server/Plugins/Bzr.py b/build/lib/Bcfg2/Server/Plugins/Bzr.py
deleted file mode 100644
index a9a5eb814..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Bzr.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import Bcfg2.Server.Plugin
-from bzrlib.workingtree import WorkingTree
-from bzrlib import errors
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Bzr')
-
-class Bzr(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Bzr is a version plugin for dealing with Bcfg2 repos."""
- name = 'Bzr'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- self.core = core
- self.datastore = datastore
-
- # Read revision from bcfg2 repo
- revision = self.get_revision()
-
- logger.debug("Initialized Bazaar plugin with directory = %(dir)s at revision = %(rev)s" % {'dir': datastore, 'rev': revision})
-
- def get_revision(self):
- """Read Bazaar revision information for the Bcfg2 repository."""
- try:
- working_tree = WorkingTree.open(self.datastore)
- revision = str(working_tree.branch.revno())
- if working_tree.has_changes(working_tree.basis_tree()) or working_tree.unknowns():
- revision += "+"
- except errors.NotBranchError:
- logger.error("Failed to read Bazaar branch; disabling Bazaar support")
- raise Bcfg2.Server.Plugin.PluginInitError
- return revision
diff --git a/build/lib/Bcfg2/Server/Plugins/Cfg.py b/build/lib/Bcfg2/Server/Plugins/Cfg.py
deleted file mode 100644
index dd1e792ec..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Cfg.py
+++ /dev/null
@@ -1,165 +0,0 @@
-"""This module implements a config file repository."""
-__revision__ = '$Revision$'
-
-import binascii
-import logging
-import lxml
-import os
-import re
-import tempfile
-
-import Bcfg2.Server.Plugin
-
-logger = logging.getLogger('Bcfg2.Plugins.Cfg')
-
-def process_delta(data, delta):
- if not delta.specific.delta:
- return data
- if delta.specific.delta == 'cat':
- datalines = data.split('\n')
- for line in delta.data.split('\n'):
- if not line:
- continue
- if line[0] == '+':
- datalines.append(line[1:])
- elif line[0] == '-':
- if line[1:] in datalines:
- datalines.remove(line[1:])
- return "\n".join(datalines)
- elif delta.specific.delta == 'diff':
- basehandle, basename = tempfile.mkstemp()
- basefile = open(basename, 'w')
- basefile.write(data)
- basefile.close()
- os.close(basehandle)
- dhandle, dname = tempfile.mkstemp()
- dfile = open(dname, 'w')
- dfile.write(delta.data)
- dfile.close()
- os.close(dhandle)
- ret = os.system("patch -uf %s < %s > /dev/null 2>&1" \
- % (basefile.name, dfile.name))
- output = open(basefile.name, 'r').read()
- [os.unlink(fname) for fname in [basefile.name, dfile.name]]
- if ret >> 8 != 0:
- raise Bcfg2.Server.Plugin.PluginExecutionError, ('delta', delta)
- return output
-
-class CfgMatcher:
- def __init__(self, fname):
- name = re.escape(fname)
- self.basefile_reg = re.compile('^(?P<basename>%s)(|\\.H_(?P<hostname>\S+)|.G(?P<prio>\d+)_(?P<group>\S+))$' % name)
- self.delta_reg = re.compile('^(?P<basename>%s)(|\\.H_(?P<hostname>\S+)|\\.G(?P<prio>\d+)_(?P<group>\S+))\\.(?P<delta>(cat|diff))$' % name)
- self.cat_count = fname.count(".cat")
- self.diff_count = fname.count(".diff")
-
- def match(self, fname):
- if fname.count(".cat") > self.cat_count \
- or fname.count('.diff') > self.diff_count:
- return self.delta_reg.match(fname)
- return self.basefile_reg.match(fname)
-
-class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
- def __init__(self, basename, path, entry_type, encoding):
- Bcfg2.Server.Plugin.EntrySet.__init__(self, basename, path,
- entry_type, encoding)
- self.specific = CfgMatcher(path.split('/')[-1])
-
- def sort_by_specific(self, one, other):
- return cmp(one.specific, other.specific)
-
- def get_pertinent_entries(self, metadata):
- '''return a list of all entries pertinent to a client => [base, delta1, delta2]'''
- matching = [ent for ent in self.entries.values() if \
- ent.specific.matches(metadata)]
- matching.sort(self.sort_by_specific)
- non_delta = [matching.index(m) for m in matching if not m.specific.delta]
- if not non_delta:
- raise Bcfg2.Server.Plugin.PluginExecutionError
- base = min(non_delta)
- used = matching[:base+1]
- used.reverse()
- return used
-
- def bind_entry(self, entry, metadata):
- self.bind_info_to_entry(entry, metadata)
- used = self.get_pertinent_entries(metadata)
- basefile = used.pop(0)
- data = basefile.data
- if entry.tag == 'Path':
- entry.set('type', 'file')
- for delta in used:
- data = data.strip()
- data = process_delta(data, delta)
- if used:
- data += '\n'
- if entry.get('encoding') == 'base64':
- entry.text = binascii.b2a_base64(data)
- else:
- entry.text = unicode(data, self.encoding)
- if entry.text in ['', None]:
- entry.set('empty', 'true')
-
- def list_accept_choices(self, metadata):
- '''return a list of candidate pull locations'''
- used = self.get_pertinent_entries(metadata)
- ret = []
- if used:
- ret.append(used[0].specific)
- if not ret[0].hostname:
- ret.append(Bcfg2.Server.Plugin.Specificity(hostname=metadata.hostname))
- return ret
-
- def build_filename(self, specific):
- bfname = self.path + '/' + self.path.split('/')[-1]
- if specific.all:
- return bfname
- elif specific.group:
- return "%s.G%d_%s" % (bfname, specific.prio, specific.group)
- elif specific.hostname:
- return "%s.H_%s" % (bfname, specific.hostname)
-
- def write_update(self, specific, new_entry, log):
- if 'text' in new_entry:
- name = self.build_filename(specific)
- open(name, 'w').write(new_entry['text'])
- if log:
- logger.info("Wrote file %s" % name)
- badattr = [attr for attr in ['owner', 'group', 'perms'] if attr in new_entry]
- if badattr:
- metadata_updates = {}
- metadata_updates.update(self.metadata)
- for attr in badattr:
- metadata_updates[attr] = new_entry.get(attr)
- if self.infoxml:
- infoxml = lxml.etree.Element('FileInfo')
- infotag = lxml.etree.SubElement(infoxml, 'Info')
- [infotag.attrib.__setitem__(attr, metadata_updates[attr]) \
- for attr in metadata_updates]
- ofile = open(self.path + "/info.xml","w")
- ofile.write(lxml.etree.tostring(infoxml, pretty_print=True))
- ofile.close()
- if log:
- logger.info("Wrote file %s" % (self.path + "/info.xml"))
- else:
- infofile = open(self.path + '/:info', 'w')
- for x in metadata_updates.iteritems():
- infofile.write("%s: %s\n" % x)
- infofile.close()
- if log:
- logger.info("Wrote file %s" % infofile.name)
-
-class Cfg(Bcfg2.Server.Plugin.GroupSpool,
- Bcfg2.Server.Plugin.PullTarget):
- """This generator in the configuration file repository for Bcfg2."""
- name = 'Cfg'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- es_cls = CfgEntrySet
- es_child_cls = Bcfg2.Server.Plugin.SpecificData
-
- def AcceptChoices(self, entry, metadata):
- return self.entries[entry.get('name')].list_accept_choices(metadata)
-
- def AcceptPullData(self, specific, new_entry, log):
- return self.entries[new_entry.get('name')].write_update(specific, new_entry, log)
diff --git a/build/lib/Bcfg2/Server/Plugins/Cvs.py b/build/lib/Bcfg2/Server/Plugins/Cvs.py
deleted file mode 100644
index ea898c023..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Cvs.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Cvs')
-
-class Cvs(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """CVS is a version plugin for dealing with Bcfg2 repository."""
- name = 'Cvs'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- self.core = core
- self.datastore = datastore
-
- # path to cvs directory for Bcfg2 repo
- cvs_dir = "%s/CVSROOT" % datastore
-
- # Read revision from Bcfg2 repo
- if os.path.isdir(cvs_dir):
- self.get_revision()
- else:
- logger.error("%s is not a directory" % cvs_dir)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- logger.debug("Initialized cvs plugin with cvs directory = %s" % cvs_dir)
-
- def get_revision(self):
- """Read cvs revision information for the Bcfg2 repository."""
- try:
- data = Popen("env LC_ALL=C cvs log",
- shell=True,
- cwd=self.datastore,
- stdout=PIPE).stdout.readlines()
- revision = data[3].strip('\n')
- except IndexError:
- logger.error("Failed to read cvs log; disabling cvs support")
- logger.error('''Ran command "cvs log %s"''' % (self.datastore))
- logger.error("Got output: %s" % data)
- raise Bcfg2.Server.Plugin.PluginInitError
-
diff --git a/build/lib/Bcfg2/Server/Plugins/DBStats.py b/build/lib/Bcfg2/Server/Plugins/DBStats.py
deleted file mode 100644
index 2712cd45f..000000000
--- a/build/lib/Bcfg2/Server/Plugins/DBStats.py
+++ /dev/null
@@ -1,110 +0,0 @@
-import binascii
-import difflib
-import logging
-import lxml.etree
-import platform
-import time
-
-try:
- from django.core.exceptions import MultipleObjectsReturned
-except ImportError:
- pass
-
-import Bcfg2.Server.Plugin
-import Bcfg2.Server.Reports.importscript
-from Bcfg2.Server.Reports.reports.models import Client
-import Bcfg2.Server.Reports.settings
-from Bcfg2.Server.Reports.updatefix import update_database
-# for debugging output only
-logger = logging.getLogger('Bcfg2.Plugins.DBStats')
-
-class DBStats(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.ThreadedStatistics,
- Bcfg2.Server.Plugin.PullSource):
- name = 'DBStats'
- __version__ = '$Id$'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.ThreadedStatistics.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.PullSource.__init__(self)
- self.cpath = "%s/Metadata/clients.xml" % datastore
- self.core = core
- logger.debug("Searching for new models to add to the statistics database")
- try:
- update_database()
- except Exception, inst:
- logger.debug(str(inst))
- logger.debug(str(type(inst)))
-
- def handle_statistic(self, metadata, data):
- newstats = data.find("Statistics")
- newstats.set('time', time.asctime(time.localtime()))
- # ick
- data = lxml.etree.tostring(newstats)
- ndx = lxml.etree.XML(data)
- e = lxml.etree.Element('Node', name=metadata.hostname)
- e.append(ndx)
- container = lxml.etree.Element("ConfigStatistics")
- container.append(e)
-
- # FIXME need to build a metadata interface to expose a list of clients
- start = time.time()
- for i in [1, 2, 3]:
- try:
- Bcfg2.Server.Reports.importscript.load_stats(self.core.metadata.clientdata,
- container,
- 0,
- logger,
- True,
- platform.node())
- logger.info("Imported data for %s in %s seconds" \
- % (metadata.hostname, time.time() - start))
- return
- except MultipleObjectsReturned, e:
- logger.error("DBStats: MultipleObjectsReturned while handling %s: %s" % \
- (metadata.hostname, e))
- logger.error("DBStats: Data is inconsistent")
- break
- except:
- logger.error("DBStats: Failed to write to db (lock); retrying",
- exc_info=1)
- logger.error("DBStats: Retry limit failed for %s; aborting operation" \
- % metadata.hostname)
-
- def GetExtra(self, client):
- c_inst = Client.objects.filter(name=client)[0]
- return [(a.entry.kind, a.entry.name) for a in
- c_inst.current_interaction.extra()]
-
- def GetCurrentEntry(self, client, e_type, e_name):
- try:
- c_inst = Client.objects.filter(name=client)[0]
- except IndexError:
- self.logger.error("Unknown client: %s" % client)
- raise Bcfg2.Server.Plugin.PluginExecutionError
- result = c_inst.current_interaction.bad().filter(entry__kind=e_type,
- entry__name=e_name)
- if not result:
- raise Bcfg2.Server.Plugin.PluginExecutionError
- entry = result[0]
- ret = []
- data = ('owner', 'group', 'perms')
- for t in data:
- if getattr(entry.reason, "current_%s" % t) == '':
- ret.append(getattr(entry.reason, t))
- else:
- ret.append(getattr(entry.reason, "current_%s" % t))
-
- if entry.reason.current_diff != '':
- if entry.reason.is_binary:
- ret.append(binascii.a2b_base64(entry.reason.current_diff))
- else:
- ret.append('\n'.join(difflib.restore(\
- entry.reason.current_diff.split('\n'), 1)))
- elif entry.reason.is_binary:
- # If len is zero the object was too large to store
- raise Bcfg2.Server.Plugin.PluginExecutionError
- else:
- ret.append(None)
- return ret
diff --git a/build/lib/Bcfg2/Server/Plugins/Darcs.py b/build/lib/Bcfg2/Server/Plugins/Darcs.py
deleted file mode 100644
index eb34a52c4..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Darcs.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import os
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Darcs')
-
-class Darcs(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Darcs is a version plugin for dealing with Bcfg2 repos."""
- name = 'Darcs'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self)
- self.core = core
- self.datastore = datastore
-
- # path to darcs directory for bcfg2 repo
- darcs_dir = "%s/_darcs" % datastore
-
- # Read changeset from bcfg2 repo
- if os.path.isdir(darcs_dir):
- self.get_revision()
- else:
- logger.error("%s is not present." % darcs_dir)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- logger.debug("Initialized Darcs plugin with darcs directory = %s" % darcs_dir)
-
- def get_revision(self):
- """Read Darcs changeset information for the Bcfg2 repository."""
- try:
- data = Popen("env LC_ALL=C darcs changes",
- shell=True,
- cwd=self.datastore,
- stdout=PIPE).stdout.readlines()
- revision = data[0].strip('\n')
- except:
- logger.error("Failed to read darcs repository; disabling Darcs support")
- logger.error('''Ran command "darcs changes" from directory "%s"''' % (self.datastore))
- logger.error("Got output: %s" % data)
- raise Bcfg2.Server.Plugin.PluginInitError
- return revision
-
diff --git a/build/lib/Bcfg2/Server/Plugins/Decisions.py b/build/lib/Bcfg2/Server/Plugins/Decisions.py
deleted file mode 100644
index 1f9525a0e..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Decisions.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import logging
-import lxml.etree
-import Bcfg2.Server.Plugin
-logger = logging.getLogger('Bcfg2.Plugins.Decisions')
-
-class DecisionFile(Bcfg2.Server.Plugin.SpecificData):
- def handle_event(self, event):
- Bcfg2.Server.Plugin.SpecificData.handle_event(self, event)
- self.contents = lxml.etree.XML(self.data)
-
- def get_decisions(self):
- return [(x.get('type'), x.get('name')) for x in self.contents.xpath('.//Decision')]
-
-class DecisionSet(Bcfg2.Server.Plugin.EntrySet):
- def __init__(self, path, fam, encoding):
- """Container for decision specification files.
-
- Arguments:
- - `path`: repository path
- - `fam`: reference to the file monitor
- - `encoding`: XML character encoding
-
- """
- pattern = '(white|black)list'
- Bcfg2.Server.Plugin.EntrySet.__init__(self, pattern, path, \
- DecisionFile, encoding)
- try:
- fam.AddMonitor(path, self)
- except OSError, e:
- logger.error('Adding filemonitor for %s failed. '
- 'Make sure directory exists' % path)
- raise Bcfg2.Server.Plugin.PluginInitError(e)
-
- def HandleEvent(self, event):
- if event.filename != self.path:
- return self.handle_event(event)
-
- def GetDecisions(self, metadata, mode):
- ret = []
- candidates = [c for c in self.get_matching(metadata)
- if c.name.split('/')[-1].startswith(mode)]
- for c in candidates:
- ret += c.get_decisions()
- return ret
-
-class Decisions(DecisionSet,
- Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Decision):
- name = 'Decisions'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- """Decisions plugins
-
- Arguments:
- - `core`: Bcfg2.Core instance
- - `datastore`: File repository location
-
- """
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Decision.__init__(self)
- DecisionSet.__init__(self, self.data, core.fam, core.encoding)
-
diff --git a/build/lib/Bcfg2/Server/Plugins/Deps.py b/build/lib/Bcfg2/Server/Plugins/Deps.py
deleted file mode 100644
index 088f8cdad..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Deps.py
+++ /dev/null
@@ -1,103 +0,0 @@
-"""This plugin provides automatic dependency handling."""
-__revision__ = '$Revision$'
-
-import lxml.etree
-
-import Bcfg2.Server.Plugin
-
-class DNode(Bcfg2.Server.Plugin.INode):
- """DNode provides supports for single predicate types for dependencies."""
- raw = {'Group':"lambda x:'%s' in x.groups and predicate(x)"}
- containers = ['Group']
-
- def __init__(self, data, idict, parent=None):
- self.data = data
- self.contents = {}
- if parent == None:
- self.predicate = lambda x:True
- else:
- predicate = parent.predicate
- if data.tag in self.raw.keys():
- self.predicate = eval(self.raw[data.tag] % (data.get('name')), {'predicate':predicate})
- else:
- raise Exception
- mytype = self.__class__
- self.children = []
- for item in data.getchildren():
- if item.tag in self.containers:
- self.children.append(mytype(item, idict, self))
- else:
- data = [(child.tag, child.get('name')) for child in item.getchildren()]
- try:
- self.contents[item.tag][item.get('name')] = data
- except KeyError:
- self.contents[item.tag] = {item.get('name'):data}
-
-class DepXMLSrc(Bcfg2.Server.Plugin.XMLSrc):
- __node__ = DNode
-
-class Deps(Bcfg2.Server.Plugin.PrioDir,
- Bcfg2.Server.Plugin.StructureValidator):
- name = 'Deps'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- __child__ = DepXMLSrc
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.PrioDir.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.StructureValidator.__init__(self)
- self.cache = {}
-
- def HandleEvent(self, event):
- self.cache = {}
- Bcfg2.Server.Plugin.PrioDir.HandleEvent(self, event)
-
- def validate_structures(self, metadata, structures):
- entries = []
- prereqs = []
- for structure in structures:
- for entry in structure.getchildren():
- if (entry.tag, entry.get('name')) not in entries \
- and not isinstance(entry, lxml.etree._Comment):
- entries.append((entry.tag, entry.get('name')))
- entries.sort()
- entries = tuple(entries)
- gdata = list(metadata.groups)
- gdata.sort()
- gdata = tuple(gdata)
- if (entries, gdata) in self.cache:
- prereqs = self.cache[(entries, gdata)]
- else:
- [src.Cache(metadata) for src in self.entries.values()]
-
- toexamine = list(entries[:])
- while toexamine:
- entry = toexamine.pop()
- matching = [src for src in self.entries.values()
- if src.cache and entry[0] in src.cache[1]
- and entry[1] in src.cache[1][entry[0]]]
- if len(matching) > 1:
- prio = [int(src.priority) for src in matching]
- if prio.count(max(prio)) > 1:
- self.logger.error("Found conflicting %s sources with same priority for %s, pkg %s" %
- (entry[0].lower(), metadata.hostname, entry[1]))
- raise Bcfg2.Server.Plugin.PluginExecutionError
- index = prio.index(max(prio))
- matching = [matching[index]]
-
- if not matching:
- continue
- elif len(matching) == 1:
- for prq in matching[0].cache[1][entry[0]][entry[1]]:
- if prq not in prereqs and prq not in entries:
- toexamine.append(prq)
- prereqs.append(prq)
- self.cache[(entries, gdata)] = prereqs
-
- newstruct = lxml.etree.Element("Independent")
- for tag, name in prereqs:
- try:
- lxml.etree.SubElement(newstruct, tag, name=name)
- except:
- self.logger.error("Failed to add dep entry for %s:%s" % (tag, name))
- structures.append(newstruct)
diff --git a/build/lib/Bcfg2/Server/Plugins/Editor.py b/build/lib/Bcfg2/Server/Plugins/Editor.py
deleted file mode 100644
index bfd4d6e93..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Editor.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import Bcfg2.Server.Plugin
-import re
-import lxml.etree
-
-def linesub(pattern, repl, filestring):
- """Substitutes instances of pattern with repl in filestring."""
- if filestring == None:
- filestring = ''
- output = list()
- fileread = filestring.split('\n')
- for line in fileread:
- output.append(re.sub(pattern, repl, filestring))
- return '\n'.join(output)
-
-class EditDirectives(Bcfg2.Server.Plugin.SpecificData):
- """This object handles the editing directives."""
- def ProcessDirectives(self, input):
- """Processes a list of edit directives on input."""
- temp = input
- for directive in self.data.split('\n'):
- directive = directive.split(',')
- temp = linesub(directive[0], directive[1], temp)
- return temp
-
-class EditEntrySet(Bcfg2.Server.Plugin.EntrySet):
- def __init__(self, basename, path, entry_type, encoding):
- self.ignore = re.compile("^(\.#.*|.*~|\\..*\\.(tmp|sw[px])|%s\.H_.*)$" %path.split('/')[-1])
- Bcfg2.Server.Plugin.EntrySet.__init__(self, basename, path, entry_type, encoding)
- self.inputs = dict()
-
- def bind_entry(self, entry, metadata):
- client = metadata.hostname
- filename = entry.get('name')
- permdata = {'owner':'root', 'group':'root'}
- permdata['perms'] = '0644'
- [entry.attrib.__setitem__(key, permdata[key]) for key in permdata]
- entry.text = self.entries['edits'].ProcessDirectives(self.get_client_data(client))
- if not entry.text:
- entry.set('empty', 'true')
- try:
- f = open('%s/%s.H_%s' %(self.path, filename.split('/')[-1], client), 'w')
- f.write(entry.text)
- f.close()
- except:
- pass
-
- def get_client_data(self, client):
- return self.inputs[client]
-
-
-class Editor(Bcfg2.Server.Plugin.GroupSpool,
- Bcfg2.Server.Plugin.Probing):
- name = 'Editor'
- __version__ = '$Id$'
- __author__ = 'bcfg2-dev@mcs.anl.gov'
- filename_pattern = 'edits'
- es_child_cls = EditDirectives
- es_cls = EditEntrySet
-
- def GetProbes(self, _):
- '''Return a set of probes for execution on client'''
- probelist = list()
- for name in self.entries.keys():
- probe = lxml.etree.Element('probe')
- probe.set('name', name)
- probe.set('source', "Editor")
- probe.text = "cat %s" % name
- probelist.append(probe)
- return probelist
-
- def ReceiveData(self, client, datalist):
- for data in datalist:
- self.entries[data.get('name')].inputs[client.hostname] = data.text
diff --git a/build/lib/Bcfg2/Server/Plugins/Fossil.py b/build/lib/Bcfg2/Server/Plugins/Fossil.py
deleted file mode 100644
index 57d427673..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Fossil.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import os
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Fossil')
-
-class Fossil(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Fossil is a version plugin for dealing with Bcfg2 repos."""
- name = 'Fossil'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- self.core = core
- self.datastore = datastore
-
- # path to fossil file for bcfg2 repo
- fossil_file = "%s/_FOSSIL_" % datastore
-
- # Read revision from bcfg2 repo
- if os.path.isfile(fossil_file):
- revision = self.get_revision()
- elif not os.path.isdir(datastore):
- logger.error("%s is not a directory" % datastore)
- raise Bcfg2.Server.Plugin.PluginInitError
- else:
- logger.error("%s is not a file" % fossil_file)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- logger.debug("Initialized Fossil.py plugin with %(ffile)s at revision %(frev)s" \
- % {'ffile': fossil_file, 'frev': revision})
-
- def get_revision(self):
- """Read fossil revision information for the Bcfg2 repository."""
- try:
- data = Popen("env LC_ALL=C fossil info",
- shell=True,
- cwd=self.datastore,
- stdout=PIPE).stdout.readlines()
- revline = [line.split(': ')[1].strip() for line in data if \
- line.split(': ')[0].strip() == 'checkout'][-1]
- revision = revline.split(' ')[0]
- except IndexError:
- logger.error("Failed to read fossil info; disabling fossil support")
- logger.error('''Ran command "fossil info" from directory "%s"''' % (self.datastore))
- logger.error("Got output: %s" % data)
- raise Bcfg2.Server.Plugin.PluginInitError
- return revision
diff --git a/build/lib/Bcfg2/Server/Plugins/Git.py b/build/lib/Bcfg2/Server/Plugins/Git.py
deleted file mode 100644
index aaeac12ae..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Git.py
+++ /dev/null
@@ -1,45 +0,0 @@
-"""The Git plugin provides a revision interface for Bcfg2 repos using git."""
-
-import os
-from dulwich.repo import Repo
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Git')
-
-
-class Git(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Git is a version plugin for dealing with Bcfg2 repos."""
- name = 'Git'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self)
- self.core = core
- self.datastore = datastore
-
- # path to git directory for bcfg2 repo
- git_dir = "%s/.git" % datastore
-
- # Read revision from bcfg2 repo
- if os.path.isdir(git_dir):
- self.get_revision()
- else:
- logger.error("%s is not a directory" % git_dir)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- logger.debug("Initialized git plugin with git directory %s" % git_dir)
-
- def get_revision(self):
- """Read git revision information for the Bcfg2 repository."""
- try:
- repo = Repo(self.datastore)
- revision = repo.head()
- except:
- logger.error("Failed to read git repository; disabling git support")
- raise Bcfg2.Server.Plugin.PluginInitError
- return revision
diff --git a/build/lib/Bcfg2/Server/Plugins/GroupPatterns.py b/build/lib/Bcfg2/Server/Plugins/GroupPatterns.py
deleted file mode 100644
index 3801a6a08..000000000
--- a/build/lib/Bcfg2/Server/Plugins/GroupPatterns.py
+++ /dev/null
@@ -1,117 +0,0 @@
-import lxml.etree
-import re
-
-import Bcfg2.Server.Plugin
-
-class PackedDigitRange(object):
- def __init__(self, digit_range):
- self.sparse = list()
- self.ranges = list()
- for item in digit_range.split(','):
- if '-' in item:
- self.ranges.append(tuple([int(x) for x in item.split('-')]))
- else:
- self.sparse.append(int(item))
-
- def includes(self, other):
- iother = int(other)
- if iother in self.sparse:
- return True
- for (start, end) in self.ranges:
- if iother in xrange(start, end+1):
- return True
- return False
-
-class PatternMap(object):
- range_finder = '\\[\\[[\d\-,]+\\]\\]'
- def __init__(self, pattern, rangestr, groups):
- self.pattern = pattern
- self.rangestr = rangestr
- self.groups = groups
- if pattern != None:
- self.re = re.compile(pattern)
- self.process = self.process_re
- elif rangestr != None:
- self.process = self.process_range
- self.re = re.compile('^' + re.subn(self.range_finder, '(\d+)', rangestr)[0])
- dmatcher = re.compile(re.subn(self.range_finder, '\\[\\[([\d\-,]+)\\]\\]', rangestr)[0])
- self.dranges = [PackedDigitRange(x) for x in dmatcher.match(rangestr).groups()]
- else:
- raise Exception
-
- def process_range(self, name):
- match = self.re.match(name)
- if not match:
- return None
- digits = match.groups()
- for i in range(len(digits)):
- if not self.dranges[i].includes(digits[i]):
- return None
- return self.groups
-
- def process_re(self, name):
- match = self.re.match(name)
- if not match:
- return None
- ret = list()
- sub = match.groups()
- for group in self.groups:
- newg = group
- for idx in range(len(sub)):
- newg = newg.replace('$%s' % (idx+1), sub[idx])
- ret.append(newg)
- return ret
-
-class PatternFile(Bcfg2.Server.Plugin.SingleXMLFileBacked):
- def __init__(self, filename, fam):
- Bcfg2.Server.Plugin.SingleXMLFileBacked.__init__(self, filename, fam)
- self.patterns = []
-
- def Index(self):
- self.patterns = []
- try:
- parsed = lxml.etree.XML(self.data)
- except:
- Bcfg2.Server.Plugin.logger.error("Failed to read file %s" % self.name)
- return
- for entry in parsed.findall('GroupPattern'):
- try:
- pat = None
- rng = None
- if entry.find('NamePattern') is not None:
- pat = entry.find('NamePattern').text
- if entry.find('NameRange') is not None:
- rng = entry.find('NameRange').text
- groups = [g.text for g in entry.findall('Group')]
- self.patterns.append(PatternMap(pat, rng, groups))
- except:
- Bcfg2.Server.Plugin.logger.error(\
- "GroupPatterns: Failed to initialize pattern %s" % \
- (entry.get('pattern')))
-
- def process_patterns(self, hostname):
- ret = []
- for pattern in self.patterns:
- try:
- gn = pattern.process(hostname)
- if gn is not None:
- ret.extend(gn)
- except:
- Bcfg2.Server.Plugin.logger.error(\
- "GroupPatterns: Failed to process pattern %s for %s" % \
- (pattern.pattern, hostname), exc_info=1)
- return ret
-
-class GroupPatterns(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Connector):
- name = "GroupPatterns"
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- self.config = PatternFile(self.data + '/config.xml',
- core.fam)
-
- def get_additional_groups(self, metadata):
- return self.config.process_patterns(metadata.hostname)
diff --git a/build/lib/Bcfg2/Server/Plugins/Guppy.py b/build/lib/Bcfg2/Server/Plugins/Guppy.py
deleted file mode 100644
index b217378d6..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Guppy.py
+++ /dev/null
@@ -1,63 +0,0 @@
-"""
-This plugin is used to trace memory leaks within the bcfg2-server
-process using Guppy. By default the remote debugger is started
-when this plugin is enabled. The debugger can be shutoff in a running
-process using "bcfg2-admin xcmd Guppy.Disable" and reenabled using
-"bcfg2-admin xcmd Guppy.Enable".
-
-To attach the console run:
-
-python -c "from guppy import hpy;hpy().monitor()"
-
-For example:
-
-# python -c "from guppy import hpy;hpy().monitor()"
-<Monitor>
-*** Connection 1 opened ***
-<Monitor> lc
-CID PID ARGV
- 1 25063 ['/usr/sbin/bcfg2-server', '-D', '/var/run/bcfg2-server.pid']
-<Monitor> sc 1
-Remote connection 1. To return to Monitor, type <Ctrl-C> or .<RETURN>
-<Annex> int
-Remote interactive console. To return to Annex, type '-'.
->>> hp.heap()
-...
-
-
-"""
-import re
-import Bcfg2.Server.Plugin
-
-class Guppy(Bcfg2.Server.Plugin.Plugin):
- """Guppy is a debugging plugin to help trace memory leaks"""
- name = 'Guppy'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- experimental = True
- __rmi__ = Bcfg2.Server.Plugin.Plugin.__rmi__ + ['Enable','Disable']
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
-
- self.Enable()
-
- def Enable(self):
- """Enable remote debugging"""
- try:
- from guppy.heapy import Remote
- Remote.on()
- except:
- self.logger.error("Failed to create Heapy context")
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def Disable(self):
- """Disable remote debugging"""
- try:
- from guppy.heapy import Remote
- Remote.off()
- except:
- self.logger.error("Failed to disable Heapy")
- raise Bcfg2.Server.Plugin.PluginInitError
-
diff --git a/build/lib/Bcfg2/Server/Plugins/Hg.py b/build/lib/Bcfg2/Server/Plugins/Hg.py
deleted file mode 100644
index 3f2864a1c..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Hg.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-from mercurial import ui, hg
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Mercurial')
-
-class Hg(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Mercurial is a version plugin for dealing with Bcfg2 repository."""
- name = 'Mercurial'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self)
- self.core = core
- self.datastore = datastore
-
- # path to hg directory for Bcfg2 repo
- hg_dir = "%s/.hg" % datastore
-
- # Read changeset from bcfg2 repo
- if os.path.isdir(hg_dir):
- self.get_revision()
- else:
- logger.error("%s is not present." % hg_dir)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- logger.debug("Initialized hg plugin with hg directory = %s" % hg_dir)
-
- def get_revision(self):
- """Read hg revision information for the Bcfg2 repository."""
- try:
- repo_path = "%s/" % self.datastore
- repo = hg.repository(ui.ui(), repo_path)
- tip = repo.changelog.tip()
- revision = repo.changelog.rev(tip)
- except:
- logger.error("Failed to read hg repository; disabling mercurial support")
- raise Bcfg2.Server.Plugin.PluginInitError
- return revision
-
diff --git a/build/lib/Bcfg2/Server/Plugins/Hostbase.py b/build/lib/Bcfg2/Server/Plugins/Hostbase.py
deleted file mode 100644
index 65992596d..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Hostbase.py
+++ /dev/null
@@ -1,585 +0,0 @@
-'''This file provides the Hostbase plugin. It manages dns/dhcp/nis host information'''
-__revision__ = '$Revision$'
-
-import os
-os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.Server.Hostbase.settings'
-from lxml.etree import Element, SubElement
-import Bcfg2.Server.Plugin
-from Bcfg2.Server.Plugin import PluginExecutionError, PluginInitError
-from time import strftime
-from sets import Set
-from django.template import Context, loader
-from django.db import connection
-import re
-import cStringIO
-
-class Hostbase(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Structure,
- Bcfg2.Server.Plugin.Generator):
- """The Hostbase plugin handles host/network info."""
- name = 'Hostbase'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- filepath = '/my/adm/hostbase/files/bind'
-
- def __init__(self, core, datastore):
-
- self.ready = False
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Structure.__init__(self)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- files = ['zone.tmpl', 'reversesoa.tmpl', 'named.tmpl', 'reverseappend.tmpl',
- 'dhcpd.tmpl', 'hosts.tmpl', 'hostsappend.tmpl']
- self.filedata = {}
- self.dnsservers = []
- self.dhcpservers = []
- self.templates = {'zone':loader.get_template('zone.tmpl'),
- 'reversesoa':loader.get_template('reversesoa.tmpl'),
- 'named':loader.get_template('named.tmpl'),
- 'namedviews':loader.get_template('namedviews.tmpl'),
- 'reverseapp':loader.get_template('reverseappend.tmpl'),
- 'dhcp':loader.get_template('dhcpd.tmpl'),
- 'hosts':loader.get_template('hosts.tmpl'),
- 'hostsapp':loader.get_template('hostsappend.tmpl'),
- }
- self.Entries['ConfigFile'] = {}
- self.__rmi__ = ['rebuildState']
- try:
- self.rebuildState(None)
- except:
- raise PluginInitError
-
- def FetchFile(self, entry, metadata):
- """Return prebuilt file data."""
- fname = entry.get('name').split('/')[-1]
- if not fname in self.filedata:
- raise PluginExecutionError
- perms = {'owner':'root', 'group':'root', 'perms':'644'}
- [entry.attrib.__setitem__(key, value) for (key, value) in perms.iteritems()]
- entry.text = self.filedata[fname]
-
- def BuildStructures(self, metadata):
- """Build hostbase bundle."""
- if metadata.hostname not in self.dnsservers or metadata.hostname not in self.dhcpservers:
- return []
- output = Element("Bundle", name='hostbase')
- if metadata.hostname in self.dnsservers:
- for configfile in self.Entries['ConfigFile']:
- if re.search('/etc/bind/', configfile):
- SubElement(output, "ConfigFile", name=configfile)
- if metadata.hostname in self.dhcpservers:
- SubElement(output, "ConfigFile", name="/etc/dhcp3/dhcpd.conf")
- return [output]
-
- def rebuildState(self, _):
- """Pre-cache all state information for hostbase config files
- callable as an XMLRPC function.
-
- """
- self.buildZones()
- self.buildDHCP()
- self.buildHosts()
- self.buildHostsLPD()
- self.buildPrinters()
- self.buildNetgroups()
- return True
-
- def buildZones(self):
- """Pre-build and stash zone files."""
- cursor = connection.cursor()
-
- cursor.execute("SELECT id, serial FROM hostbase_zone")
- zones = cursor.fetchall()
-
- for zone in zones:
- # update the serial number for all zone files
- todaydate = (strftime('%Y%m%d'))
- try:
- if todaydate == str(zone[1])[:8]:
- serial = zone[1] + 1
- else:
- serial = int(todaydate) * 100
- except (KeyError):
- serial = int(todaydate) * 100
- cursor.execute("""UPDATE hostbase_zone SET serial = \'%s\' WHERE id = \'%s\'""" % (str(serial), zone[0]))
-
- cursor.execute("SELECT * FROM hostbase_zone WHERE zone NOT LIKE \'%%.rev\'")
- zones = cursor.fetchall()
-
- iplist = []
- hosts = {}
-
- for zone in zones:
- zonefile = cStringIO.StringIO()
- externalzonefile = cStringIO.StringIO()
- cursor.execute("""SELECT n.name FROM hostbase_zone_nameservers z
- INNER JOIN hostbase_nameserver n ON z.nameserver_id = n.id
- WHERE z.zone_id = \'%s\'""" % zone[0])
- nameservers = cursor.fetchall()
- cursor.execute("""SELECT i.ip_addr FROM hostbase_zone_addresses z
- INNER JOIN hostbase_zoneaddress i ON z.zoneaddress_id = i.id
- WHERE z.zone_id = \'%s\'""" % zone[0])
- addresses = cursor.fetchall()
- cursor.execute("""SELECT m.priority, m.mx FROM hostbase_zone_mxs z
- INNER JOIN hostbase_mx m ON z.mx_id = m.id
- WHERE z.zone_id = \'%s\'""" % zone[0])
- mxs = cursor.fetchall()
- context = Context({
- 'zone': zone,
- 'nameservers': nameservers,
- 'addresses': addresses,
- 'mxs': mxs
- })
- zonefile.write(self.templates['zone'].render(context))
- externalzonefile.write(self.templates['zone'].render(context))
-
- querystring = """SELECT h.hostname, p.ip_addr,
- n.name, c.cname, m.priority, m.mx, n.dns_view
- 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 n.id = x.name_id)
- INNER JOIN hostbase_mx m ON m.id = x.mx_id)
- LEFT JOIN hostbase_cname c ON n.id = c.name_id
- WHERE n.name LIKE '%%%%%s'
- AND h.status = 'active'
- ORDER BY h.hostname, n.name, p.ip_addr
- """ % zone[1]
- cursor.execute(querystring)
- zonehosts = cursor.fetchall()
- prevhost = (None, None, None, None)
- cnames = cStringIO.StringIO()
- cnamesexternal = cStringIO.StringIO()
- for host in zonehosts:
- if not host[2].split(".", 1)[1] == zone[1]:
- zonefile.write(cnames.getvalue())
- externalzonefile.write(cnamesexternal.getvalue())
- cnames = cStringIO.StringIO()
- cnamesexternal = cStringIO.StringIO()
- continue
- if not prevhost[1] == host[1] or not prevhost[2] == host[2]:
- zonefile.write(cnames.getvalue())
- externalzonefile.write(cnamesexternal.getvalue())
- cnames = cStringIO.StringIO()
- cnamesexternal = cStringIO.StringIO()
- zonefile.write("%-32s%-10s%-32s\n" %
- (host[2].split(".", 1)[0], 'A', host[1]))
- zonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
- if host[6] == 'global':
- externalzonefile.write("%-32s%-10s%-32s\n" %
- (host[2].split(".", 1)[0], 'A', host[1]))
- externalzonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
- elif not prevhost[5] == host[5]:
- zonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
- if host[6] == 'global':
- externalzonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
-
- if host[3]:
- try:
- if host[3].split(".", 1)[1] == zone[1]:
- cnames.write("%-32s%-10s%-32s\n" %
- (host[3].split(".", 1)[0],
- 'CNAME',host[2].split(".", 1)[0]))
- if host[6] == 'global':
- cnamesexternal.write("%-32s%-10s%-32s\n" %
- (host[3].split(".", 1)[0],
- 'CNAME',host[2].split(".", 1)[0]))
- else:
- cnames.write("%-32s%-10s%-32s\n" %
- (host[3]+".",
- 'CNAME',
- host[2].split(".", 1)[0]))
- if host[6] == 'global':
- cnamesexternal.write("%-32s%-10s%-32s\n" %
- (host[3]+".",
- 'CNAME',
- host[2].split(".", 1)[0]))
-
- except:
- pass
- prevhost = host
- zonefile.write(cnames.getvalue())
- externalzonefile.write(cnamesexternal.getvalue())
- zonefile.write("\n\n%s" % zone[9])
- externalzonefile.write("\n\n%s" % zone[9])
- self.filedata[zone[1]] = zonefile.getvalue()
- self.filedata[zone[1] + ".external"] = externalzonefile.getvalue()
- zonefile.close()
- externalzonefile.close()
- self.Entries['ConfigFile']["%s/%s" % (self.filepath, zone[1])] = self.FetchFile
- self.Entries['ConfigFile']["%s/%s.external" % (self.filepath, zone[1])] = self.FetchFile
-
- cursor.execute("SELECT * FROM hostbase_zone WHERE zone LIKE \'%%.rev\' AND zone <> \'.rev\'")
- reversezones = cursor.fetchall()
-
- reversenames = []
- for reversezone in reversezones:
- cursor.execute("""SELECT n.name FROM hostbase_zone_nameservers z
- INNER JOIN hostbase_nameserver n ON z.nameserver_id = n.id
- WHERE z.zone_id = \'%s\'""" % reversezone[0])
- reverse_nameservers = cursor.fetchall()
-
- context = Context({
- 'inaddr': reversezone[1].rstrip('.rev'),
- 'zone': reversezone,
- 'nameservers': reverse_nameservers,
- })
-
- self.filedata[reversezone[1]] = self.templates['reversesoa'].render(context)
- self.filedata[reversezone[1] + '.external'] = self.templates['reversesoa'].render(context)
- self.filedata[reversezone[1]] += reversezone[9]
- self.filedata[reversezone[1] + '.external'] += reversezone[9]
-
- subnet = reversezone[1].split(".")
- subnet.reverse()
- reversenames.append((reversezone[1].rstrip('.rev'),".".join(subnet[1:])))
-
- for filename in reversenames:
- cursor.execute("""
- SELECT DISTINCT h.hostname, p.ip_addr, n.dns_view 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 n.ip_id = p.id
- WHERE p.ip_addr LIKE '%s%%%%' AND h.status = 'active' ORDER BY p.ip_addr
- """ % filename[1])
- reversehosts = cursor.fetchall()
- zonefile = cStringIO.StringIO()
- externalzonefile = cStringIO.StringIO()
- if len(filename[0].split(".")) == 2:
- originlist = []
- [originlist.append((".".join([ip[1].split(".")[2], filename[0]]),
- ".".join([filename[1], ip[1].split(".")[2]])))
- for ip in reversehosts
- if (".".join([ip[1].split(".")[2], filename[0]]),
- ".".join([filename[1], ip[1].split(".")[2]])) not in originlist]
- for origin in originlist:
- hosts = [(host[1].split("."), host[0])
- for host in reversehosts
- if host[1].rstrip('0123456789').rstrip('.') == origin[1]]
- hosts_external = [(host[1].split("."), host[0])
- for host in reversehosts
- if (host[1].rstrip('0123456789').rstrip('.') == origin[1]
- and host[2] == 'global')]
- context = Context({
- 'hosts': hosts,
- 'inaddr': origin[0],
- 'fileorigin': filename[0],
- })
- zonefile.write(self.templates['reverseapp'].render(context))
- context = Context({
- 'hosts': hosts_external,
- 'inaddr': origin[0],
- 'fileorigin': filename[0],
- })
- externalzonefile.write(self.templates['reverseapp'].render(context))
- else:
- originlist = [filename[0]]
- hosts = [(host[1].split("."), host[0])
- for host in reversehosts
- if (host[1].split("."), host[0]) not in hosts]
- hosts_external = [(host[1].split("."), host[0])
- for host in reversehosts
- if ((host[1].split("."), host[0]) not in hosts_external
- and host[2] == 'global')]
- context = Context({
- 'hosts': hosts,
- 'inaddr': filename[0],
- 'fileorigin': None,
- })
- zonefile.write(self.templates['reverseapp'].render(context))
- context = Context({
- 'hosts': hosts_external,
- 'inaddr': filename[0],
- 'fileorigin': None,
- })
- externalzonefile.write(self.templates['reverseapp'].render(context))
- self.filedata['%s.rev' % filename[0]] += zonefile.getvalue()
- self.filedata['%s.rev.external' % filename[0]] += externalzonefile.getvalue()
- zonefile.close()
- externalzonefile.close()
- self.Entries['ConfigFile']['%s/%s.rev' % (self.filepath, filename[0])] = self.FetchFile
- self.Entries['ConfigFile']['%s/%s.rev.external' % (self.filepath, filename[0])] = self.FetchFile
-
- ## here's where the named.conf file gets written
- context = Context({
- 'zones': zones,
- 'reverses': reversenames,
- })
- self.filedata['named.conf'] = self.templates['named'].render(context)
- self.Entries['ConfigFile']['/my/adm/hostbase/files/named.conf'] = self.FetchFile
- self.filedata['named.conf.views'] = self.templates['namedviews'].render(context)
- self.Entries['ConfigFile']['/my/adm/hostbase/files/named.conf.views'] = self.FetchFile
-
-
- def buildDHCP(self):
- """Pre-build dhcpd.conf and stash in the filedata table."""
-
- # fetches all the hosts with DHCP == True
- cursor = connection.cursor()
- cursor.execute("""
- SELECT hostname, mac_addr, ip_addr
- FROM (hostbase_host h INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip ip ON i.id = ip.interface_id
- WHERE i.dhcp=1 AND h.status='active' AND i.mac_addr <> ''
- AND i.mac_addr <> 'float' AND i.mac_addr <> 'unknown'
- ORDER BY h.hostname, i.mac_addr
- """)
-
- dhcphosts = cursor.fetchall()
- count = 0
- hosts = []
- hostdata = [dhcphosts[0][0], dhcphosts[0][1], dhcphosts[0][2]]
- if len(dhcphosts) > 1:
- for x in range(1, len(dhcphosts)):
- # if an interface has 2 or more ip addresses
- # adds the ip to the current interface
- if hostdata[0].split(".")[0] == dhcphosts[x][0].split(".")[0] and hostdata[1] == dhcphosts[x][1]:
- hostdata[2] = ", ".join([hostdata[2], dhcphosts[x][2]])
- # if a host has 2 or more interfaces
- # writes the current one and grabs the next
- elif hostdata[0].split(".")[0] == dhcphosts[x][0].split(".")[0]:
- hosts.append(hostdata)
- count += 1
- hostdata = ["-".join([dhcphosts[x][0], str(count)]), dhcphosts[x][1], dhcphosts[x][2]]
- # new host found, writes current data to the template
- else:
- hosts.append(hostdata)
- count = 0
- hostdata = [dhcphosts[x][0], dhcphosts[x][1], dhcphosts[x][2]]
- #makes sure the last of the data gets written out
- if hostdata not in hosts:
- hosts.append(hostdata)
-
- context = Context({
- 'hosts': hosts,
- 'numips': len(hosts),
- })
-
- self.filedata['dhcpd.conf'] = self.templates['dhcp'].render(context)
- self.Entries['ConfigFile']['/my/adm/hostbase/files/dhcpd.conf'] = self.FetchFile
-
-
- def buildHosts(self):
- """Pre-build and stash /etc/hosts file."""
-
- append_data = []
-
- cursor = connection.cursor()
- cursor.execute("""
- SELECT hostname FROM hostbase_host ORDER BY hostname
- """)
- hostbase = cursor.fetchall()
- domains = [host[0].split(".", 1)[1] for host in hostbase]
- domains_set = Set(domains)
- domain_data = [(domain, domains.count(domain)) for domain in domains_set]
- domain_data.sort()
-
- cursor.execute("""
- SELECT ip_addr FROM hostbase_ip ORDER BY ip_addr
- """)
- ips = cursor.fetchall()
- three_octets = [ip[0].rstrip('0123456789').rstrip('.') \
- for ip in ips]
- three_octets_set = Set(three_octets)
- three_octets_data = [(octet, three_octets.count(octet)) \
- for octet in three_octets_set]
- three_octets_data.sort()
-
- for three_octet in three_octets_data:
- querystring = """SELECT h.hostname, h.primary_user,
- p.ip_addr, n.name, c.cname
- 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)
- LEFT JOIN hostbase_cname c ON n.id = c.name_id
- WHERE p.ip_addr LIKE \'%s.%%%%\' AND h.status = 'active'""" % three_octet[0]
- cursor.execute(querystring)
- tosort = list(cursor.fetchall())
- tosort.sort(lambda x, y: cmp(int(x[2].split(".")[-1]), int(y[2].split(".")[-1])))
- append_data.append((three_octet, tuple(tosort)))
-
- two_octets = [ip.rstrip('0123456789').rstrip('.') for ip in three_octets]
- two_octets_set = Set(two_octets)
- two_octets_data = [(octet, two_octets.count(octet))
- for octet in two_octets_set]
- two_octets_data.sort()
-
- context = Context({
- 'domain_data': domain_data,
- 'three_octets_data': three_octets_data,
- 'two_octets_data': two_octets_data,
- 'three_octets': three_octets,
- 'num_ips': len(three_octets),
- })
-
- self.filedata['hosts'] = self.templates['hosts'].render(context)
-
- for subnet in append_data:
- ips = []
- simple = True
- namelist = [name.split('.', 1)[0] for name in [subnet[1][0][3]]]
- cnamelist = []
- if subnet[1][0][4]:
- cnamelist.append(subnet[1][0][4].split('.', 1)[0])
- simple = False
- appenddata = subnet[1][0]
- for ip in subnet[1][1:]:
- if appenddata[2] == ip[2]:
- namelist.append(ip[3].split('.', 1)[0])
- if ip[4]:
- cnamelist.append(ip[4].split('.', 1)[0])
- simple = False
- appenddata = ip
- else:
- if appenddata[0] == ip[0]:
- simple = False
- ips.append((appenddata[2], appenddata[0], Set(namelist),
- cnamelist, simple, appenddata[1]))
- appenddata = ip
- simple = True
- namelist = [ip[3].split('.', 1)[0]]
- cnamelist = []
- if ip[4]:
- cnamelist.append(ip[4].split('.', 1)[0])
- simple = False
- ips.append((appenddata[2], appenddata[0], Set(namelist),
- cnamelist, simple, appenddata[1]))
- context = Context({
- 'subnet': subnet[0],
- 'ips': ips,
- })
- self.filedata['hosts'] += self.templates['hostsapp'].render(context)
- self.Entries['ConfigFile']['/mcs/etc/hosts'] = self.FetchFile
-
- def buildPrinters(self):
- """The /mcs/etc/printers.data file"""
- header = """# This file is automatically generated. DO NOT EDIT IT!
-#
-Name Room User Type Notes
-============== ========== ============================== ======================== ====================
-"""
-
- cursor = connection.cursor()
- # fetches all the printers from the database
- cursor.execute("""
- SELECT printq, location, primary_user, comments
- FROM hostbase_host
- WHERE whatami='printer' AND printq <> '' AND status = 'active'
- ORDER BY printq
- """)
- printers = cursor.fetchall()
-
- printersfile = header
- for printer in printers:
- # splits up the printq line and gets the
- # correct description out of the comments section
- temp = printer[3].split('\n')
- for printq in re.split(',[ ]*', printer[0]):
- if len(temp) > 1:
- printersfile += ("%-16s%-12s%-32s%-26s%s\n" %
- (printq, printer[1], printer[2], temp[1], temp[0]))
- else:
- printersfile += ("%-16s%-12s%-32s%-26s%s\n" %
- (printq, printer[1], printer[2], '', printer[3]))
- self.filedata['printers.data'] = printersfile
- self.Entries['ConfigFile']['/mcs/etc/printers.data'] = self.FetchFile
-
- def buildHostsLPD(self):
- """Creates the /mcs/etc/hosts.lpd file"""
-
- # this header needs to be changed to be more generic
- header = """+@machines
-+@all-machines
-achilles.ctd.anl.gov
-raven.ops.anl.gov
-seagull.hr.anl.gov
-parrot.ops.anl.gov
-condor.ops.anl.gov
-delphi.esh.anl.gov
-anlcv1.ctd.anl.gov
-anlvms.ctd.anl.gov
-olivia.ctd.anl.gov\n\n"""
-
- cursor = connection.cursor()
- cursor.execute("""
- SELECT hostname FROM hostbase_host WHERE netgroup=\"red\" AND status = 'active'
- ORDER BY hostname""")
- redmachines = list(cursor.fetchall())
- cursor.execute("""
- SELECT n.name 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
- WHERE netgroup=\"red\" AND n.only=1 AND h.status = 'active'
- """)
- redmachines.extend(list(cursor.fetchall()))
- cursor.execute("""
- SELECT hostname FROM hostbase_host WHERE netgroup=\"win\" AND status = 'active'
- ORDER BY hostname""")
- winmachines = list(cursor.fetchall())
- cursor.execute("""
- SELECT n.name 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
- WHERE netgroup=\"win\" AND n.only=1 AND h.status = 'active'
- """)
- winmachines.__add__(list(cursor.fetchall()))
- hostslpdfile = header
- for machine in redmachines:
- hostslpdfile += machine[0] + "\n"
- hostslpdfile += "\n"
- for machine in winmachines:
- hostslpdfile += machine[0] + "\n"
- self.filedata['hosts.lpd'] = hostslpdfile
- self.Entries['ConfigFile']['/mcs/etc/hosts.lpd'] = self.FetchFile
-
-
- def buildNetgroups(self):
- """Makes the *-machine files"""
- header = """###################################################################
-# This file lists hosts in the '%s' machine netgroup, it is
-# automatically generated. DO NOT EDIT THIS FILE!
-#
-# Number of hosts in '%s' machine netgroup: %i
-#\n\n"""
-
- cursor = connection.cursor()
- # fetches all the hosts that with valid netgroup entries
- cursor.execute("""
- SELECT h.hostname, n.name, h.netgroup, n.only 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
- WHERE h.netgroup <> '' AND h.netgroup <> 'none' AND h.status = 'active'
- ORDER BY h.netgroup, h.hostname
- """)
- nameslist = cursor.fetchall()
- # gets the first host and initializes the hash
- hostdata = nameslist[0]
- netgroups = {hostdata[2]:[hostdata[0]]}
- for row in nameslist:
- # if new netgroup, create it
- if row[2] not in netgroups:
- netgroups.update({row[2]:[]})
- # if it belongs in the netgroup and has multiple interfaces, put them in
- if hostdata[0] == row[0] and row[3]:
- netgroups[row[2]].append(row[1])
- hostdata = row
- # if its a new host, write the old one to the hash
- elif hostdata[0] != row[0]:
- netgroups[row[2]].append(row[0])
- hostdata = row
-
- for netgroup in netgroups:
- fileoutput = cStringIO.StringIO()
- fileoutput.write(header % (netgroup, netgroup, len(netgroups[netgroup])))
- for each in netgroups[netgroup]:
- fileoutput.write(each + "\n")
- self.filedata['%s-machines' % netgroup] = fileoutput.getvalue()
- fileoutput.close()
- self.Entries['ConfigFile']['/my/adm/hostbase/makenets/machines/%s-machines' % netgroup] = self.FetchFile
-
- cursor.execute("""
- UPDATE hostbase_host SET dirty=0
- """)
diff --git a/build/lib/Bcfg2/Server/Plugins/Metadata.py b/build/lib/Bcfg2/Server/Plugins/Metadata.py
deleted file mode 100644
index 81fd3e173..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Metadata.py
+++ /dev/null
@@ -1,809 +0,0 @@
-"""This file stores persistent metadata for the Bcfg2 Configuration Repository."""
-
-__revision__ = '$Revision$'
-
-import copy
-import fcntl
-import lxml.etree
-import os
-import os.path
-import socket
-import time
-import Bcfg2.Server.Plugin
-
-class MetadataConsistencyError(Exception):
- """This error gets raised when metadata is internally inconsistent."""
- pass
-
-class MetadataRuntimeError(Exception):
- """This error is raised when the metadata engine is called prior to reading enough data."""
- pass
-
-class ClientMetadata(object):
- """This object contains client metadata."""
- def __init__(self, client, profile, groups, bundles,
- aliases, addresses, categories, uuid, password, query):
- self.hostname = client
- self.profile = profile
- self.bundles = bundles
- self.aliases = aliases
- self.addresses = addresses
- self.groups = groups
- self.categories = categories
- self.uuid = uuid
- self.password = password
- self.connectors = []
- self.query = query
-
- def inGroup(self, group):
- """Test to see if client is a member of group."""
- return group in self.groups
-
- def group_in_category(self, category):
- for grp in self.query.all_groups_in_category(category):
- if grp in self.groups:
- return grp
- return ''
-
-class MetadataQuery(object):
- def __init__(self, by_name, get_clients, by_groups, by_profiles, all_groups, all_groups_in_category):
- # resolver is set later
- self.by_name = by_name
- self.names_by_groups = by_groups
- self.names_by_profiles = by_profiles
- self.all_clients = get_clients
- self.all_groups = all_groups
- self.all_groups_in_category = all_groups_in_category
-
- def by_groups(self, groups):
- return [self.by_name(name) for name in self.names_by_groups(groups)]
-
- def by_profiles(self, profiles):
- return [self.by_name(name) for name in self.names_by_profiles(profiles)]
-
- def all(self):
- return [self.by_name(name) for name in self.all_clients()]
-
-class Metadata(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Metadata,
- Bcfg2.Server.Plugin.Statistics):
- """This class contains data for bcfg2 server metadata."""
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- name = "Metadata"
-
- def __init__(self, core, datastore, watch_clients=True):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Metadata.__init__(self)
- Bcfg2.Server.Plugin.Statistics.__init__(self)
- if watch_clients:
- try:
- core.fam.AddMonitor("%s/%s" % (self.data, "groups.xml"), self)
- core.fam.AddMonitor("%s/%s" % (self.data, "clients.xml"), self)
- except:
- print("Unable to add file monitor for groups.xml or clients.xml")
- raise Bcfg2.Server.Plugin.PluginInitError
- self.states = {}
- if watch_clients:
- self.states = {"groups.xml":False, "clients.xml":False}
- self.addresses = {}
- self.auth = dict()
- self.clients = {}
- self.aliases = {}
- self.groups = {}
- self.cgroups = {}
- self.public = []
- self.private = []
- self.profiles = []
- self.categories = {}
- self.bad_clients = {}
- self.uuid = {}
- self.secure = []
- self.floating = []
- self.passwords = {}
- self.session_cache = {}
- self.clientdata = None
- self.clientdata_original = None
- self.default = None
- self.pdirty = False
- self.extra = {'groups.xml':[], 'clients.xml':[]}
- self.password = core.password
- self.query = MetadataQuery(core.build_metadata,
- lambda:self.clients.keys(),
- self.get_client_names_by_groups,
- self.get_client_names_by_profiles,
- self.get_all_group_names,
- self.get_all_groups_in_category)
-
- @classmethod
- def init_repo(cls, repo, groups, os_selection, clients):
- path = '%s/%s' % (repo, cls.name)
- os.makedirs(path)
- open("%s/Metadata/groups.xml" %
- repo, "w").write(groups % os_selection)
- open("%s/Metadata/clients.xml" %
- repo, "w").write(clients % socket.getfqdn())
-
- def get_groups(self):
- '''return groups xml tree'''
- groups_tree = lxml.etree.parse(self.data + "/groups.xml")
- root = groups_tree.getroot()
- return root
-
- def search_group(self, group_name, tree):
- """Find a group."""
- for node in tree.findall("//Group"):
- if node.get("name") == group_name:
- return node
- for child in node:
- if child.tag == "Alias" and child.attrib["name"] == group_name:
- return node
- return None
-
- def add_group(self, group_name, attribs):
- """Add group to groups.xml."""
- tree = lxml.etree.parse(self.data + "/groups.xml")
- root = tree.getroot()
- element = lxml.etree.Element("Group", name=group_name)
- for key, val in attribs.iteritems():
- element.set(key, val)
- node = self.search_group(group_name, tree)
- if node != None:
- self.logger.error("Group \"%s\" already exists" % (group_name))
- raise MetadataConsistencyError
- root.append(element)
- group_tree = open(self.data + "/groups.xml","w")
- fd = group_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(group_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- group_tree.close()
-
- def update_group(self, group_name, attribs):
- """Update a groups attributes."""
- tree = lxml.etree.parse(self.data + "/groups.xml")
- root = tree.getroot()
- node = self.search_group(group_name, tree)
- if node == None:
- self.logger.error("Group \"%s\" not found" % (group_name))
- raise MetadataConsistencyError
- node.attrib.update(attribs)
- group_tree = open(self.data + "/groups.xml","w")
- fd = group_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(group_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- group_tree.close()
-
- def remove_group(self, group_name):
- """Remove a group."""
- tree = lxml.etree.parse(self.data + "/groups.xml")
- root = tree.getroot()
- node = self.search_group(group_name, tree)
- if node == None:
- self.logger.error("Client \"%s\" not found" % (group_name))
- raise MetadataConsistencyError
- root.remove(node)
- group_tree = open(self.data + "/groups.xml","w")
- fd = group_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(group_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- group_tree.close()
-
- def add_bundle(self, bundle_name):
- """Add bundle to groups.xml."""
- tree = lxml.etree.parse(self.data + "/groups.xml")
- root = tree.getroot()
- element = lxml.etree.Element("Bundle", name=bundle_name)
- node = self.search_group(bundle_name, tree)
- if node != None:
- self.logger.error("Bundle \"%s\" already exists" % (bundle_name))
- raise MetadataConsistencyError
- root.append(element)
- group_tree = open(self.data + "/groups.xml","w")
- fd = group_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(group_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- group_tree.close()
-
- def remove_bundle(self, bundle_name):
- """Remove a bundle."""
- tree = lxml.etree.parse(self.data + "/groups.xml")
- root = tree.getroot()
- node = self.search_group(bundle_name, tree)
- if node == None:
- self.logger.error("Bundle \"%s\" not found" % (bundle_name))
- raise MetadataConsistencyError
- root.remove(node)
- group_tree = open(self.data + "/groups.xml","w")
- fd = group_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(group_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- group_tree.close()
-
- def search_client(self, client_name, tree):
- """Find a client."""
- for node in tree.findall("//Client"):
- if node.get("name") == client_name:
- return node
- for child in node:
- if child.tag == "Alias" and child.attrib["name"] == client_name:
- return node
- return None
-
- def add_client(self, client_name, attribs):
- """Add client to clients.xml."""
- tree = lxml.etree.parse(self.data + "/clients.xml")
- root = tree.getroot()
- element = lxml.etree.Element("Client", name=client_name)
- for key, val in attribs.iteritems():
- element.set(key, val)
- node = self.search_client(client_name, tree)
- if node != None:
- self.logger.error("Client \"%s\" already exists" % (client_name))
- raise MetadataConsistencyError
- root.append(element)
- client_tree = open(self.data + "/clients.xml","w")
- fd = client_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(client_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- client_tree.close()
-
- def update_client(self, client_name, attribs):
- """Update a clients attributes."""
- tree = lxml.etree.parse(self.data + "/clients.xml")
- root = tree.getroot()
- node = self.search_client(client_name, tree)
- if node == None:
- self.logger.error("Client \"%s\" not found" % (client_name))
- raise MetadataConsistencyError
- node.attrib.update(attribs)
- client_tree = open(self.data + "/clients.xml","w")
- fd = client_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- tree.write(client_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- client_tree.close()
-
- def HandleEvent(self, event):
- """Handle update events for data files."""
- filename = event.filename.split('/')[-1]
- if filename in ['groups.xml', 'clients.xml']:
- dest = filename
- elif filename in reduce(lambda x, y:x+y, self.extra.values()):
- if event.code2str() == 'exists':
- return
- dest = [key for key, value in self.extra.iteritems() if filename in value][0]
- else:
- return
- if event.code2str() == 'endExist':
- return
- try:
- xdata = lxml.etree.parse("%s/%s" % (self.data, dest))
- except lxml.etree.XMLSyntaxError:
- self.logger.error('Failed to parse %s' % (dest))
- return
- included = [ent.get('href') for ent in \
- xdata.findall('./{http://www.w3.org/2001/XInclude}include')]
- xdata_original = copy.deepcopy(xdata)
- if included:
- for name in included:
- if name not in self.extra[dest]:
- self.core.fam.AddMonitor("%s/%s" % (self.data, name), self)
- self.extra[dest].append(name)
- try:
- xdata.xinclude()
- except lxml.etree.XIncludeError:
- self.logger.error("Failed to process XInclude for file %s" % dest)
-
- if dest == 'clients.xml':
- self.clients = {}
- self.aliases = {}
- self.raliases = {}
- self.bad_clients = {}
- self.secure = []
- self.floating = []
- self.addresses = {}
- self.raddresses = {}
- self.clientdata_original = xdata_original
- self.clientdata = xdata
- for client in xdata.findall('.//Client'):
- clname = client.get('name').lower()
- if 'address' in client.attrib:
- caddr = client.get('address')
- if caddr in self.addresses:
- self.addresses[caddr].append(clname)
- else:
- self.addresses[caddr] = [clname]
- if clname not in self.raddresses:
- self.raddresses[clname] = set()
- self.raddresses[clname].add(caddr)
- if 'auth' in client.attrib:
- self.auth[client.get('name')] = client.get('auth',
- 'cert+password')
- if 'uuid' in client.attrib:
- self.uuid[client.get('uuid')] = clname
- if client.get('secure', 'false') == 'true':
- self.secure.append(clname)
- if client.get('location', 'fixed') == 'floating':
- self.floating.append(clname)
- if 'password' in client.attrib:
- self.passwords[clname] = client.get('password')
- for alias in [alias for alias in client.findall('Alias')\
- if 'address' in alias.attrib]:
- if alias.get('address') in self.addresses:
- self.addresses[alias.get('address')].append(clname)
- else:
- self.addresses[alias.get('address')] = [clname]
- if clname not in self.raddresses:
- self.raddresses[clname] = set()
- self.raddresses[clname].add(alias.get('address'))
- self.clients.update({clname: client.get('profile')})
- [self.aliases.update({alias.get('name'): clname}) \
- for alias in client.findall('Alias')]
- self.raliases[clname] = set()
- [self.raliases[clname].add(alias.get('name')) for alias \
- in client.findall('Alias')]
- elif dest == 'groups.xml':
- self.public = []
- self.private = []
- self.profiles = []
- self.groups = {}
- grouptmp = {}
- self.categories = {}
- for group in xdata.xpath('//Groups/Group') \
- + xdata.xpath('Group'):
- grouptmp[group.get('name')] = tuple([[item.get('name') for item in group.findall(spec)]
- for spec in ['./Bundle', './Group']])
- grouptmp[group.get('name')][1].append(group.get('name'))
- if group.get('default', 'false') == 'true':
- self.default = group.get('name')
- if group.get('profile', 'false') == 'true':
- self.profiles.append(group.get('name'))
- if group.get('public', 'false') == 'true':
- self.public.append(group.get('name'))
- elif group.get('public', 'true') == 'false':
- self.private.append(group.get('name'))
- if 'category' in group.attrib:
- self.categories[group.get('name')] = group.get('category')
- for group in grouptmp:
- # self.groups[group] => (bundles, groups, categories)
- self.groups[group] = (set(), set(), {})
- tocheck = [group]
- group_cat = self.groups[group][2]
- while tocheck:
- now = tocheck.pop()
- self.groups[group][1].add(now)
- if now in grouptmp:
- (bundles, groups) = grouptmp[now]
- for ggg in [ggg for ggg in groups if ggg not in self.groups[group][1]]:
- if ggg not in self.categories or \
- self.categories[ggg] not in self.groups[group][2]:
- self.groups[group][1].add(ggg)
- tocheck.append(ggg)
- if ggg in self.categories:
- group_cat[self.categories[ggg]] = ggg
- elif ggg in self.categories:
- self.logger.info("Group %s: %s cat-suppressed %s" % \
- (group,
- group_cat[self.categories[ggg]],
- ggg))
- [self.groups[group][0].add(bund) for bund in bundles]
- self.states[dest] = True
- if False not in self.states.values():
- # check that all client groups are real and complete
- real = self.groups.keys()
- for client in self.clients.keys():
- if self.clients[client] not in self.profiles:
- self.logger.error("Client %s set as nonexistent or incomplete group %s" \
- % (client, self.clients[client]))
- self.logger.error("Removing client mapping for %s" % (client))
- self.bad_clients[client] = self.clients[client]
- del self.clients[client]
- for bclient in self.bad_clients.keys():
- if self.bad_clients[bclient] in self.profiles:
- self.logger.info("Restored profile mapping for client %s" % bclient)
- self.clients[bclient] = self.bad_clients[bclient]
- del self.bad_clients[bclient]
-
- def set_profile(self, client, profile, addresspair):
- """Set group parameter for provided client."""
- self.logger.info("Asserting client %s profile to %s" % (client, profile))
- if False in self.states.values():
- raise MetadataRuntimeError
- if profile not in self.public:
- self.logger.error("Failed to set client %s to private group %s" % (client, profile))
- raise MetadataConsistencyError
- if client in self.clients:
- self.logger.info("Changing %s group from %s to %s" % (client, self.clients[client], profile))
- cli = self.clientdata_original.xpath('.//Client[@name="%s"]' % (client))
- cli[0].set('profile', profile)
- else:
- self.logger.info("Creating new client: %s, profile %s" % \
- (client, profile))
- if addresspair in self.session_cache:
- # we are working with a uuid'd client
- lxml.etree.SubElement(self.clientdata_original.getroot(),
- 'Client',
- name=self.session_cache[addresspair][1],
- uuid=client, profile=profile,
- address=addresspair[0])
- else:
- lxml.etree.SubElement(self.clientdata_original.getroot(),
- 'Client', name=client,
- profile=profile)
- self.clients[client] = profile
- self.write_back_clients()
-
- def write_back_clients(self):
- """Write changes to client.xml back to disk."""
- try:
- datafile = open("%s/%s" % (self.data, 'clients.xml.new'), 'w')
- except IOError:
- self.logger.error("Failed to write clients.xml.new")
- raise MetadataRuntimeError
- # prep data
- dataroot = self.clientdata_original.getroot()
- if hasattr(dataroot, 'iter'):
- items = dataroot.iter()
- else:
- items = dataroot.getchildren()
- for item in items:
- # no items have text data of any sort
- item.tail = None
- item.text = None
- newcontents = lxml.etree.tostring(dataroot, pretty_print=True)
-
- fd = datafile.fileno()
- while self.locked(fd) == True:
- pass
- try:
- datafile.write(newcontents)
- except:
- fcntl.lockf(fd, fcntl.LOCK_UN)
- self.logger.error("Metadata: Failed to write new clients data to clients.xml.new", exc_info=1)
- os.unlink("%s/%s" % (self.data, "clients.xml.new"))
- raise MetadataRuntimeError
- datafile.close()
-
- # check if clients.xml is a symlink
- clientsxml = "%s/%s" % (self.data, 'clients.xml')
- if os.path.islink(clientsxml):
- clientsxml = os.readlink(clientsxml)
-
- try:
- os.rename("%s/%s" % (self.data, 'clients.xml.new'), clientsxml)
- except:
- self.logger.error("Metadata: Failed to rename clients.xml.new")
- raise MetadataRuntimeError
-
- def locked(self, fd):
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- return True
- return False
-
- def resolve_client(self, addresspair):
- """Lookup address locally or in DNS to get a hostname."""
- if addresspair in self.session_cache:
- (stamp, uuid) = self.session_cache[addresspair]
- if time.time() - stamp < 90:
- return self.session_cache[addresspair][1]
- address = addresspair[0]
- if address in self.addresses:
- if len(self.addresses[address]) != 1:
- self.logger.error("Address %s has multiple reverse assignments; a uuid must be used" % (address))
- raise MetadataConsistencyError
- return self.addresses[address][0]
- try:
- cname = socket.gethostbyaddr(address)[0].lower()
- if cname in self.aliases:
- return self.aliases[cname]
- return cname
- except socket.herror:
- warning = "address resolution error for %s" % (address)
- self.logger.warning(warning)
- raise MetadataConsistencyError
-
- def get_initial_metadata(self, client):
- """Return the metadata for a given client."""
- if False in self.states.values():
- raise MetadataRuntimeError
- client = client.lower()
- if client in self.aliases:
- client = self.aliases[client]
- if client in self.clients:
- profile = self.clients[client]
- (bundles, groups, categories) = self.groups[profile]
- else:
- if self.default == None:
- self.logger.error("Cannot set group for client %s; no default group set" % (client))
- raise MetadataConsistencyError
- self.set_profile(client, self.default, (None, None))
- profile = self.default
- [bundles, groups, categories] = self.groups[self.default]
- aliases = self.raliases.get(client, set())
- addresses = self.raddresses.get(client, set())
- newgroups = set(groups)
- newbundles = set(bundles)
- newcategories = {}
- newcategories.update(categories)
- if client in self.passwords:
- password = self.passwords[client]
- else:
- password = None
- uuids = [item for item, value in self.uuid.iteritems() if value == client]
- if uuids:
- uuid = uuids[0]
- else:
- uuid = None
- for group in self.cgroups.get(client, []):
- if group in self.groups:
- nbundles, ngroups, ncategories = self.groups[group]
- else:
- nbundles, ngroups, ncategories = ([], [group], {})
- [newbundles.add(b) for b in nbundles if b not in newbundles]
- [newgroups.add(g) for g in ngroups if g not in newgroups]
- newcategories.update(ncategories)
- return ClientMetadata(client, profile, newgroups, newbundles, aliases,
- addresses, newcategories, uuid, password, self.query)
-
- def get_all_group_names(self):
- all_groups = set()
- [all_groups.update(g[1]) for g in self.groups.values()]
- return all_groups
-
- def get_all_groups_in_category(self, category):
- all_groups = set()
- [all_groups.add(g) for g in self.categories \
- if self.categories[g] == category]
- return all_groups
-
- def get_client_names_by_profiles(self, profiles):
- return [client for client, profile in self.clients.iteritems() \
- if profile in profiles]
-
- def get_client_names_by_groups(self, groups):
- gprofiles = [profile for profile in self.profiles if \
- self.groups[profile][1].issuperset(groups)]
- return self.get_client_names_by_profiles(gprofiles)
-
- def merge_additional_groups(self, imd, groups):
- for group in groups:
- if group in self.categories and \
- self.categories[group] in imd.categories:
- continue
- nb, ng, _ = self.groups.get(group, (list(), [group], dict()))
- for b in nb:
- if b not in imd.bundles:
- imd.bundles.add(b)
- for g in ng:
- if g not in imd.groups:
- if g in self.categories and \
- self.categories[g] in imd.categories:
- continue
- if g in self.private:
- self.logger.error("Refusing to add dynamic membership in private group %s for client %s" % (g, imd.hostname))
- continue
- imd.groups.add(g)
-
- def merge_additional_data(self, imd, source, data):
- if not hasattr(imd, source):
- setattr(imd, source, data)
- imd.connectors.append(source)
-
- def validate_client_address(self, client, addresspair):
- """Check address against client."""
- address = addresspair[0]
- if client in self.floating:
- self.debug_log("Client %s is floating" % client)
- return True
- if address in self.addresses:
- if client in self.addresses[address]:
- self.debug_log("Client %s matches address %s" % (client, address))
- return True
- else:
- self.logger.error("Got request for non-float client %s from %s" \
- % (client, address))
- return False
- resolved = self.resolve_client(addresspair)
- if resolved.lower() == client.lower():
- return True
- else:
- self.logger.error("Got request for %s from incorrect address %s" \
- % (client, address))
- self.logger.error("Resolved to %s" % resolved)
- return False
-
- def AuthenticateConnection(self, cert, user, password, address):
- """This function checks auth creds."""
- if cert:
- id_method = 'cert'
- certinfo = dict([x[0] for x in cert['subject']])
- # look at cert.cN
- client = certinfo['commonName']
- self.debug_log("Got cN %s; using as client name" % client)
- auth_type = self.auth.get(client, 'cert+password')
- elif user == 'root':
- id_method = 'address'
- try:
- client = self.resolve_client(address)
- except MetadataConsistencyError:
- self.logger.error("Client %s failed to resolve; metadata problem" % (address[0]))
- return False
- else:
- id_method = 'uuid'
- # user maps to client
- if user not in self.uuid:
- client = user
- self.uuid[user] = user
- else:
- client = self.uuid[user]
-
- # we have the client name
- self.debug_log("Authenticating client %s" % client)
-
- # next we validate the address
- if id_method == 'uuid':
- addr_is_valid = True
- else:
- addr_is_valid = self.validate_client_address(client, address)
-
- if not addr_is_valid:
- return False
-
- if id_method == 'cert' and auth_type != 'cert+password':
- # we are done if cert+password not required
- return True
-
- if client not in self.passwords:
- if client in self.secure:
- self.logger.error("Client %s in secure mode but has no password" % (address[0]))
- return False
- if password != self.password:
- self.logger.error("Client %s used incorrect global password" % (address[0]))
- return False
- if client not in self.secure:
- if client in self.passwords:
- plist = [self.password, self.passwords[client]]
- else:
- plist = [self.password]
- if password not in plist:
- self.logger.error("Client %s failed to use either allowed password" % \
- (address[0]))
- return False
- else:
- # client in secure mode and has a client password
- if password != self.passwords[client]:
- self.logger.error("Client %s failed to use client password in secure mode" % \
- (address[0]))
- return False
- # populate the session cache
- if user != 'root':
- self.session_cache[address] = (time.time(), client)
- return True
-
- def process_statistics(self, meta, _):
- """Hook into statistics interface to toggle clients in bootstrap mode."""
- client = meta.hostname
- if client in self.auth and self.auth[client] == 'bootstrap':
- self.logger.info("Asserting client %s auth mode to cert" % client)
- cli = self.clientdata_original.xpath('.//Client[@name="%s"]' \
- % (client))
- cli[0].set('auth', 'cert')
- self.write_back_clients()
-
- def viz(self, hosts, bundles, key, colors):
- """Admin mode viz support."""
- groups_tree = lxml.etree.parse(self.data + "/groups.xml")
- try:
- groups_tree.xinclude()
- except lxml.etree.XincludeError:
- self.logger.error("Failed to process XInclude for file %s" % dest)
- groups = groups_tree.getroot()
- categories = {'default':'grey83'}
- instances = {}
- viz_str = ""
- egroups = groups.findall("Group") + groups.findall('.//Groups/Group')
- for group in egroups:
- if not group.get('category') in categories:
- categories[group.get('category')] = colors.pop()
- group.set('color', categories[group.get('category')])
- if None in categories:
- del categories[None]
- if hosts:
- clients = self.clients
- for client, profile in clients.iteritems():
- if profile in instances:
- instances[profile].append(client)
- else:
- instances[profile] = [client]
- for profile, clist in instances.iteritems():
- clist.sort()
- viz_str += '''\t"%s-instances" [ label="%s", shape="record" ];\n''' \
- % (profile, '|'.join(clist))
- viz_str += '''\t"%s-instances" -> "group-%s";\n''' \
- % (profile, profile)
- if bundles:
- bundles = []
- [bundles.append(bund.get('name')) \
- for bund in groups.findall('.//Bundle') \
- if bund.get('name') not in bundles]
- bundles.sort()
- for bundle in bundles:
- viz_str += '''\t"bundle-%s" [ label="%s", shape="septagon"];\n''' \
- % (bundle, bundle)
- gseen = []
- for group in egroups:
- if group.get('profile', 'false') == 'true':
- style = "filled, bold"
- else:
- style = "filled"
- gseen.append(group.get('name'))
- viz_str += '\t"group-%s" [label="%s", style="%s", fillcolor=%s];\n' % \
- (group.get('name'), group.get('name'), style, group.get('color'))
- if bundles:
- for bundle in group.findall('Bundle'):
- viz_str += '\t"group-%s" -> "bundle-%s";\n' % \
- (group.get('name'), bundle.get('name'))
- gfmt = '\t"group-%s" [label="%s", style="filled", fillcolor="grey83"];\n'
- for group in egroups:
- for parent in group.findall('Group'):
- if parent.get('name') not in gseen:
- viz_str += gfmt % (parent.get('name'), parent.get('name'))
- gseen.append(parent.get("name"))
- viz_str += '\t"group-%s" -> "group-%s" ;\n' % \
- (group.get('name'), parent.get('name'))
- if key:
- for category in categories:
- viz_str += '''\t"''' + category + '''" [label="''' + category + \
- '''", shape="record", style="filled", fillcolor=''' + \
- categories[category] + '''];\n'''
- return viz_str
diff --git a/build/lib/Bcfg2/Server/Plugins/NagiosGen.py b/build/lib/Bcfg2/Server/Plugins/NagiosGen.py
deleted file mode 100644
index cd6f843fb..000000000
--- a/build/lib/Bcfg2/Server/Plugins/NagiosGen.py
+++ /dev/null
@@ -1,114 +0,0 @@
-'''This module implements a Nagios configuration generator'''
-
-import glob
-import logging
-import os
-import re
-import socket
-
-import Bcfg2.Server.Plugin
-
-LOGGER = logging.getLogger('Bcfg2.Plugins.NagiosGen')
-
-host_config_fmt = \
-'''
-define host{
- host_name %s
- alias %s
- address %s
-'''
-
-class NagiosGen(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Generator):
- """NagiosGen is a Bcfg2 plugin that dynamically generates
- Nagios configuration file based on Bcfg2 data.
- """
- name = 'NagiosGen'
- __version__ = '0.6'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- self.Entries = {'Path':
- {'/etc/nagiosgen.status' : self.createhostconfig,
- '/etc/nagios/nagiosgen.cfg': self.createserverconfig}}
-
- self.client_attrib = {'encoding':'ascii',
- 'owner':'root',
- 'group':'root',
- 'type':'file',
- 'perms':'0400'}
- self.server_attrib = {'encoding':'ascii',
- 'owner':'nagios',
- 'group':'nagios',
- 'type':'file',
- 'perms':'0440'}
-
- def createhostconfig(self, entry, metadata):
- """Build host specific configuration file."""
- host_address = socket.gethostbyname(metadata.hostname)
- host_groups = [grp for grp in metadata.groups if \
- os.path.isfile('%s/%s-group.cfg' % (self.data, grp))]
- host_config = host_config_fmt % \
- (metadata.hostname, metadata.hostname, host_address)
-
- if host_groups:
- host_config += ' hostgroups %s\n' % (",".join(host_groups))
-
- xtra = None
- if hasattr(metadata, 'Properties') and \
- 'NagiosGen.xml' in metadata.Properties:
- for q in (metadata.hostname, 'default'):
- xtra = metadata.Properties['NagiosGen.xml'].data.find(q)
- if xtra is not None:
- break
-
- if xtra is not None:
- directives = list(xtra)
- for item in directives:
- host_config += ' %-32s %s\n' % (item.tag, item.text)
-
- else:
- host_config += ' use default\n'
-
- host_config += '}\n'
- entry.text = host_config
- [entry.attrib.__setitem__(key, value) for \
- (key, value) in self.client_attrib.iteritems()]
- try:
- fileh = open("%s/%s-host.cfg" % \
- (self.data, metadata.hostname), 'w')
- fileh.write(host_config)
- fileh.close()
- except OSError, ioerr:
- LOGGER.error("Failed to write %s/%s-host.cfg" % \
- (self.data, metadata.hostname))
- LOGGER.error(ioerr)
-
- def createserverconfig(self, entry, _):
- """Build monolithic server configuration file."""
- host_configs = glob.glob('%s/*-host.cfg' % self.data)
- group_configs = glob.glob('%s/*-group.cfg' % self.data)
- host_data = ""
- group_data = ""
- for host in host_configs:
- hostfile = open(host, 'r')
- host_data += hostfile.read()
- hostfile.close()
- for group in group_configs:
- group_name = re.sub("(-group.cfg|.*/(?=[^/]+))", "", group)
- if host_data.find(group_name) != -1:
- groupfile = open(group, 'r')
- group_data += groupfile.read()
- groupfile.close()
- entry.text = group_data + host_data
- [entry.attrib.__setitem__(key, value) for \
- (key, value) in self.server_attrib.iteritems()]
- try:
- fileh = open("%s/nagiosgen.cfg" % (self.data), 'w')
- fileh.write(group_data + host_data)
- fileh.close()
- except OSError, ioerr:
- LOGGER.error("Failed to write %s/nagiosgen.cfg" % (self.data))
- LOGGER.error(ioerr)
diff --git a/build/lib/Bcfg2/Server/Plugins/Ohai.py b/build/lib/Bcfg2/Server/Plugins/Ohai.py
deleted file mode 100644
index 0f7c7187f..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Ohai.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import lxml.etree
-import os
-
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Ohai')
-
-import Bcfg2.Server.Plugin
-
-try:
- import json
-except:
- # FIXME: can be removed when server prereq is >= python 2.6
- # necessary for clients without the in-tree json module
- try:
- import simplejson as json
- except:
- logger.error("Unable to load any json modules. Make sure "
- "python-simplejson is installed.")
- raise ImportError
-
-
-class OhaiCache(object):
-
- def __init__(self, dirname):
- self.dirname = dirname
- self.cache = dict()
-
- def __setitem__(self, item, value):
- if value == None:
- # simply return if the client returned nothing
- return
- self.cache[item] = json.loads(value)
- file("%s/%s.json" % (self.dirname, item), 'w').write(value)
-
- def __getitem__(self, item):
- if item not in self.cache:
- try:
- data = open("%s/%s.json" % (self.dirname, item)).read()
- except:
- raise KeyError, item
- self.cache[item] = json.loads(data)
- return self.cache[item]
-
- def __iter__(self):
- data = self.cache.keys()
- data.extend([x[:-5] for x in os.listdir(self.dirname)])
- return data.__iter__()
-
-
-class Ohai(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Probing,
- Bcfg2.Server.Plugin.Connector):
- """The Ohai plugin is used to detect information about the client operating system."""
- name = 'Ohai'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Probing.__init__(self)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- self.probe = lxml.etree.Element('probe', name='Ohai', source='Ohai',
- interpreter='/bin/sh')
- self.probe.text = 'ohai'
- try:
- os.stat(self.data)
- except:
- os.makedirs(self.data)
- self.cache = OhaiCache(self.data)
-
- def GetProbes(self, meta, force=False):
- return [self.probe]
-
- def ReceiveData(self, meta, datalist):
- self.cache[meta.hostname] = datalist[0].text
-
- def get_additional_data(self, meta):
- if meta.hostname in self.cache:
- return self.cache[meta.hostname]
- return dict()
diff --git a/build/lib/Bcfg2/Server/Plugins/Packages.py b/build/lib/Bcfg2/Server/Plugins/Packages.py
deleted file mode 100644
index 194330723..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Packages.py
+++ /dev/null
@@ -1,869 +0,0 @@
-import cPickle
-import copy
-import gzip
-import tarfile
-import glob
-import logging
-import lxml.etree
-import os
-import re
-import sys
-import urllib2
-
-# FIXME: Remove when server python dep is 2.5 or greater
-if sys.version_info >= (2, 5):
- from hashlib import md5
-else:
- from md5 import md5
-
-import Bcfg2.Logger
-import Bcfg2.Server.Plugin
-
-# build sources.list?
-# caching for yum
-
-class NoData(Exception):
- pass
-
-class SomeData(Exception):
- pass
-
-logger = logging.getLogger('Packages')
-
-def source_from_xml(xsource):
- ret = dict([('rawurl', False), ('url', False)])
- for key, tag in [('groups', 'Group'), ('components', 'Component'),
- ('arches', 'Arch'), ('blacklist', 'Blacklist'),
- ('whitelist', 'Whitelist')]:
- ret[key] = [item.text for item in xsource.findall(tag)]
- # version and component need to both contain data for sources to work
- try:
- ret['version'] = xsource.find('Version').text
- except:
- ret['version'] = 'placeholder'
- if ret['components'] == []:
- ret['components'] = ['placeholder']
- try:
- if xsource.find('Recommended').text in ['True', 'true']:
- ret['recommended'] = True
- else:
- ret['recommended'] = False
- except:
- ret['recommended'] = False
- if xsource.find('RawURL') is not None:
- ret['rawurl'] = xsource.find('RawURL').text
- if not ret['rawurl'].endswith('/'):
- ret['rawurl'] += '/'
- else:
- ret['url'] = xsource.find('URL').text
- if not ret['url'].endswith('/'):
- ret['url'] += '/'
- return ret
-
-def _fetch_url(url):
- if '@' in url:
- mobj = re.match('(\w+://)([^:]+):([^@]+)@(.*)$', url)
- if not mobj:
- raise ValueError
- user = mobj.group(2)
- passwd = mobj.group(3)
- url = mobj.group(1) + mobj.group(4)
- auth = urllib2.HTTPBasicAuthHandler(urllib2.HTTPPasswordMgrWithDefaultRealm())
- auth.add_password(None, url, user, passwd)
- urllib2.install_opener(urllib2.build_opener(auth))
- return urllib2.urlopen(url).read()
-
-class Source(object):
- basegroups = []
-
- def __init__(self, basepath, url, version, arches, components, groups, rawurl,
- blacklist, whitelist, recommended):
- self.basepath = basepath
- self.version = version
- self.components = components
- self.url = url
- self.rawurl = rawurl
- self.groups = groups
- self.arches = arches
- self.deps = dict()
- self.provides = dict()
- self.blacklist = set(blacklist)
- self.whitelist = set(whitelist)
- self.cachefile = '%s/cache-%s' % (self.basepath, md5(cPickle.dumps( \
- [self.version, self.components, self.url, \
- self.rawurl, self.groups, self.arches])).hexdigest())
- self.recommended = recommended
- self.url_map = []
-
- def load_state(self):
- pass
-
- def setup_data(self, force_update=False):
- should_read = True
- should_download = False
- if os.path.exists(self.cachefile):
- try:
- self.load_state()
- should_read = False
- except:
- logger.error("Cachefile %s load failed; falling back to file read"\
- % (self.cachefile))
- if should_read:
- try:
- self.read_files()
- except:
- logger.error("Packages: File read failed; falling back to file download")
- should_download = True
-
- if should_download or force_update:
- try:
- self.update()
- self.read_files()
- except:
- logger.error("Failed to update source", exc_info=1)
-
- def get_urls(self):
- return []
- urls = property(get_urls)
-
- def get_files(self):
- return [self.escape_url(url) for url in self.urls]
- files = property(get_files)
-
- def get_vpkgs(self, meta):
- agroups = ['global'] + [a for a in self.arches if a in meta.groups]
- vdict = dict()
- for agrp in agroups:
- for key, value in self.provides[agrp].iteritems():
- if key not in vdict:
- vdict[key] = set(value)
- else:
- vdict[key].update(value)
- return vdict
-
- def escape_url(self, url):
- return "%s/%s" % (self.basepath, url.replace('/', '@'))
-
- def file_init(self):
- pass
-
- def read_files(self):
- pass
-
- def update(self):
- for url in self.urls:
- logger.info("Packages: Updating %s" % url)
- fname = self.escape_url(url)
- try:
- data = _fetch_url(url)
- except ValueError:
- logger.error("Packages: Bad url string %s" % url)
- continue
- except urllib2.HTTPError, h:
- logger.error("Packages: Failed to fetch url %s. code=%s" \
- % (url, h.code))
- continue
- file(fname, 'w').write(data)
-
- def applies(self, metadata):
- return len([g for g in self.basegroups if g in metadata.groups]) != 0 and \
- len([g for g in metadata.groups if g in self.groups]) \
- == len(self.groups)
-
- def get_arches(self, metadata):
- return ['global'] + [a for a in self.arches if a in metadata.groups]
-
- def get_deps(self, metadata, pkgname):
- for arch in self.get_arches(metadata):
- if pkgname in self.deps[arch]:
- return self.deps[arch][pkgname]
- raise NoData
-
- def get_provides(self, metadata, required):
- for arch in self.get_arches(metadata):
- if required in self.provides[arch]:
- return self.provides[arch][required]
- raise NoData
-
- def is_package(self, metadata, _):
- return False
-
- def get_url_info(self):
- return {'groups': copy.copy(self.groups), \
- 'urls': [copy.deepcopy(url) for url in self.url_map]}
-
-class YUMSource(Source):
- xp = '{http://linux.duke.edu/metadata/common}'
- rp = '{http://linux.duke.edu/metadata/rpm}'
- rpo = '{http://linux.duke.edu/metadata/repo}'
- fl = '{http://linux.duke.edu/metadata/filelists}'
- basegroups = ['yum', 'redhat', 'centos', 'fedora']
- ptype = 'yum'
-
- def __init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended):
- Source.__init__(self, basepath, url, version, arches, components,
- groups, rawurl, blacklist, whitelist, recommended)
- if not self.rawurl:
- self.baseurl = self.url + '%(version)s/%(component)s/%(arch)s/'
- else:
- self.baseurl = self.rawurl
- self.packages = dict()
- self.deps = dict([('global', dict())])
- self.provides = dict([('global', dict())])
- self.filemap = dict([(x, dict()) for x in ['global'] + self.arches])
- self.needed_paths = set()
- self.file_to_arch = dict()
-
- def save_state(self):
- cache = file(self.cachefile, 'wb')
- cPickle.dump((self.packages, self.deps, self.provides,
- self.filemap, self.url_map), cache, 2)
- cache.close()
-
- def load_state(self):
- data = file(self.cachefile)
- (self.packages, self.deps, self.provides, \
- self.filemap, self.url_map) = cPickle.load(data)
-
- def get_urls(self):
- surls = list()
- self.url_map = []
- for arch in self.arches:
- usettings = [{'version': self.version, 'component':comp,
- 'arch':arch} for comp in self.components]
- for setting in usettings:
- setting['groups'] = self.groups
- setting['url'] = self.baseurl % setting
- self.url_map.append(copy.deepcopy(setting))
- surls.append((arch, [setting['url'] for setting in usettings]))
- urls = []
- for (sarch, surl_list) in surls:
- for surl in surl_list:
- if not surl.endswith('/'):
- surl += '/'
- rmdurl = surl + 'repodata/repomd.xml'
- try:
- repomd = _fetch_url(rmdurl)
- xdata = lxml.etree.XML(repomd)
- except ValueError:
- logger.error("Packages: Bad url string %s" % rmdurl)
- continue
- except urllib2.HTTPError, h:
- logger.error("Packages: Failed to fetch url %s. code=%s" \
- % (rmdurl, h.code))
- continue
- except:
- logger.error("Failed to process url %s" % rmdurl)
- continue
- for elt in xdata.findall(self.rpo + 'data'):
- if elt.get('type') not in ['filelists', 'primary']:
- continue
- floc = elt.find(self.rpo + 'location')
- fullurl = surl + floc.get('href')
- urls.append(fullurl)
- self.file_to_arch[self.escape_url(fullurl)] = sarch
- return urls
- urls = property(get_urls)
-
- def read_files(self):
- for fname in [f for f in self.files if f.endswith('primary.xml.gz')]:
- farch = self.file_to_arch[fname]
- fdata = lxml.etree.parse(fname).getroot()
- self.parse_primary(fdata, farch)
- for fname in [f for f in self.files if f.endswith('filelists.xml.gz')]:
- farch = self.file_to_arch[fname]
- fdata = lxml.etree.parse(fname).getroot()
- self.parse_filelist(fdata, farch)
- # merge data
- sdata = self.packages.values()
- self.packages['global'] = copy.deepcopy(sdata.pop())
- while sdata:
- self.packages['global'].intersection(sdata.pop())
-
- for key in self.packages:
- if key == 'global':
- continue
- self.packages[key] = self.packages['global'].difference(self.packages[key])
- self.save_state()
-
- def parse_filelist(self, data, arch):
- if arch not in self.filemap:
- self.filemap[arch] = dict()
- for pkg in data.findall(self.fl + 'package'):
- for fentry in [fe for fe in pkg.findall(self.fl + 'file') \
- if fe.text in self.needed_paths]:
- if fentry.text in self.filemap[arch]:
- self.filemap[arch][fentry.text].add(pkg.get('name'))
- else:
- self.filemap[arch][fentry.text] = set([pkg.get('name')])
-
- def parse_primary(self, data, arch):
- if arch not in self.packages:
- self.packages[arch] = set()
- if arch not in self.deps:
- self.deps[arch] = dict()
- if arch not in self.provides:
- self.provides[arch] = dict()
- for pkg in data.getchildren():
- if not pkg.tag.endswith('package'):
- continue
- pkgname = pkg.find(self.xp + 'name').text
- self.packages[arch].add(pkgname)
-
- pdata = pkg.find(self.xp + 'format')
- pre = pdata.find(self.rp + 'requires')
- self.deps[arch][pkgname] = set()
- for entry in pre.getchildren():
- self.deps[arch][pkgname].add(entry.get('name'))
- if entry.get('name').startswith('/'):
- self.needed_paths.add(entry.get('name'))
- pro = pdata.find(self.rp + 'provides')
- if pro != None:
- for entry in pro.getchildren():
- prov = entry.get('name')
- if prov not in self.provides[arch]:
- self.provides[arch][prov] = list()
- self.provides[arch][prov].append(pkgname)
-
- def is_package(self, metadata, item):
- arch = [a for a in self.arches if a in metadata.groups]
- if not arch:
- return False
- return (item in self.packages['global'] or item in self.packages[arch[0]]) and \
- item not in self.blacklist and \
- ((len(self.whitelist) == 0) or item in self.whitelist)
-
- def get_vpkgs(self, metadata):
- rv = Source.get_vpkgs(self, metadata)
- for arch, fmdata in self.filemap.iteritems():
- if arch not in metadata.groups and arch != 'global':
- continue
- for filename, pkgs in fmdata.iteritems():
- rv[filename] = pkgs
- return rv
-
- def filter_unknown(self, unknown):
- filtered = set([u for u in unknown if u.startswith('rpmlib')])
- unknown.difference_update(filtered)
-
-class APTSource(Source):
- basegroups = ['apt', 'debian', 'ubuntu', 'nexenta']
- ptype = 'deb'
-
- def __init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended):
- Source.__init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended)
- self.pkgnames = set()
-
- self.url_map = [{'rawurl': self.rawurl, 'url': self.url, 'version': self.version, \
- 'components': self.components, 'arches': self.arches, 'groups': self.groups}]
-
- def save_state(self):
- cache = file(self.cachefile, 'wb')
- cPickle.dump((self.pkgnames, self.deps, self.provides),
- cache, 2)
- cache.close()
-
- def load_state(self):
- data = file(self.cachefile)
- self.pkgnames, self.deps, self.provides = cPickle.load(data)
-
- def filter_unknown(self, unknown):
- filtered = set([u for u in unknown if u.startswith('choice')])
- unknown.difference_update(filtered)
-
- def get_urls(self):
- if not self.rawurl:
- return ["%sdists/%s/%s/binary-%s/Packages.gz" % \
- (self.url, self.version, part, arch) for part in self.components \
- for arch in self.arches]
- else:
- return ["%sPackages.gz" % (self.rawurl)]
- urls = property(get_urls)
-
- def read_files(self):
- bdeps = dict()
- bprov = dict()
- if self.recommended:
- depfnames = ['Depends', 'Pre-Depends', 'Recommends']
- else:
- depfnames = ['Depends', 'Pre-Depends']
- for fname in self.files:
- if not self.rawurl:
- barch = [x for x in fname.split('@') if x.startswith('binary-')][0][7:]
- else:
- # RawURL entries assume that they only have one <Arch></Arch>
- # element and that it is the architecture of the source.
- barch = self.arches[0]
- if barch not in bdeps:
- bdeps[barch] = dict()
- bprov[barch] = dict()
- try:
- reader = gzip.GzipFile(fname)
- except:
- print("Failed to read file %s" % fname)
- raise
- for line in reader.readlines():
- words = line.strip().split(':', 1)
- if words[0] == 'Package':
- pkgname = words[1].strip().rstrip()
- self.pkgnames.add(pkgname)
- bdeps[barch][pkgname] = []
- elif words[0] in depfnames:
- vindex = 0
- for dep in words[1].split(','):
- if '|' in dep:
- cdeps = [re.sub('\s+', '', re.sub('\(.*\)', '', cdep)) for cdep in dep.split('|')]
- dyn_dname = "choice-%s-%s-%s" % (pkgname, barch, vindex)
- vindex += 1
- bdeps[barch][pkgname].append(dyn_dname)
- bprov[barch][dyn_dname] = set(cdeps)
- else:
- raw_dep = re.sub('\(.*\)', '', dep)
- raw_dep = raw_dep.rstrip().strip()
- bdeps[barch][pkgname].append(raw_dep)
- elif words[0] == 'Provides':
- for pkg in words[1].split(','):
- dname = pkg.rstrip().strip()
- if dname not in bprov[barch]:
- bprov[barch][dname] = set()
- bprov[barch][dname].add(pkgname)
-
- self.deps['global'] = dict()
- self.provides['global'] = dict()
- for barch in bdeps:
- self.deps[barch] = dict()
- self.provides[barch] = dict()
- for pkgname in self.pkgnames:
- pset = set()
- for barch in bdeps:
- if pkgname not in bdeps[barch]:
- bdeps[barch][pkgname] = []
- pset.add(tuple(bdeps[barch][pkgname]))
- if len(pset) == 1:
- self.deps['global'][pkgname] = pset.pop()
- else:
- for barch in bdeps:
- self.deps[barch][pkgname] = bdeps[barch][pkgname]
- provided = set()
- for bprovided in bprov.values():
- provided.update(set(bprovided))
- for prov in provided:
- prset = set()
- for barch in bprov:
- if prov not in bprov[barch]:
- continue
- prset.add(tuple(bprov[barch].get(prov, ())))
- if len(prset) == 1:
- self.provides['global'][prov] = prset.pop()
- else:
- for barch in bprov:
- self.provides[barch][prov] = bprov[barch].get(prov, ())
- self.save_state()
-
- def is_package(self, _, pkg):
- return pkg in self.pkgnames and \
- pkg not in self.blacklist and \
- (len(self.whitelist) == 0 or pkg in self.whitelist)
-
-class PACSource(Source):
- basegroups = ['arch', 'parabola']
- ptype = 'pacman'
-
- def __init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended):
- Source.__init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended)
- self.pkgnames = set()
-
- self.url_map = [{'rawurl': self.rawurl, 'url': self.url, 'version': self.version, \
- 'components': self.components, 'arches': self.arches, 'groups': self.groups}]
-
- def save_state(self):
- cache = file(self.cachefile, 'wb')
- cPickle.dump((self.pkgnames, self.deps, self.provides),
- cache, 2)
- cache.close()
-
- def load_state(self):
- data = file(self.cachefile)
- self.pkgnames, self.deps, self.provides = cPickle.load(data)
-
- def filter_unknown(self, unknown):
- filtered = set([u for u in unknown if u.startswith('choice')])
- unknown.difference_update(filtered)
-
- def get_urls(self):
- if not self.rawurl:
- return ["%s/%s/os/%s/%s.db.tar.gz" % \
- (self.url, part, arch, part) for part in self.components \
- for arch in self.arches]
- else:
- raise Exception("PACSource : RAWUrl not supported (yet)")
- urls = property(get_urls)
-
-
- def read_files(self):
- bdeps = dict()
- bprov = dict()
-
- if self.recommended:
- depfnames = ['Depends', 'Pre-Depends', 'Recommends']
- else:
- depfnames = ['Depends', 'Pre-Depends']
-
- for fname in self.files:
- if not self.rawurl:
- barch = [x for x in fname.split('@') if x in self.arches][0]
- else:
- # RawURL entries assume that they only have one <Arch></Arch>
- # element and that it is the architecture of the source.
- barch = self.arches[0]
-
- if barch not in bdeps:
- bdeps[barch] = dict()
- bprov[barch] = dict()
- try:
- print "try to read : " + fname
- tar = tarfile.open(fname, "r")
- reader = gzip.GzipFile(fname)
- except:
- print("Failed to read file %s" % fname)
- raise
-
- for tarinfo in tar:
- if tarinfo.isdir():
- self.pkgnames.add(tarinfo.name.rsplit("-",2)[0])
- print "added : " + tarinfo.name.rsplit("-",2)[0]
- tar.close()
-
- self.deps['global'] = dict()
- self.provides['global'] = dict()
- for barch in bdeps:
- self.deps[barch] = dict()
- self.provides[barch] = dict()
- for pkgname in self.pkgnames:
- pset = set()
- for barch in bdeps:
- if pkgname not in bdeps[barch]:
- bdeps[barch][pkgname] = []
- pset.add(tuple(bdeps[barch][pkgname]))
- if len(pset) == 1:
- self.deps['global'][pkgname] = pset.pop()
- else:
- for barch in bdeps:
- self.deps[barch][pkgname] = bdeps[barch][pkgname]
- provided = set()
- for bprovided in bprov.values():
- provided.update(set(bprovided))
- for prov in provided:
- prset = set()
- for barch in bprov:
- if prov not in bprov[barch]:
- continue
- prset.add(tuple(bprov[barch].get(prov, ())))
- if len(prset) == 1:
- self.provides['global'][prov] = prset.pop()
- else:
- for barch in bprov:
- self.provides[barch][prov] = bprov[barch].get(prov, ())
- self.save_state()
-
- def is_package(self, _, pkg):
- return pkg in self.pkgnames and \
- pkg not in self.blacklist and \
- (len(self.whitelist) == 0 or pkg in self.whitelist)
-
-class Packages(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.StructureValidator,
- Bcfg2.Server.Plugin.Generator,
- Bcfg2.Server.Plugin.Connector):
- name = 'Packages'
- conflicts = ['Pkgmgr']
- experimental = True
- __rmi__ = Bcfg2.Server.Plugin.Plugin.__rmi__ + ['Refresh', 'Reload']
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.StructureValidator.__init__(self)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- self.cachepath = self.data + '/cache'
- self.sentinels = set()
- self.sources = []
- self.disableResolver = False
- self.disableMetaData = False
- self.virt_pkgs = dict()
-
- if not os.path.exists(self.cachepath):
- # create cache directory if needed
- os.makedirs(self.cachepath)
- self._load_config()
-
- def get_relevant_groups(self, meta):
- mgrps = list(set([g for g in meta.groups for s in self.get_matching_sources(meta) \
- if g in s.basegroups or g in s.groups or g in s.arches]))
- mgrps.sort()
- return tuple(mgrps)
-
- def build_vpkgs_entry(self, meta):
- # build single entry for all matching sources
- mgrps = self.get_relevant_groups(meta)
- vpkgs = dict()
- for source in self.get_matching_sources(meta):
- s_vpkgs = source.get_vpkgs(meta)
- for name, prov_set in s_vpkgs.iteritems():
- if name not in vpkgs:
- vpkgs[name] = set(prov_set)
- else:
- vpkgs[name].update(prov_set)
- return vpkgs
-
- def get_matching_sources(self, meta):
- return [s for s in self.sources if s.applies(meta)]
-
- def HandlesEntry(self, entry, metadata):
- if [x for x in metadata.groups if x in self.sentinels] \
- and entry.tag == 'Package':
- return True
- return False
-
- def HandleEntry(self, entry, metadata):
- entry.set('version', 'auto')
- for source in self.sources:
- if [x for x in metadata.groups if x in source.basegroups]:
- entry.set('type', source.ptype)
-
- def complete(self, meta, input_requirements, debug=False):
- '''Build the transitive closure of all package dependencies
-
- Arguments:
- meta - client metadata instance
- packages - set of package names
- debug - print out debug information for the decision making process
- returns => (set(packages), set(unsatisfied requirements), package type)
- '''
- sources = self.get_matching_sources(meta)
- # reverse list so that priorities correspond to file order
- sources.reverse()
- if len(sources) == 0:
- self.logger.error("Packages: No matching sources for client %s; improper group memberships?" % (meta.hostname))
- return set(), set(), 'failed'
- ptype = set([s.ptype for s in sources])
- if len(ptype) < 1:
- return set(), set(), 'failed'
-
- # setup vpkg cache
- pgrps = self.get_relevant_groups(meta)
- if pgrps not in self.virt_pkgs:
- self.virt_pkgs[pgrps] = self.build_vpkgs_entry(meta)
- vpkg_cache = self.virt_pkgs[pgrps]
-
- # unclassified is set of unsatisfied requirements (may be pkg for vpkg)
- unclassified = set(input_requirements)
- vpkgs = set()
- both = set()
- pkgs = set(input_requirements)
-
- packages = set()
- examined = set()
- unknown = set()
-
- final_pass = False
- really_done = False
- # do while unclassified or vpkgs or both or pkgs
- while unclassified or pkgs or both or final_pass:
- #print len(unclassified), len(pkgs), len(both), len(vpkgs), final_pass
- if really_done:
- break
- if len(unclassified) + len(pkgs) + len(both) == 0:
- # one more pass then exit
- really_done = True
-
- while unclassified:
- current = unclassified.pop()
- examined.add(current)
- is_pkg = True in [source.is_package(meta, current) for source in sources]
- is_vpkg = current in vpkg_cache
-
- if is_pkg and is_vpkg:
- both.add(current)
- elif is_pkg and not is_vpkg:
- pkgs.add(current)
- elif is_vpkg and not is_pkg:
- vpkgs.add(current)
- elif not is_vpkg and not is_pkg:
- unknown.add(current)
-
- while pkgs:
- # direct packages; current can be added, and all deps should be resolved
- current = pkgs.pop()
- if debug:
- self.logger.debug("Packages: handling package requirement %s" % (current))
- deps = ()
- for source in sources:
- if source.is_package(meta, current):
- try:
- deps = source.get_deps(meta, current)
- break
- except:
- continue
- packages.add(current)
- newdeps = set(deps).difference(examined)
- if debug and newdeps:
- self.logger.debug("Packages: Package %s added requirements %s" % (current, newdeps))
- unclassified.update(newdeps)
-
- satisfied_vpkgs = set()
- for current in vpkgs:
- # virtual dependencies, satisfied if one of N in the config, or can be forced if only one provider
- if len(vpkg_cache[current]) == 1:
- if debug:
- self.logger.debug("Packages: requirement %s satisfied by %s" % (current, vpkg_cache[current]))
- unclassified.update(vpkg_cache[current].difference(examined))
- satisfied_vpkgs.add(current)
- elif [item for item in vpkg_cache[current] if item in packages]:
- if debug:
- self.logger.debug("Packages: requirement %s satisfied by %s" % (current, [item for item in vpkg_cache[current] if item in packages]))
- satisfied_vpkgs.add(current)
- vpkgs.difference_update(satisfied_vpkgs)
-
- satisfied_both = set()
- for current in both:
- # packages that are both have virtual providers as well as a package with that name
- # allow use of virt through explicit specification, then fall back to forcing current on last pass
- if [item for item in vpkg_cache[current] if item in packages]:
- if debug:
- self.logger.debug("Packages: requirement %s satisfied by %s" % (current, [item for item in vpkg_cache[current] if item in packages]))
- satisfied_both.add(current)
- elif current in input_requirements or final_pass:
- pkgs.add(current)
- satisfied_both.add(current)
- both.difference_update(satisfied_both)
-
- if len(unclassified) + len(pkgs) == 0:
- final_pass = True
- else:
- final_pass = False
-
- for source in sources:
- source.filter_unknown(unknown)
-
- return packages, unknown, ptype.pop()
-
- def validate_structures(self, meta, structures):
- '''Ensure client configurations include all needed prerequisites
-
- Arguments:
- meta - client metadata instance
- structures - a list of structure-stage entry combinations
- '''
- if self.disableResolver: return # Config requests no resolver
-
- initial = set([pkg.get('name') for struct in structures \
- for pkg in struct.findall('Package') +
- struct.findall('BoundPackage')])
- news = lxml.etree.Element('Independent')
- packages, unknown, ptype = self.complete(meta, initial,
- debug=self.debug_flag)
- if unknown:
- self.logger.info("Got unknown entries")
- self.logger.info(list(unknown))
- newpkgs = list(packages.difference(initial))
- newpkgs.sort()
- for pkg in newpkgs:
- lxml.etree.SubElement(news, 'BoundPackage', name=pkg,
- type=ptype, version='auto', origin='Packages')
- structures.append(news)
-
- def make_non_redundant(self, meta, plname=None, plist=None):
- '''build a non-redundant version of a list of packages
-
- Arguments:
- meta - client metadata instance
- plname - name of file containing a list of packages
- '''
- if plname is not None:
- pkgnames = set([x.strip() for x in open(plname).readlines()])
- elif plist is not None:
- pkgnames = set(plist)
- redundant = set()
- sources = self.get_matching_sources(meta)
- for source in sources:
- for pkgname in pkgnames:
- if source.is_pkg(meta, current):
- try:
- deps = source.get_deps(meta, pkgname)
- except:
- continue
- for rpkg in deps:
- if rpkg in pkgnames:
- redundant.add(rpkg)
- return pkgnames.difference(redundant), redundant
-
- def Refresh(self):
- '''Packages.Refresh() => True|False\nReload configuration specification and download sources\n'''
- self._load_config(force_update=True)
- return True
-
- def Reload(self):
- '''Packages.Refresh() => True|False\nReload configuration specification and sources\n'''
- self._load_config()
- return True
-
- def _load_config(self, force_update=False):
- '''
- Load the configuration data and setup sources
-
- Keyword args:
- force_update Force downloading repo data
- '''
- self.virt_pkgs = dict()
- try:
- xdata = lxml.etree.parse(self.data + '/config.xml')
- xdata.xinclude()
- xdata = xdata.getroot()
- except (lxml.etree.XIncludeError, \
- lxml.etree.XMLSyntaxError), xmlerr:
- self.logger.error("Package: Error processing xml: %s" % xmlerr)
- raise Bcfg2.Server.Plugin.PluginInitError
- except IOError:
- self.logger.error("Failed to read Packages configuration. Have" +
- " you created your config.xml file?")
- raise Bcfg2.Server.Plugin.PluginInitError
-
- # Load Packages config
- config = xdata.xpath('//Sources/Config')
- if config:
- if config[0].get("resolver", "enabled").lower() == "disabled":
- self.logger.info("Packages: Resolver disabled")
- self.disableResolver = True
- if config[0].get("metadata", "enabled").lower() == "disabled":
- self.logger.info("Packages: Metadata disabled")
- self.disableResolver = True
- self.disableMetaData = True
-
- self.sentinels = set()
- self.sources = []
- for s in xdata.findall('.//APTSource'):
- self.sources.append(APTSource(self.cachepath, **source_from_xml(s)))
- for s in xdata.findall('.//YUMSource'):
- self.sources.append(YUMSource(self.cachepath, **source_from_xml(s)))
- for s in xdata.findall('.//PACSource'):
- self.sources.append(PACSource(self.cachepath, **source_from_xml(s)))
-
- cachefiles = []
- for source in self.sources:
- cachefiles.append(source.cachefile)
- if not self.disableMetaData: source.setup_data(force_update)
- self.sentinels.update(source.basegroups)
- for cfile in glob.glob("%s/cache-*" % self.cachepath):
- if cfile not in cachefiles:
- os.unlink(cfile)
-
- def get_additional_data(self, meta):
- sdata = []
- [sdata.extend(copy.deepcopy(src.url_map)) for src in self.get_matching_sources(meta)]
- return dict(sources=sdata)
diff --git a/build/lib/Bcfg2/Server/Plugins/Pkgmgr.py b/build/lib/Bcfg2/Server/Plugins/Pkgmgr.py
deleted file mode 100644
index b58a7c91d..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Pkgmgr.py
+++ /dev/null
@@ -1,155 +0,0 @@
-'''This module implements a package management scheme for all images'''
-__revision__ = '$Revision$'
-
-import logging
-import re
-import Bcfg2.Server.Plugin
-
-logger = logging.getLogger('Bcfg2.Plugins.Pkgmgr')
-
-class FuzzyDict(dict):
- fuzzy = re.compile('(?P<name>.*):(?P<alist>\S+(,\S+)*)')
- def __getitem__(self, key):
- if isinstance(key, str):
- mdata = self.fuzzy.match(key)
- if mdata:
- return dict.__getitem__(self, mdata.groupdict()['name'])
- else:
- print "got non-string key %s" % str(key)
- return dict.__getitem__(self, key)
-
- def has_key(self, key):
- if isinstance(key, str):
- mdata = self.fuzzy.match(key)
- if self.fuzzy.match(key):
- return dict.has_key(self, mdata.groupdict()['name'])
- return dict.has_key(self, key)
-
- def get(self, key, default=None):
- try:
- return self.__getitem__(key)
- except:
- if default:
- return default
- raise
-
-class PNode(Bcfg2.Server.Plugin.INode):
- """PNode has a list of packages available at a particular group intersection."""
- splitters = {'rpm':re.compile('^(.*/)?(?P<name>[\w\+\d\.]+(-[\w\+\d\.]+)*)-' + \
- '(?P<version>[\w\d\.]+-([\w\d\.]+))\.(?P<arch>\S+)\.rpm$'),
- 'encap':re.compile('^(?P<name>[\w-]+)-(?P<version>[\w\d\.+-]+).encap.*$')}
- ignore = ['Package']
-
- def Match(self, metadata, data):
- """Return a dictionary of package mappings."""
- if self.predicate(metadata):
- for key in self.contents:
- try:
- data[key].update(self.contents[key])
- except:
- data[key] = FuzzyDict()
- data[key].update(self.contents[key])
- for child in self.children:
- child.Match(metadata, data)
-
- def __init__(self, data, pdict, parent=None):
- # copy local attributes to all child nodes if no local attribute exists
- if not pdict.has_key('Package'):
- pdict['Package'] = set()
- for child in data.getchildren():
- for attr in [key for key in data.attrib.keys() \
- if key != 'name' and not child.attrib.has_key(key)]:
- try:
- child.set(attr, data.get(attr))
- except:
- # don't fail on things like comments and other immutable elements
- pass
- Bcfg2.Server.Plugin.INode.__init__(self, data, pdict, parent)
- if not self.contents.has_key('Package'):
- self.contents['Package'] = FuzzyDict()
- for pkg in data.findall('./Package'):
- if pkg.attrib.has_key('name') and pkg.get('name') not in pdict['Package']:
- pdict['Package'].add(pkg.get('name'))
- if pkg.get('name') != None:
- self.contents['Package'][pkg.get('name')] = {}
- if pkg.getchildren():
- self.contents['Package'][pkg.get('name')]['__children__'] \
- = pkg.getchildren()
- if pkg.attrib.has_key('simplefile'):
- pkg.set('url', "%s/%s" % (pkg.get('uri'), pkg.get('simplefile')))
- self.contents['Package'][pkg.get('name')].update(pkg.attrib)
- else:
- if pkg.attrib.has_key('file'):
- if pkg.attrib.has_key('multiarch'):
- archs = pkg.get('multiarch').split()
- srcs = pkg.get('srcs', pkg.get('multiarch')).split()
- url = ' '.join(["%s/%s" % (pkg.get('uri'), pkg.get('file') % {'src':srcs[idx], 'arch':archs[idx]})
- for idx in range(len(archs))])
- pkg.set('url', url)
- else:
- pkg.set('url', '%s/%s' % (pkg.get('uri'), pkg.get('file')))
- if self.splitters.has_key(pkg.get('type')) and pkg.get('file') != None:
- mdata = self.splitters[pkg.get('type')].match(pkg.get('file'))
- if not mdata:
- logger.error("Failed to match pkg %s" % pkg.get('file'))
- continue
- pkgname = mdata.group('name')
- self.contents['Package'][pkgname] = mdata.groupdict()
- self.contents['Package'][pkgname].update(pkg.attrib)
- if pkg.attrib.get('file'):
- self.contents['Package'][pkgname]['url'] = pkg.get('url')
- self.contents['Package'][pkgname]['type'] = pkg.get('type')
- if pkg.get('verify'):
- self.contents['Package'][pkgname]['verify'] = pkg.get('verify')
- if pkg.get('multiarch'):
- self.contents['Package'][pkgname]['multiarch'] = pkg.get('multiarch')
- if pkgname not in pdict['Package']:
- pdict['Package'].add(pkgname)
- if pkg.getchildren():
- self.contents['Package'][pkgname]['__children__'] = pkg.getchildren()
- else:
- self.contents['Package'][pkg.get('name')].update(pkg.attrib)
-
-
-class PkgSrc(Bcfg2.Server.Plugin.XMLSrc):
- """PkgSrc files contain a PNode hierarchy that returns matching package entries."""
- __node__ = PNode
- __cacheobj__ = FuzzyDict
-
-class Pkgmgr(Bcfg2.Server.Plugin.PrioDir):
- """This is a generator that handles package assignments."""
- name = 'Pkgmgr'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- __child__ = PkgSrc
- __element__ = 'Package'
-
- def HandleEvent(self, event):
- '''Handle events and update dispatch table'''
- Bcfg2.Server.Plugin.XMLDirectoryBacked.HandleEvent(self, event)
- for src in self.entries.values():
- for itype, children in src.items.iteritems():
- for child in children:
- try:
- self.Entries[itype][child] = self.BindEntry
- except KeyError:
- self.Entries[itype] = FuzzyDict([(child,
- self.BindEntry)])
-
- def BindEntry(self, entry, metadata):
- """Bind data for entry, and remove instances that are not requested."""
- pname = entry.get('name')
- Bcfg2.Server.Plugin.PrioDir.BindEntry(self, entry, metadata)
- if entry.findall('Instance'):
- mdata = FuzzyDict.fuzzy.match(pname)
- if mdata:
- arches = mdata.group('alist').split(',')
- [entry.remove(inst) for inst in \
- entry.findall('Instance') \
- if inst.get('arch') not in arches]
-
- def HandlesEntry(self, entry, metadata):
- return entry.tag == 'Package' and entry.get('name').split(':')[0] in self.Entries['Package'].keys()
-
- def HandleEntry(self, entry, metadata):
- self.BindEntry(entry, metadata)
diff --git a/build/lib/Bcfg2/Server/Plugins/Probes.py b/build/lib/Bcfg2/Server/Plugins/Probes.py
deleted file mode 100644
index c00185732..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Probes.py
+++ /dev/null
@@ -1,150 +0,0 @@
-import lxml.etree
-import re
-
-import Bcfg2.Server.Plugin
-
-specific_probe_matcher = re.compile("(.*/)?(?P<basename>\S+)(.(?P<mode>[GH](\d\d)?)_\S+)")
-probe_matcher = re.compile("(.*/)?(?P<basename>\S+)")
-
-class ProbeSet(Bcfg2.Server.Plugin.EntrySet):
- ignore = re.compile("^(\.#.*|.*~|\\..*\\.(tmp|sw[px])|probed\\.xml)$")
- def __init__(self, path, fam, encoding, plugin_name):
- fpattern = '[0-9A-Za-z_\-]+'
- self.plugin_name = plugin_name
- Bcfg2.Server.Plugin.EntrySet.__init__(self, fpattern, path,
- Bcfg2.Server.Plugin.SpecificData,
- encoding)
- fam.AddMonitor(path, self)
- self.bangline = re.compile('^#!(?P<interpreter>.*)$')
-
- def HandleEvent(self, event):
- if event.filename != self.path:
- return self.handle_event(event)
-
- def get_probe_data(self, metadata):
- ret = []
- build = dict()
- candidates = self.get_matching(metadata)
- candidates.sort(lambda x, y: cmp(x.specific, y.specific))
- for entry in candidates:
- rem = specific_probe_matcher.match(entry.name)
- if not rem:
- rem = probe_matcher.match(entry.name)
- pname = rem.group('basename')
- if pname not in build:
- build[pname] = entry
-
- for (name, entry) in build.iteritems():
- probe = lxml.etree.Element('probe')
- probe.set('name', name.split('/')[-1])
- probe.set('source', self.plugin_name)
- probe.text = entry.data
- match = self.bangline.match(entry.data.split('\n')[0])
- if match:
- probe.set('interpreter', match.group('interpreter'))
- else:
- probe.set('interpreter', '/bin/sh')
- ret.append(probe)
- return ret
-
-class Probes(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Probing,
- Bcfg2.Server.Plugin.Connector):
- """A plugin to gather information from a client machine."""
- name = 'Probes'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- Bcfg2.Server.Plugin.Probing.__init__(self)
-
- try:
- self.probes = ProbeSet(self.data, core.fam, core.encoding,
- self.name)
- except:
- raise Bcfg2.Server.Plugin.PluginInitError
-
- self.probedata = dict()
- self.cgroups = dict()
- self.load_data()
-
- def write_data(self):
- """Write probe data out for use with bcfg2-info."""
- top = lxml.etree.Element("Probed")
- for client, probed in self.probedata.iteritems():
- cx = lxml.etree.SubElement(top, 'Client', name=client)
- for probe in probed:
- lxml.etree.SubElement(cx, 'Probe', name=probe,
- value=self.probedata[client][probe])
- for group in self.cgroups[client]:
- lxml.etree.SubElement(cx, "Group", name=group)
- data = lxml.etree.tostring(top, encoding='UTF-8', xml_declaration=True,
- pretty_print='true')
- try:
- datafile = open("%s/%s" % (self.data, 'probed.xml'), 'w')
- except IOError:
- self.logger.error("Failed to write probed.xml")
- datafile.write(data)
-
- def load_data(self):
- try:
- data = lxml.etree.parse(self.data + '/probed.xml').getroot()
- except:
- self.logger.error("Failed to read file probed.xml")
- return
- self.probedata = {}
- self.cgroups = {}
- for client in data.getchildren():
- self.probedata[client.get('name')] = {}
- self.cgroups[client.get('name')]=[]
- for pdata in client:
- if (pdata.tag == 'Probe'):
- self.probedata[client.get('name')][pdata.get('name')] = pdata.get('value')
- elif (pdata.tag == 'Group'):
- self.cgroups[client.get('name')].append(pdata.get('name'))
-
- def GetProbes(self, meta, force=False):
- """Return a set of probes for execution on client."""
- return self.probes.get_probe_data(meta)
-
- def ReceiveData(self, client, datalist):
- self.cgroups[client.hostname] = []
- self.probedata[client.hostname] = {}
- for data in datalist:
- self.ReceiveDataItem(client, data)
- self.write_data()
-
- def ReceiveDataItem(self, client, data):
- """Receive probe results pertaining to client."""
- if not self.cgroups.has_key(client.hostname):
- self.cgroups[client.hostname] = []
- if data.text == None:
- self.logger.error("Got null response to probe %s from %s" % \
- (data.get('name'), client.hostname))
- try:
- self.probedata[client.hostname].update({data.get('name'): ''})
- except KeyError:
- self.probedata[client.hostname] = {data.get('name'): ''}
- return
- dlines = data.text.split('\n')
- self.logger.debug("%s:probe:%s:%s" % (client.hostname,
- data.get('name'), [line.strip() for line in dlines]))
- for line in dlines[:]:
- if line.split(':')[0] == 'group':
- newgroup = line.split(':')[1].strip()
- if newgroup not in self.cgroups[client.hostname]:
- self.cgroups[client.hostname].append(newgroup)
- dlines.remove(line)
- dtext = "\n".join(dlines)
- try:
- self.probedata[client.hostname].update({data.get('name'):dtext})
- except KeyError:
- self.probedata[client.hostname] = {data.get('name'):dtext}
-
- def get_additional_groups(self, meta):
- return self.cgroups.get(meta.hostname, list())
-
- def get_additional_data(self, meta):
- return self.probedata.get(meta.hostname, dict())
diff --git a/build/lib/Bcfg2/Server/Plugins/Properties.py b/build/lib/Bcfg2/Server/Plugins/Properties.py
deleted file mode 100644
index 86330f6a0..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Properties.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import copy
-import lxml.etree
-
-import Bcfg2.Server.Plugin
-
-
-class PropertyFile(Bcfg2.Server.Plugin.XMLFileBacked):
- """Class for properties files."""
-
- def Index(self):
- """Build data into an xml object."""
- try:
- self.data = lxml.etree.XML(self.data)
- except lxml.etree.XMLSyntaxError:
- Bcfg2.Server.Plugin.logger.error("Failed to parse %s" % self.name)
-
-
-class PropDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked):
- __child__ = PropertyFile
-
-
-class Properties(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Connector):
- """
- The properties plugin maps property
- files into client metadata instances.
- """
- name = 'Properties'
- version = '$Revision$'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- self.store = PropDirectoryBacked(self.data, core.fam)
-
- def get_additional_data(self, _):
- return copy.deepcopy(self.store.entries)
diff --git a/build/lib/Bcfg2/Server/Plugins/Rules.py b/build/lib/Bcfg2/Server/Plugins/Rules.py
deleted file mode 100644
index eb0547cdb..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Rules.py
+++ /dev/null
@@ -1,11 +0,0 @@
-"""This generator provides rule-based entry mappings."""
-__revision__ = '$Revision$'
-
-import Bcfg2.Server.Plugin
-
-
-class Rules(Bcfg2.Server.Plugin.PrioDir):
- """This is a generator that handles service assignments."""
- name = 'Rules'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
diff --git a/build/lib/Bcfg2/Server/Plugins/SGenshi.py b/build/lib/Bcfg2/Server/Plugins/SGenshi.py
deleted file mode 100644
index cead06e34..000000000
--- a/build/lib/Bcfg2/Server/Plugins/SGenshi.py
+++ /dev/null
@@ -1,76 +0,0 @@
-'''This module implements a templating generator based on Genshi'''
-__revision__ = '$Revision$'
-
-import genshi.input
-import genshi.template
-import lxml.etree
-import logging
-
-import Bcfg2.Server.Plugin
-import Bcfg2.Server.Plugins.TGenshi
-
-logger = logging.getLogger('Bcfg2.Plugins.SGenshi')
-
-
-class SGenshiTemplateFile(Bcfg2.Server.Plugins.TGenshi.TemplateFile):
-
- def get_xml_value(self, metadata):
- if not hasattr(self, 'template'):
- logger.error("No parsed template information for %s" % (self.name))
- raise Bcfg2.Server.Plugin.PluginExecutionError
- try:
- stream = self.template.generate(metadata=metadata,).filter( \
- Bcfg2.Server.Plugins.TGenshi.removecomment)
- data = stream.render('xml', strip_whitespace=False)
- return lxml.etree.XML(data)
- except LookupError, lerror:
- logger.error('Genshi lookup error: %s' % lerror)
- except genshi.template.TemplateError, terror:
- logger.error('Genshi template error: %s' % terror)
- except genshi.input.ParseError, perror:
- logger.error('Genshi parse error: %s' % perror)
- raise
-
-
-class SGenshiEntrySet(Bcfg2.Server.Plugin.EntrySet):
-
- def __init__(self, path, fam, encoding):
- fpattern = '\S+\.xml'
- Bcfg2.Server.Plugin.EntrySet.__init__(self, fpattern, path,
- SGenshiTemplateFile, encoding)
- fam.AddMonitor(path, self)
-
- def HandleEvent(self, event):
- '''passthrough event handler for old calling convention'''
- if event.filename != self.path:
- return self.handle_event(event)
-
- def BuildStructures(self, metadata):
- """Build SGenshi structures."""
- ret = []
- for entry in self.get_matching(metadata):
- try:
- ret.append(entry.get_xml_value(metadata))
- except:
- logger.error("SGenshi: Failed to template file %s" % entry.name)
- return ret
-
-
-class SGenshi(SGenshiEntrySet,
- Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Structure):
- """The SGenshi plugin provides templated structures."""
- name = 'SGenshi'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- deprecated = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Structure.__init__(self)
- try:
- SGenshiEntrySet.__init__(self, self.data, self.core.fam, core.encoding)
- except:
- logger.error("Failed to load %s repository; disabling %s" \
- % (self.name, self.name))
- raise Bcfg2.Server.Plugin.PluginInitError
diff --git a/build/lib/Bcfg2/Server/Plugins/SSHbase.py b/build/lib/Bcfg2/Server/Plugins/SSHbase.py
deleted file mode 100644
index 6d68ecb0a..000000000
--- a/build/lib/Bcfg2/Server/Plugins/SSHbase.py
+++ /dev/null
@@ -1,279 +0,0 @@
-'''This module manages ssh key files for bcfg2'''
-__revision__ = '$Revision$'
-
-import binascii
-import os
-import socket
-import shutil
-import tempfile
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Plugin
-
-
-class SSHbase(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Generator,
- Bcfg2.Server.Plugin.DirectoryBacked,
- Bcfg2.Server.Plugin.PullTarget):
- """
- The sshbase generator manages ssh host keys (both v1 and v2)
- for hosts. It also manages the ssh_known_hosts file. It can
- integrate host keys from other management domains and similarly
- export its keys. The repository contains files in the following
- formats:
-
- ssh_host_key.H_(hostname) -> the v1 host private key for
- (hostname)
- ssh_host_key.pub.H_(hostname) -> the v1 host public key
- for (hostname)
- ssh_host_(dr)sa_key.H_(hostname) -> the v2 ssh host
- private key for (hostname)
- ssh_host_(dr)sa_key.pub.H_(hostname) -> the v2 ssh host
- public key for (hostname)
- ssh_known_hosts -> the current known hosts file. this
- is regenerated each time a new key is generated.
-
- """
- name = 'SSHbase'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- pubkeys = ["ssh_host_dsa_key.pub.H_%s",
- "ssh_host_rsa_key.pub.H_%s", "ssh_host_key.pub.H_%s"]
- hostkeys = ["ssh_host_dsa_key.H_%s",
- "ssh_host_rsa_key.H_%s", "ssh_host_key.H_%s"]
- keypatterns = ['ssh_host_dsa_key', 'ssh_host_rsa_key', 'ssh_host_key',
- 'ssh_host_dsa_key.pub', 'ssh_host_rsa_key.pub',
- 'ssh_host_key.pub']
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- Bcfg2.Server.Plugin.PullTarget.__init__(self)
- try:
- Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data,
- self.core.fam)
- except OSError, ioerr:
- self.logger.error("Failed to load SSHbase repository from %s" \
- % (self.data))
- self.logger.error(ioerr)
- raise Bcfg2.Server.Plugin.PluginInitError
- self.Entries = {'Path':
- {'/etc/ssh/ssh_known_hosts': self.build_skn,
- '/etc/ssh/ssh_host_dsa_key': self.build_hk,
- '/etc/ssh/ssh_host_rsa_key': self.build_hk,
- '/etc/ssh/ssh_host_dsa_key.pub': self.build_hk,
- '/etc/ssh/ssh_host_rsa_key.pub': self.build_hk,
- '/etc/ssh/ssh_host_key': self.build_hk,
- '/etc/ssh/ssh_host_key.pub': self.build_hk}}
- self.ipcache = {}
- self.namecache = {}
- self.__skn = False
-
- def get_skn(self):
- """Build memory cache of the ssh known hosts file."""
- if not self.__skn:
- self.__skn = "\n".join([value.data for key, value in \
- self.entries.iteritems() if \
- key.endswith('.static')])
- names = dict()
- # if no metadata is registered yet, defer
- if len(self.core.metadata.query.all()) == 0:
- self.__skn = False
- return self.__skn
- for cmeta in self.core.metadata.query.all():
- names[cmeta.hostname] = set([cmeta.hostname])
- names[cmeta.hostname].update(cmeta.aliases)
- newnames = set()
- newips = set()
- for name in names[cmeta.hostname]:
- newnames.add(name.split('.')[0])
- try:
- newips.add(self.get_ipcache_entry(name)[0])
- except:
- continue
- names[cmeta.hostname].update(newnames)
- names[cmeta.hostname].update(cmeta.addresses)
- names[cmeta.hostname].update(newips)
- # TODO: Only perform reverse lookups on IPs if an option is set.
- if True:
- for ip in newips:
- try:
- names[cmeta.hostname].update(self.get_namecache_entry(ip))
- except:
- continue
- names[cmeta.hostname] = sorted(names[cmeta.hostname])
- # now we have our name cache
- pubkeys = [pubk for pubk in self.entries.keys() \
- if pubk.find('.pub.H_') != -1]
- pubkeys.sort()
- badnames = set()
- for pubkey in pubkeys:
- hostname = pubkey.split('H_')[1]
- if hostname not in names:
- if hostname not in badnames:
- badnames.add(hostname)
- self.logger.error("SSHbase: Unknown host %s; ignoring public keys" % hostname)
- continue
- self.__skn += "%s %s" % (','.join(names[hostname]),
- self.entries[pubkey].data)
- return self.__skn
-
- def set_skn(self, value):
- """Set backing data for skn."""
- self.__skn = value
- skn = property(get_skn, set_skn)
-
- def HandleEvent(self, event=None):
- """Local event handler that does skn regen on pubkey change."""
- Bcfg2.Server.Plugin.DirectoryBacked.HandleEvent(self, event)
- if event and '_key.pub.H_' in event.filename:
- self.skn = False
- if event and event.filename.endswith('.static'):
- self.skn = False
- if not self.__skn:
- if (len(self.entries.keys())) >= (len(os.listdir(self.data))-1):
- _ = self.skn
-
- def HandlesEntry(self, entry, _):
- """Handle key entries dynamically."""
- return entry.tag == 'Path' and \
- ([fpat for fpat in self.keypatterns
- if entry.get('name').endswith(fpat)]
- or entry.get('name').endswith('ssh_known_hosts'))
-
- def HandleEntry(self, entry, metadata):
- """Bind data."""
- if entry.get('name').endswith('ssh_known_hosts'):
- return self.build_skn(entry, metadata)
- else:
- return self.build_hk(entry, metadata)
-
- def get_ipcache_entry(self, client):
- """Build a cache of dns results."""
- if client in self.ipcache:
- if self.ipcache[client]:
- return self.ipcache[client]
- else:
- raise socket.gaierror
- else:
- # need to add entry
- try:
- ipaddr = socket.gethostbyname(client)
- self.ipcache[client] = (ipaddr, client)
- return (ipaddr, client)
- except socket.gaierror:
- cmd = "getent hosts %s" % client
- ipaddr = Popen(cmd, shell=True, \
- stdout=PIPE).stdout.read().strip().split()
- if ipaddr:
- self.ipcache[client] = (ipaddr, client)
- return (ipaddr, client)
- self.ipcache[client] = False
- self.logger.error("Failed to find IP address for %s" % client)
- raise socket.gaierror
-
- def get_namecache_entry(self, cip):
- """Build a cache of name lookups from client IP addresses."""
- if cip in self.namecache:
- # lookup cached name from IP
- if self.namecache[cip]:
- return self.namecache[cip]
- else:
- raise socket.gaierror
- else:
- # add an entry that has not been cached
- try:
- rvlookup = socket.gethostbyaddr(cip)
- if rvlookup[0]:
- self.namecache[cip] = [rvlookup[0]]
- else:
- self.namecache[cip] = []
- self.namecache[cip].extend(rvlookup[1])
- return self.namecache[cip]
- except socket.gaierror:
- self.namecache[cip] = False
- self.logger.error("Failed to find any names associated with IP address %s" % cip)
- raise
-
- def build_skn(self, entry, metadata):
- """This function builds builds a host specific known_hosts file."""
- client = metadata.hostname
- entry.text = self.skn
- hostkeys = [keytmpl % client for keytmpl in self.pubkeys \
- if (keytmpl % client) in self.entries]
- hostkeys.sort()
- for hostkey in hostkeys:
- entry.text += "localhost,localhost.localdomain,127.0.0.1 %s" % (
- self.entries[hostkey].data)
- permdata = {'owner':'root',
- 'group':'root',
- 'type':'file',
- 'perms':'0644'}
- [entry.attrib.__setitem__(key, permdata[key]) for key in permdata]
-
- def build_hk(self, entry, metadata):
- """This binds host key data into entries."""
- client = metadata.hostname
- filename = "%s.H_%s" % (entry.get('name').split('/')[-1], client)
- if filename not in self.entries.keys():
- self.GenerateHostKeys(client)
- if not filename in self.entries:
- self.logger.error("%s still not registered" % filename)
- raise Bcfg2.Server.Plugin.PluginExecutionError
- keydata = self.entries[filename].data
- permdata = {'owner':'root',
- 'group':'root',
- 'type':'file',
- 'perms':'0600'}
- if entry.get('name')[-4:] == '.pub':
- permdata['perms'] = '0644'
- [entry.attrib.__setitem__(key, permdata[key]) for key in permdata]
- if "ssh_host_key.H_" == filename[:15]:
- entry.attrib['encoding'] = 'base64'
- entry.text = binascii.b2a_base64(keydata)
- else:
- entry.text = keydata
-
- def GenerateHostKeys(self, client):
- """Generate new host keys for client."""
- keylist = [keytmpl % client for keytmpl in self.hostkeys]
- for hostkey in keylist:
- if 'ssh_host_rsa_key.H_' == hostkey[:19]:
- keytype = 'rsa'
- elif 'ssh_host_dsa_key.H_' == hostkey[:19]:
- keytype = 'dsa'
- else:
- keytype = 'rsa1'
-
- if hostkey not in self.entries.keys():
- fileloc = "%s/%s" % (self.data, hostkey)
- publoc = self.data + '/' + ".".join([hostkey.split('.')[0],
- 'pub',
- "H_%s" % client])
- tempdir = tempfile.mkdtemp()
- temploc = "%s/%s" % (tempdir, hostkey)
- cmd = 'ssh-keygen -q -f %s -N "" -t %s -C root@%s < /dev/null'
- os.system(cmd % (temploc, keytype, client))
- shutil.copy(temploc, fileloc)
- shutil.copy("%s.pub" % temploc, publoc)
- self.AddEntry(hostkey)
- self.AddEntry(".".join([hostkey.split('.')[0]]+['pub', "H_%s" \
- % client]))
- try:
- os.unlink(temploc)
- os.unlink("%s.pub" % temploc)
- os.rmdir(tempdir)
- except OSError:
- self.logger.error("Failed to unlink temporary ssh keys")
-
- def AcceptChoices(self, _, metadata):
- return [Bcfg2.Server.Plugin.Specificity(hostname=metadata.hostname)]
-
- def AcceptPullData(self, specific, entry, log):
- """Per-plugin bcfg2-admin pull support."""
- # specific will always be host specific
- filename = "%s/%s.H_%s" % (self.data, entry['name'].split('/')[-1],
- specific.hostname)
- open(filename, 'w').write(entry['text'])
- if log:
- print "Wrote file %s" % filename
diff --git a/build/lib/Bcfg2/Server/Plugins/SSLCA.py b/build/lib/Bcfg2/Server/Plugins/SSLCA.py
deleted file mode 100644
index 0dc448e69..000000000
--- a/build/lib/Bcfg2/Server/Plugins/SSLCA.py
+++ /dev/null
@@ -1,239 +0,0 @@
-import Bcfg2.Server.Plugin
-import Bcfg2.Options
-import lxml.etree
-import posixpath
-import tempfile
-import os
-from subprocess import Popen, PIPE, STDOUT
-from ConfigParser import ConfigParser
-
-class SSLCA(Bcfg2.Server.Plugin.GroupSpool):
- """
- The SSLCA generator handles the creation and
- management of ssl certificates and their keys.
- """
- name = 'SSLCA'
- __version__ = '$Id:$'
- __author__ = 'g.hagger@gmail.com'
- __child__ = Bcfg2.Server.Plugin.FileBacked
- key_specs = {}
- cert_specs = {}
- CAs = {}
-
- def HandleEvent(self, event=None):
- """
- Updates which files this plugin handles based upon filesystem events.
- Allows configuration items to be added/removed without server restarts.
- """
- action = event.code2str()
- if event.filename[0] == '/':
- return
- epath = "".join([self.data, self.handles[event.requestID],
- event.filename])
- if posixpath.isdir(epath):
- ident = self.handles[event.requestID] + event.filename
- else:
- ident = self.handles[event.requestID][:-1]
-
- fname = "".join([ident, '/', event.filename])
-
- if event.filename.endswith('.xml'):
- if action in ['exists', 'created', 'changed']:
- if event.filename.endswith('key.xml'):
- key_spec = dict(lxml.etree.parse(epath).find('Key').items())
- self.key_specs[ident] = {
- 'bits': key_spec.get('bits', 2048),
- 'type': key_spec.get('type', 'rsa')
- }
- self.Entries['Path'][ident] = self.get_key
- elif event.filename.endswith('cert.xml'):
- cert_spec = dict(lxml.etree.parse(epath).find('Cert').items())
- ca = cert_spec.get('ca', 'default')
- self.cert_specs[ident] = {
- 'ca': ca,
- 'format': cert_spec.get('format', 'pem'),
- 'key': cert_spec.get('key'),
- 'days': cert_spec.get('days', 365),
- 'C': cert_spec.get('c'),
- 'L': cert_spec.get('l'),
- 'ST': cert_spec.get('st'),
- 'OU': cert_spec.get('ou'),
- 'O': cert_spec.get('o'),
- 'emailAddress': cert_spec.get('emailaddress')
- }
- cp = ConfigParser()
- cp.read(self.core.cfile)
- self.CAs[ca] = dict(cp.items('sslca_'+ca))
- self.Entries['Path'][ident] = self.get_cert
- if action == 'deleted':
- if ident in self.Entries['Path']:
- del self.Entries['Path'][ident]
- else:
- if action in ['exists', 'created']:
- if posixpath.isdir(epath):
- self.AddDirectoryMonitor(epath[len(self.data):])
- if ident not in self.entries and posixpath.isfile(epath):
- self.entries[fname] = self.__child__(epath)
- self.entries[fname].HandleEvent(event)
- if action == 'changed':
- self.entries[fname].HandleEvent(event)
- elif action == 'deleted':
- if fname in self.entries:
- del self.entries[fname]
- else:
- self.entries[fname].HandleEvent(event)
-
- def get_key(self, entry, metadata):
- """
- either grabs a prexisting key hostfile, or triggers the generation
- of a new key if one doesn't exist.
- """
- # set path type and permissions, otherwise bcfg2 won't bind the file
- permdata = {'owner':'root',
- 'group':'root',
- 'type':'file',
- 'perms':'644'}
- [entry.attrib.__setitem__(key, permdata[key]) for key in permdata]
-
- # check if we already have a hostfile, or need to generate a new key
- # TODO: verify key fits the specs
- path = entry.get('name')
- filename = "".join([path, '/', path.rsplit('/', 1)[1], '.H_', metadata.hostname])
- if filename not in self.entries.keys():
- key = self.build_key(filename, entry, metadata)
- open(self.data + filename, 'w').write(key)
- entry.text = key
- else:
- entry.text = self.entries[filename].data
-
- def build_key(self, filename, entry, metadata):
- """
- generates a new key according the the specification
- """
- type = self.key_specs[entry.get('name')]['type']
- bits = self.key_specs[entry.get('name')]['bits']
- if type == 'rsa':
- cmd = "openssl genrsa %s " % bits
- elif type == 'dsa':
- cmd = "openssl dsaparam -noout -genkey %s" % bits
- key = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
- return key
-
- def get_cert(self, entry, metadata):
- """
- either grabs a prexisting cert hostfile, or triggers the generation
- of a new cert if one doesn't exist.
- """
- # set path type and permissions, otherwise bcfg2 won't bind the file
- permdata = {'owner':'root',
- 'group':'root',
- 'type':'file',
- 'perms':'644'}
- [entry.attrib.__setitem__(key, permdata[key]) for key in permdata]
-
- path = entry.get('name')
- filename = "".join([path, '/', path.rsplit('/', 1)[1], '.H_', metadata.hostname])
-
- # first - ensure we have a key to work with
- key = self.cert_specs[entry.get('name')].get('key')
- key_filename = "".join([key, '/', key.rsplit('/', 1)[1], '.H_', metadata.hostname])
- if key_filename not in self.entries:
- e = lxml.etree.Element('Path')
- e.attrib['name'] = key
- self.core.Bind(e, metadata)
-
- # check if we have a valid hostfile
- if filename in self.entries.keys() and self.verify_cert(filename, entry):
- entry.text = self.entries[filename].data
- else:
- cert = self.build_cert(key_filename, entry, metadata)
- open(self.data + filename, 'w').write(cert)
- entry.text = cert
-
- def verify_cert(self, filename, entry):
- """
- check that a certificate validates against the ca cert,
- and that it has not expired.
- """
- chaincert = self.CAs[self.cert_specs[entry.get('name')]['ca']].get('chaincert')
- cert = self.data + filename
- cmd = "openssl verify -CAfile %s %s" % (chaincert, cert)
- res = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT).stdout.read()
- if res == cert + ": OK\n":
- return True
- return False
-
- def build_cert(self, key_filename, entry, metadata):
- """
- creates a new certificate according to the specification
- """
- req_config = self.build_req_config(entry, metadata)
- req = self.build_request(key_filename, req_config, entry)
- ca = self.cert_specs[entry.get('name')]['ca']
- ca_config = self.CAs[ca]['config']
- days = self.cert_specs[entry.get('name')]['days']
- passphrase = self.CAs[ca].get('passphrase')
- if passphrase:
- cmd = "openssl ca -config %s -in %s -days %s -batch -passin pass:%s" % (ca_config, req, days, passphrase)
- else:
- cmd = "openssl ca -config %s -in %s -days %s -batch" % (ca_config, req, days)
- cert = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
- try:
- os.unlink(req_config)
- os.unlink(req)
- except OSError:
- self.logger.error("Failed to unlink temporary files")
- return cert
-
- def build_req_config(self, entry, metadata):
- """
- generates a temporary openssl configuration file that is
- used to generate the required certificate request
- """
- # create temp request config file
- conffile = open(tempfile.mkstemp()[1], 'w')
- cp = ConfigParser({})
- cp.optionxform = str
- defaults = {
- 'req': {
- 'default_md': 'sha1',
- 'distinguished_name': 'req_distinguished_name',
- 'req_extensions': 'v3_req',
- 'x509_extensions': 'v3_req',
- 'prompt': 'no'
- },
- 'req_distinguished_name': {},
- 'v3_req': {
- 'subjectAltName': '@alt_names'
- },
- 'alt_names': {}
- }
- for section in defaults.keys():
- cp.add_section(section)
- for key in defaults[section]:
- cp.set(section, key, defaults[section][key])
- x = 1
- altnames = list(metadata.aliases)
- altnames.append(metadata.hostname)
- for altname in altnames:
- cp.set('alt_names', 'DNS.'+str(x), altname)
- x += 1
- for item in ['C', 'L', 'ST', 'O', 'OU', 'emailAddress']:
- if self.cert_specs[entry.get('name')][item]:
- cp.set('req_distinguished_name', item, self.cert_specs[entry.get('name')][item])
- cp.set('req_distinguished_name', 'CN', metadata.hostname)
- cp.write(conffile)
- conffile.close()
- return conffile.name
-
- def build_request(self, key_filename, req_config, entry):
- """
- creates the certificate request
- """
- req = tempfile.mkstemp()[1]
- days = self.cert_specs[entry.get('name')]['days']
- key = self.data + key_filename
- cmd = "openssl req -new -config %s -days %s -key %s -text -out %s" % (req_config, days, key, req)
- res = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
- return req
-
diff --git a/build/lib/Bcfg2/Server/Plugins/Snapshots.py b/build/lib/Bcfg2/Server/Plugins/Snapshots.py
deleted file mode 100644
index a4489ae95..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Snapshots.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#import lxml.etree
-import logging
-import binascii
-import difflib
-#import sqlalchemy
-#import sqlalchemy.orm
-import Bcfg2.Server.Plugin
-import Bcfg2.Server.Snapshots
-import Bcfg2.Logger
-from Bcfg2.Server.Snapshots.model import Snapshot
-import Queue
-import time
-import threading
-
-logger = logging.getLogger('Snapshots')
-
-ftypes = ['ConfigFile', 'SymLink', 'Directory']
-datafields = {
- 'Package': ['version'],
- 'Path': ['type'],
- 'Service': ['status'],
- 'ConfigFile': ['owner', 'group', 'perms'],
- 'Directory': ['owner', 'group', 'perms'],
- 'SymLink': ['to'],
- }
-
-def build_snap_ent(entry):
- basefields = []
- if entry.tag in ['Package', 'Service']:
- basefields += ['type']
- desired = dict([(key, unicode(entry.get(key))) for key in basefields])
- state = dict([(key, unicode(entry.get(key))) for key in basefields])
- desired.update([(key, unicode(entry.get(key))) for key in \
- datafields[entry.tag]])
- if entry.tag == 'ConfigFile' or \
- ((entry.tag == 'Path') and (entry.get('type') == 'file')):
- if entry.text == None:
- desired['contents'] = None
- else:
- if entry.get('encoding', 'ascii') == 'ascii':
- desired['contents'] = unicode(entry.text)
- else:
- desired['contents'] = unicode(binascii.a2b_base64(entry.text))
-
- if 'current_bfile' in entry.attrib:
- state['contents'] = unicode(binascii.a2b_base64( \
- entry.get('current_bfile')))
- elif 'current_bdiff' in entry.attrib:
- diff = binascii.a2b_base64(entry.get('current_bdiff'))
- state['contents'] = unicode( \
- '\n'.join(difflib.restore(diff.split('\n'), 1)))
-
- state.update([(key, unicode(entry.get('current_' + key, entry.get(key)))) \
- for key in datafields[entry.tag]])
- if entry.tag in ['ConfigFile', 'Path'] and entry.get('exists', 'true') == 'false':
- state = None
- return [desired, state]
-
-
-class Snapshots(Bcfg2.Server.Plugin.Statistics,
- Bcfg2.Server.Plugin.Plugin):
- name = 'Snapshots'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Statistics.__init__(self)
- self.session = Bcfg2.Server.Snapshots.setup_session(core.cfile)
- self.work_queue = Queue.Queue()
- self.loader = threading.Thread(target=self.load_snapshot)
- self.loader.start()
-
- def load_snapshot(self):
- while self.running:
- try:
- (metadata, data) = self.work_queue.get(block=True, timeout=5)
- except:
- continue
- self.statistics_from_old_stats(metadata, data)
-
- def process_statistics(self, metadata, data):
- return self.work_queue.put((metadata, data))
-
- def statistics_from_old_stats(self, metadata, xdata):
- # entries are name -> (modified, correct, start, desired, end)
- # not sure we can get all of this from old format stats
- t1 = time.time()
- entries = dict([('Package', dict()),
- ('Service', dict()), ('Path', dict())])
- extra = dict([('Package', dict()), ('Service', dict()),
- ('Path', dict())])
- bad = []
- state = xdata.find('.//Statistics')
- correct = state.get('state') == 'clean'
- revision = unicode(state.get('revision', '-1'))
- for entry in state.find('.//Bad'):
- data = [False, False, unicode(entry.get('name'))] \
- + build_snap_ent(entry)
- if entry.tag in ftypes:
- etag = 'Path'
- else:
- etag = entry.tag
- entries[etag][entry.get('name')] = data
- for entry in state.find('.//Modified'):
- if entry.tag in ftypes:
- etag = 'Path'
- else:
- etag = entry.tag
- if entry.get('name') in entries[etag]:
- data = [True, False, unicode(entry.get('name'))] + \
- build_snap_ent(entry)
- else:
- data = [True, False, unicode(entry.get('name'))] + \
- build_snap_ent(entry)
- for entry in state.find('.//Extra'):
- if entry.tag in datafields:
- data = build_snap_ent(entry)[1]
- ename = unicode(entry.get('name'))
- data['name'] = ename
- extra[entry.tag][ename] = data
- else:
- print "extra", entry.tag, entry.get('name')
- t2 = time.time()
- snap = Snapshot.from_data(self.session, correct, revision,
- metadata, entries, extra)
- self.session.add(snap)
- self.session.commit()
- t3 = time.time()
- logger.info("Snapshot storage took %fs" % (t3-t2))
- return True
diff --git a/build/lib/Bcfg2/Server/Plugins/Statistics.py b/build/lib/Bcfg2/Server/Plugins/Statistics.py
deleted file mode 100644
index c7fa0e534..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Statistics.py
+++ /dev/null
@@ -1,161 +0,0 @@
-'''This file manages the statistics collected by the BCFG2 Server'''
-__revision__ = '$Revision$'
-
-import binascii
-import copy
-import difflib
-import logging
-from lxml.etree import XML, SubElement, Element, XMLSyntaxError
-import lxml.etree
-import os
-import Queue
-from time import asctime, localtime, time, strptime, mktime
-import threading
-
-import Bcfg2.Server.Plugin
-
-
-class StatisticsStore(object):
- """Manages the memory and file copy of statistics collected about client runs."""
- __min_write_delay__ = 0
-
- def __init__(self, filename):
- self.filename = filename
- self.element = Element('Dummy')
- self.dirty = 0
- self.lastwrite = 0
- self.logger = logging.getLogger('Bcfg2.Server.Statistics')
- self.ReadFromFile()
-
- def WriteBack(self, force=0):
- """Write statistics changes back to persistent store."""
- if (self.dirty and (self.lastwrite + self.__min_write_delay__ <= time())) \
- or force:
- try:
- fout = open(self.filename + '.new', 'w')
- except IOError, ioerr:
- self.logger.error("Failed to open %s for writing: %s" % (self.filename + '.new', ioerr))
- else:
- fout.write(lxml.etree.tostring(self.element, encoding='UTF-8', xml_declaration=True))
- fout.close()
- os.rename(self.filename + '.new', self.filename)
- self.dirty = 0
- self.lastwrite = time()
-
- def ReadFromFile(self):
- """Reads current state regarding statistics."""
- try:
- fin = open(self.filename, 'r')
- data = fin.read()
- fin.close()
- self.element = XML(data)
- self.dirty = 0
- except (IOError, XMLSyntaxError):
- self.logger.error("Creating new statistics file %s"%(self.filename))
- self.element = Element('ConfigStatistics')
- self.WriteBack()
- self.dirty = 0
-
- def updateStats(self, xml, client):
- """Updates the statistics of a current node with new data."""
-
- # Current policy:
- # - Keep anything less than 24 hours old
- # - Keep latest clean run for clean nodes
- # - Keep latest clean and dirty run for dirty nodes
- newstat = xml.find('Statistics')
-
- if newstat.get('state') == 'clean':
- node_dirty = 0
- else:
- node_dirty = 1
-
- # Find correct node entry in stats data
- # The following list comprehension should be guarenteed to return at
- # most one result
- nodes = [elem for elem in self.element.findall('Node') \
- if elem.get('name') == client]
- nummatch = len(nodes)
- if nummatch == 0:
- # Create an entry for this node
- node = SubElement(self.element, 'Node', name=client)
- elif nummatch == 1 and not node_dirty:
- # Delete old instance
- node = nodes[0]
- [node.remove(elem) for elem in node.findall('Statistics') \
- if self.isOlderThan24h(elem.get('time'))]
- elif nummatch == 1 and node_dirty:
- # Delete old dirty statistics entry
- node = nodes[0]
- [node.remove(elem) for elem in node.findall('Statistics') \
- if (elem.get('state') == 'dirty' \
- and self.isOlderThan24h(elem.get('time')))]
- else:
- # Shouldn't be reached
- self.logger.error("Duplicate node entry for %s"%(client))
-
- # Set current time for stats
- newstat.set('time', asctime(localtime()))
-
- # Add statistic
- node.append(copy.deepcopy(newstat))
-
- # Set dirty
- self.dirty = 1
- self.WriteBack(force=1)
-
- def isOlderThan24h(self, testTime):
- """Helper function to determine if <time> string is older than 24 hours."""
- now = time()
- utime = mktime(strptime(testTime))
- secondsPerDay = 60*60*24
-
- return (now-utime) > secondsPerDay
-
-
-class Statistics(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.ThreadedStatistics,
- Bcfg2.Server.Plugin.PullSource):
- name = 'Statistics'
- __version__ = '$Id$'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.ThreadedStatistics.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.PullSource.__init__(self)
- fpath = "%s/etc/statistics.xml" % datastore
- self.data_file = StatisticsStore(fpath)
-
- def handle_statistic(self, metadata, data):
- self.data_file.updateStats(data, metadata.hostname)
-
- def FindCurrent(self, client):
- rt = self.data_file.element.xpath('//Node[@name="%s"]' % client)[0]
- maxtime = max([strptime(stat.get('time')) for stat \
- in rt.findall('Statistics')])
- return [stat for stat in rt.findall('Statistics') \
- if strptime(stat.get('time')) == maxtime][0]
-
- def GetExtra(self, client):
- return [(entry.tag, entry.get('name')) for entry \
- in self.FindCurrent(client).xpath('.//Extra/*')]
-
- def GetCurrentEntry(self, client, e_type, e_name):
- curr = self.FindCurrent(client)
- entry = curr.xpath('.//Bad/%s[@name="%s"]' % (e_type, e_name))
- if not entry:
- raise Bcfg2.Server.Plugin.PluginExecutionError
- cfentry = entry[-1]
-
- owner = cfentry.get('current_owner', cfentry.get('owner'))
- group = cfentry.get('current_group', cfentry.get('group'))
- perms = cfentry.get('current_perms', cfentry.get('perms'))
- if 'current_bfile' in cfentry.attrib:
- contents = binascii.a2b_base64(cfentry.get('current_bfile'))
- elif 'current_bdiff' in cfentry.attrib:
- diff = binascii.a2b_base64(cfentry.get('current_bdiff'))
- contents = '\n'.join(difflib.restore(diff.split('\n'), 1))
- else:
- contents = None
-
- return (owner, group, perms, contents)
diff --git a/build/lib/Bcfg2/Server/Plugins/Svcmgr.py b/build/lib/Bcfg2/Server/Plugins/Svcmgr.py
deleted file mode 100644
index 6d25c1a6d..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Svcmgr.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""This generator provides service mappings."""
-__revision__ = '$Revision$'
-
-import Bcfg2.Server.Plugin
-
-
-class Svcmgr(Bcfg2.Server.Plugin.PrioDir):
- """This is a generator that handles service assignments."""
- name = 'Svcmgr'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- deprecated = True
diff --git a/build/lib/Bcfg2/Server/Plugins/Svn.py b/build/lib/Bcfg2/Server/Plugins/Svn.py
deleted file mode 100644
index cb4ab649b..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Svn.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import os
-from subprocess import Popen, PIPE
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Svn')
-
-
-class Svn(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Svn is a version plugin for dealing with Bcfg2 repos."""
- name = 'Svn'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- self.core = core
- self.datastore = datastore
-
- # path to svn directory for bcfg2 repo
- svn_dir = "%s/.svn" % datastore
-
- # Read revision from bcfg2 repo
- if os.path.isdir(svn_dir):
- self.get_revision()
- else:
- logger.error("%s is not a directory" % svn_dir)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- logger.debug("Initialized svn plugin with svn directory = %s" % svn_dir)
-
- def get_revision(self):
- """Read svn revision information for the Bcfg2 repository."""
- try:
- data = Popen(("env LC_ALL=C svn info %s" %
- (self.datastore)), shell=True,
- stdout=PIPE).communicate()[0].split('\n')
- return [line.split(': ')[1] for line in data \
- if line[:9] == 'Revision:'][-1]
- except IndexError:
- logger.error("Failed to read svn info; disabling svn support")
- logger.error('''Ran command "svn info %s"''' % (self.datastore))
- logger.error("Got output: %s" % data)
- raise Bcfg2.Server.Plugin.PluginInitError
diff --git a/build/lib/Bcfg2/Server/Plugins/TCheetah.py b/build/lib/Bcfg2/Server/Plugins/TCheetah.py
deleted file mode 100644
index d40f4baf3..000000000
--- a/build/lib/Bcfg2/Server/Plugins/TCheetah.py
+++ /dev/null
@@ -1,78 +0,0 @@
-'''This module implements a templating generator based on Cheetah'''
-__revision__ = '$Revision$'
-
-import binascii
-import logging
-import sys
-import traceback
-import Bcfg2.Server.Plugin
-
-logger = logging.getLogger('Bcfg2.Plugins.TCheetah')
-
-try:
- import Cheetah.Template
- import Cheetah.Parser
-except:
- logger.error("TCheetah: Failed to import Cheetah. Is it installed?")
- raise
-
-
-class TemplateFile:
- """Template file creates Cheetah template structures for the loaded file."""
-
- def __init__(self, name, specific, encoding):
- self.name = name
- self.specific = specific
- self.encoding = encoding
- self.template = None
- self.searchlist = dict()
-
- def handle_event(self, event):
- """Handle all fs events for this template."""
- if event.code2str() == 'deleted':
- return
- try:
- s = {'useStackFrames': False}
- self.template = Cheetah.Template.Template(open(self.name).read(),
- compilerSettings=s,
- searchList=self.searchlist)
- except Cheetah.Parser.ParseError, perror:
- logger.error("Cheetah parse error for file %s" % (self.name))
- logger.error(perror.report())
-
- def bind_entry(self, entry, metadata):
- """Build literal file information."""
- self.template.metadata = metadata
- self.searchlist['metadata'] = metadata
- self.template.path = entry.get('realname', entry.get('name'))
- self.searchlist['path'] = entry.get('realname', entry.get('name'))
- self.template.source_path = self.name
- self.searchlist['source_path'] = self.name
-
- if entry.tag == 'Path':
- entry.set('type', 'file')
- try:
- if type(self.template) == unicode:
- entry.text = self.template
- else:
- if entry.get('encoding') == 'base64':
- # take care of case where file needs base64 encoding
- entry.text = binascii.b2a_base64(self.template)
- else:
- entry.text = unicode(str(self.template), self.encoding)
- except:
- (a, b, c) = sys.exc_info()
- msg = traceback.format_exception(a, b, c, limit=2)[-1][:-1]
- logger.error(msg)
- logger.error("TCheetah template error for %s" % self.searchlist['path'])
- del a, b, c
- raise Bcfg2.Server.Plugin.PluginExecutionError
-
-
-class TCheetah(Bcfg2.Server.Plugin.GroupSpool):
- """The TCheetah generator implements a templating mechanism for configuration files."""
- name = 'TCheetah'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- filename_pattern = 'template'
- es_child_cls = TemplateFile
diff --git a/build/lib/Bcfg2/Server/Plugins/TGenshi.py b/build/lib/Bcfg2/Server/Plugins/TGenshi.py
deleted file mode 100644
index 29e6d7307..000000000
--- a/build/lib/Bcfg2/Server/Plugins/TGenshi.py
+++ /dev/null
@@ -1,126 +0,0 @@
-"""This module implements a templating generator based on Genshi."""
-__revision__ = '$Revision$'
-
-import binascii
-import logging
-import Bcfg2.Server.Plugin
-
-logger = logging.getLogger('Bcfg2.Plugins.TGenshi')
-
-# try to import genshi stuff
-try:
- import genshi.core
- import genshi.input
- from genshi.template import TemplateLoader, \
- TextTemplate, MarkupTemplate, TemplateError
-except ImportError:
- logger.error("TGenshi: Failed to import Genshi. Is it installed?")
- raise Bcfg2.Server.Plugin.PluginInitError
-try:
- from genshi.template import NewTextTemplate
- have_ntt = True
-except:
- have_ntt = False
-
-def removecomment(stream):
- """A genshi filter that removes comments from the stream."""
- for kind, data, pos in stream:
- if kind is genshi.core.COMMENT:
- continue
- yield kind, data, pos
-
-
-class TemplateFile:
- """Template file creates Genshi template structures for the loaded file."""
-
- def __init__(self, name, specific, encoding):
- self.name = name
- self.specific = specific
- self.encoding = encoding
- if self.specific.all:
- matchname = self.name
- elif self.specific.group:
- matchname = self.name[:self.name.find('.G')]
- else:
- matchname = self.name[:self.name.find('.H')]
- if matchname.endswith('.txt'):
- self.template_cls = TextTemplate
- elif matchname.endswith('.newtxt'):
- if not have_ntt:
- logger.error("Genshi NewTextTemplates not supported by this version of Genshi")
- else:
- self.template_cls = NewTextTemplate
- else:
- self.template_cls = MarkupTemplate
- self.HandleEvent = self.handle_event
-
- def handle_event(self, event=None):
- """Handle all fs events for this template."""
- if event and event.code2str() == 'deleted':
- return
- try:
- loader = TemplateLoader()
- try:
- self.template = loader.load(self.name, cls=self.template_cls,
- encoding=self.encoding)
- except LookupError, lerror:
- logger.error('Genshi lookup error: %s' % lerror)
- except TemplateError, terror:
- logger.error('Genshi template error: %s' % terror)
- except genshi.input.ParseError, perror:
- logger.error('Genshi parse error: %s' % perror)
-
- def bind_entry(self, entry, metadata):
- """Build literal file information."""
- fname = entry.get('realname', entry.get('name'))
- if entry.tag == 'Path':
- entry.set('type', 'file')
- try:
- stream = self.template.generate( \
- name=fname, metadata=metadata,
- path=self.name).filter(removecomment)
- if have_ntt:
- ttypes = [TextTemplate, NewTextTemplate]
- else:
- ttypes = [TextTemplate]
- if True in [isinstance(self.template, t) for t in ttypes]:
- try:
- textdata = stream.render('text', strip_whitespace=False)
- except TypeError:
- textdata = stream.render('text')
- if type(textdata) == unicode:
- entry.text = textdata
- else:
- if entry.get('encoding') == 'base64':
- # take care of case where file needs base64 encoding
- entry.text = binascii.b2a_base64(textdata)
- else:
- entry.text = unicode(textdata, self.encoding)
- else:
- try:
- xmldata = stream.render('xml', strip_whitespace=False)
- except TypeError:
- xmldata = stream.render('xml')
- if type(xmldata) == unicode:
- entry.text = xmldata
- else:
- entry.text = unicode(xmldata, self.encoding)
- except TemplateError, terror:
- logger.error('Genshi template error: %s' % terror)
- raise Bcfg2.Server.Plugin.PluginExecutionError
- except AttributeError, err:
- logger.error('Genshi template loading error: %s' % err)
- raise Bcfg2.Server.Plugin.PluginExecutionError
-
-
-class TGenshi(Bcfg2.Server.Plugin.GroupSpool):
- """
- The TGenshi generator implements a templating
- mechanism for configuration files.
-
- """
- name = 'TGenshi'
- __version__ = '$Id$'
- __author__ = 'jeff@ocjtech.us'
- filename_pattern = 'template\.(txt|newtxt|xml)'
- es_child_cls = TemplateFile
diff --git a/build/lib/Bcfg2/Server/Plugins/Trigger.py b/build/lib/Bcfg2/Server/Plugins/Trigger.py
deleted file mode 100644
index f6dd47e12..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Trigger.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import os
-import Bcfg2.Server.Plugin
-
-
-def async_run(prog, args):
- pid = os.fork()
- if pid:
- os.waitpid(pid, 0)
- else:
- dpid = os.fork()
- if not dpid:
- os.system(" ".join([prog] + args))
- os._exit(0)
-
-
-class Trigger(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Statistics):
- """Trigger is a plugin that calls external scripts (on the server)."""
- name = 'Trigger'
- __version__ = '$Id'
- __author__ = 'bcfg-dev@mcs.anl.gov'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Statistics.__init__(self)
- try:
- os.stat(self.data)
- except:
- self.logger.error("Trigger: spool directory %s does not exist; unloading" % self.data)
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def process_statistics(self, metadata, _):
- args = [metadata.hostname, '-p', metadata.profile, '-g',
- ':'.join([g for g in metadata.groups])]
- for notifier in os.listdir(self.data):
- n = self.data + '/' + notifier
- async_run(n, args)
diff --git a/build/lib/Bcfg2/Server/Plugins/Web.py b/build/lib/Bcfg2/Server/Plugins/Web.py
deleted file mode 100644
index e1646e429..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Web.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-import BaseHTTPServer
-import SimpleHTTPServer
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Web')
-
-class Web(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Web is a simple webserver to display the content of the Bcfg2 repos."""
- name = 'Web'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self)
- self.core = core
- self.datastore = datastore
-
- # Change directory to the Bcfg2 repo
- ##path = '/home/fab/backup'
- if not os.path.exists(datastore):
- ##print "Path '%s' doesn't exisit" % datastore
- logger.error("%s doesn't exist" % datastore)
- raise Bcfg2.Server.Plugin.PluginInitError
- else:
- os.chdir(datastore)
- self.start_web()
-
- logger.debug("Serving at port %s" % port)
-
-
- def start_web(self, port=6788):
- """Starts the webserver for directory listing of the Bcfg2 repo."""
- try:
- server_class = BaseHTTPServer.HTTPServer
- handler_class = SimpleHTTPServer.SimpleHTTPRequestHandler
- server_address = ('', port)
- server = server_class(server_address, handler_class)
- server.serve_forever()
- except:
- logger.error("Failed to start webserver")
- raise Bcfg2.Server.Plugin.PluginInitError
diff --git a/build/lib/Bcfg2/Server/Plugins/__Web.py b/build/lib/Bcfg2/Server/Plugins/__Web.py
deleted file mode 100644
index e1646e429..000000000
--- a/build/lib/Bcfg2/Server/Plugins/__Web.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-import BaseHTTPServer
-import SimpleHTTPServer
-import Bcfg2.Server.Plugin
-
-# for debugging output only
-import logging
-logger = logging.getLogger('Bcfg2.Plugins.Web')
-
-class Web(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """Web is a simple webserver to display the content of the Bcfg2 repos."""
- name = 'Web'
- __version__ = '$Id$'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- experimental = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self)
- self.core = core
- self.datastore = datastore
-
- # Change directory to the Bcfg2 repo
- ##path = '/home/fab/backup'
- if not os.path.exists(datastore):
- ##print "Path '%s' doesn't exisit" % datastore
- logger.error("%s doesn't exist" % datastore)
- raise Bcfg2.Server.Plugin.PluginInitError
- else:
- os.chdir(datastore)
- self.start_web()
-
- logger.debug("Serving at port %s" % port)
-
-
- def start_web(self, port=6788):
- """Starts the webserver for directory listing of the Bcfg2 repo."""
- try:
- server_class = BaseHTTPServer.HTTPServer
- handler_class = SimpleHTTPServer.SimpleHTTPRequestHandler
- server_address = ('', port)
- server = server_class(server_address, handler_class)
- server.serve_forever()
- except:
- logger.error("Failed to start webserver")
- raise Bcfg2.Server.Plugin.PluginInitError
diff --git a/build/lib/Bcfg2/Server/Plugins/__init__.py b/build/lib/Bcfg2/Server/Plugins/__init__.py
deleted file mode 100644
index c69c37452..000000000
--- a/build/lib/Bcfg2/Server/Plugins/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""Imports for Bcfg2.Server.Plugins."""
-__revision__ = '$Revision$'
-
-__all__ = [
- 'Account',
- 'Base',
- 'Bundler',
- 'Bzr',
- 'Cfg',
- 'Cvs',
- 'Darcs',
- 'Decisions',
- 'Fossil',
- 'Git',
- 'GroupPatterns',
- 'Hg',
- 'Hostbase',
- 'Metadata',
- 'NagiosGen',
- 'Ohai',
- 'Packages',
- 'Properties',
- 'Probes',
- 'Pkgmgr',
- 'Rules',
- 'SSHbase',
- 'Snapshots',
- 'Statistics',
- 'Svcmgr',
- 'Svn',
- 'TCheetah',
- 'Trigger',
- 'SGenshi',
- 'TGenshi',
- ]
diff --git a/build/lib/Bcfg2/Server/Reports/__init__.py b/build/lib/Bcfg2/Server/Reports/__init__.py
deleted file mode 100644
index bdf908f4a..000000000
--- a/build/lib/Bcfg2/Server/Reports/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-__all__ = ['manage', 'nisauth', 'reports', 'settings', 'backends', 'urls', 'importscript']
diff --git a/build/lib/Bcfg2/Server/Reports/backends.py b/build/lib/Bcfg2/Server/Reports/backends.py
deleted file mode 100644
index 9207038ed..000000000
--- a/build/lib/Bcfg2/Server/Reports/backends.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from django.contrib.auth.models import User
-from nisauth import *
-
-class NISBackend(object):
-
- def authenticate(self, username=None, password=None):
- try:
- print "start nis authenticate"
- n = nisauth(username, password)
- temp_pass = User.objects.make_random_password(100)
- nis_user = dict(username=username,
- )
-
- user_session_obj = dict(
- email = username,
- first_name = None,
- last_name = None,
- uid = n.uid
- )
- user, created = User.objects.get_or_create(username=username)
-
- return user
-
- except NISAUTHError, e:
- print str(e)
- return None
-
-
- def get_user(self, user_id):
- try:
- return User.objects.get(pk=user_id)
- except User.DoesNotExist, e:
- print str(e)
- return None
-
diff --git a/build/lib/Bcfg2/Server/Reports/importscript.py b/build/lib/Bcfg2/Server/Reports/importscript.py
deleted file mode 100644
index cdfd8079c..000000000
--- a/build/lib/Bcfg2/Server/Reports/importscript.py
+++ /dev/null
@@ -1,270 +0,0 @@
-#! /usr/bin/env python
-'''Imports statistics.xml and clients.xml files in to database backend for new statistics engine'''
-__revision__ = '$Revision$'
-
-import os, sys, binascii
-try:
- import Bcfg2.Server.Reports.settings
-except Exception, e:
- sys.stderr.write("Failed to load configuration settings. %s\n" % e)
- sys.exit(1)
-
-project_directory = os.path.dirname(Bcfg2.Server.Reports.settings.__file__)
-project_name = os.path.basename(project_directory)
-sys.path.append(os.path.join(project_directory, '..'))
-project_module = __import__(project_name, '', '', [''])
-sys.path.pop()
-# Set DJANGO_SETTINGS_MODULE appropriately.
-os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
-
-from Bcfg2.Server.Reports.reports.models import *
-from lxml.etree import XML, XMLSyntaxError
-from getopt import getopt, GetoptError
-from datetime import datetime
-from time import strptime
-from django.db import connection
-from Bcfg2.Server.Reports.updatefix import update_database
-import ConfigParser
-import logging
-import Bcfg2.Logger
-import platform
-
-def build_reason_kwargs(r_ent):
- binary_file=False
- if r_ent.get('current_bfile', False):
- binary_file=True
- rc_diff = r_ent.get('current_bfile')
- if len(rc_diff) > 1024*1024:
- rc_diff = ''
- elif len(rc_diff) == 0:
- # No point in flagging binary if we have no data
- binary_file=False
- elif r_ent.get('current_bdiff', False):
- rc_diff = binascii.a2b_base64(r_ent.get('current_bdiff'))
- elif r_ent.get('current_diff', False):
- rc_diff = r_ent.get('current_diff')
- else:
- rc_diff = ''
- return dict(owner=r_ent.get('owner', default=""),
- current_owner=r_ent.get('current_owner', default=""),
- group=r_ent.get('group', default=""),
- current_group=r_ent.get('current_group', default=""),
- perms=r_ent.get('perms', default=""),
- current_perms=r_ent.get('current_perms', default=""),
- status=r_ent.get('status', default=""),
- current_status=r_ent.get('current_status', default=""),
- to=r_ent.get('to', default=""),
- current_to=r_ent.get('current_to', default=""),
- version=r_ent.get('version', default=""),
- current_version=r_ent.get('current_version', default=""),
- current_exists=r_ent.get('current_exists', default="True").capitalize()=="True",
- current_diff=rc_diff,
- is_binary=binary_file)
-
-
-def load_stats(cdata, sdata, vlevel, logger, quick=False, location=''):
- clients = {}
- [clients.__setitem__(c.name, c) \
- for c in Client.objects.all()]
-
- pingability = {}
- [pingability.__setitem__(n.get('name'), n.get('pingable', default='N')) \
- for n in cdata.findall('Client')]
-
- for node in sdata.findall('Node'):
- name = node.get('name')
- c_inst, created = Client.objects.get_or_create(name=name)
- if vlevel > 0:
- logger.info("Client %s added to db" % name)
- clients[name] = c_inst
- try:
- pingability[name]
- except KeyError:
- pingability[name] = 'N'
- for statistics in node.findall('Statistics'):
- timestamp = datetime(*strptime(statistics.get('time'))[0:6])
- ilist = Interaction.objects.filter(client=c_inst,
- timestamp=timestamp)
- if ilist:
- current_interaction = ilist[0]
- if vlevel > 0:
- logger.info("Interaction for %s at %s with id %s already exists" % \
- (c_inst.id, timestamp, current_interaction.id))
- continue
- else:
- newint = Interaction(client=c_inst,
- timestamp = timestamp,
- state = statistics.get('state', default="unknown"),
- repo_rev_code = statistics.get('revision',default="unknown"),
- client_version = statistics.get('client_version',default="unknown"),
- goodcount = statistics.get('good',default="0"),
- totalcount = statistics.get('total',default="0"),
- server = location)
- newint.save()
- current_interaction = newint
- if vlevel > 0:
- logger.info("Interaction for %s at %s with id %s INSERTED in to db"%(c_inst.id,
- timestamp, current_interaction.id))
-
-
- counter_fields = { TYPE_CHOICES[0]: 0, TYPE_CHOICES[1]: 0, TYPE_CHOICES[2]: 0 }
- pattern = [('Bad/*', TYPE_CHOICES[0]),
- ('Extra/*', TYPE_CHOICES[2]),
- ('Modified/*', TYPE_CHOICES[1]),]
- for (xpath, type) in pattern:
- for x in statistics.findall(xpath):
- counter_fields[type] = counter_fields[type] + 1
- kargs = build_reason_kwargs(x)
-
- try:
- rr = None
- if not quick:
- try:
- rr = Reason.objects.filter(**kargs)[0]
- except IndexError:
- pass
- if not rr:
- rr = Reason(**kargs)
- rr.save()
- if vlevel > 0:
- logger.info("Created reason: %s" % rr.id)
- except Exception, ex:
- logger.error("Failed to create reason for %s: %s" % (x.get('name'), ex))
- rr = Reason(current_exists=x.get('current_exists',
- default="True").capitalize()=="True")
- rr.save()
-
- entry, created = Entries.objects.get_or_create(\
- name=x.get('name'), kind=x.tag)
-
- Entries_interactions(entry=entry, reason=rr,
- interaction=current_interaction,
- type=type[0]).save()
- if vlevel > 0:
- logger.info("%s interaction created with reason id %s and entry %s" % (xpath, rr.id, entry.id))
-
- # Update interaction counters
- current_interaction.bad_entries = counter_fields[TYPE_CHOICES[0]]
- current_interaction.modified_entries = counter_fields[TYPE_CHOICES[1]]
- current_interaction.extra_entries = counter_fields[TYPE_CHOICES[2]]
- current_interaction.save()
-
- mperfs = []
- for times in statistics.findall('OpStamps'):
- for metric, value in times.items():
- mmatch = []
- if not quick:
- mmatch = Performance.objects.filter(metric=metric, value=value)
-
- if mmatch:
- mperf = mmatch[0]
- else:
- mperf = Performance(metric=metric, value=value)
- mperf.save()
- mperfs.append(mperf)
- current_interaction.performance_items.add(*mperfs)
-
- for key in pingability.keys():
- if key not in clients:
- continue
- try:
- pmatch = Ping.objects.filter(client=clients[key]).order_by('-endtime')[0]
- if pmatch.status == pingability[key]:
- pmatch.endtime = datetime.now()
- pmatch.save()
- continue
- except IndexError:
- pass
- Ping(client=clients[key], status=pingability[key],
- starttime=datetime.now(),
- endtime=datetime.now()).save()
-
- if vlevel > 1:
- logger.info("---------------PINGDATA SYNCED---------------------")
-
- #Clients are consistent
-
-if __name__ == '__main__':
- from sys import argv
- verb = 0
- cpath = "/etc/bcfg2.conf"
- clientpath = False
- statpath = False
- syslog = False
-
- try:
- opts, args = getopt(argv[1:], "hvudc:s:CS", ["help", "verbose", "updates" ,
- "debug", "clients=", "stats=",
- "config=", "syslog"])
- except GetoptError, mesg:
- # print help information and exit:
- print "%s\nUsage:\nimportscript.py [-h] [-v] [-u] [-d] [-S] [-C bcfg2 config file] [-c clients-file] [-s statistics-file]" % (mesg)
- raise SystemExit, 2
-
- for o, a in opts:
- if o in ("-h", "--help"):
- print "Usage:\nimportscript.py [-h] [-v] -c <clients-file> -s <statistics-file> \n"
- print "h : help; this message"
- print "v : verbose; print messages on record insertion/skip"
- print "u : updates; print status messages as items inserted semi-verbose"
- print "d : debug; print most SQL used to manipulate database"
- print "C : path to bcfg2.conf config file."
- print "c : clients.xml file"
- print "s : statistics.xml file"
- print "S : syslog; output to syslog"
- raise SystemExit
- if o in ["-C", "--config"]:
- cpath = a
-
- if o in ("-v", "--verbose"):
- verb = 1
- if o in ("-u", "--updates"):
- verb = 2
- if o in ("-d", "--debug"):
- verb = 3
- if o in ("-c", "--clients"):
- clientspath = a
-
- if o in ("-s", "--stats"):
- statpath = a
- if o in ("-S", "--syslog"):
- syslog = True
-
- logger = logging.getLogger('importscript.py')
- logging.getLogger().setLevel(logging.INFO)
- Bcfg2.Logger.setup_logging('importscript.py',
- True,
- syslog)
-
- cf = ConfigParser.ConfigParser()
- cf.read([cpath])
-
- if not statpath:
- try:
- statpath = "%s/etc/statistics.xml" % cf.get('server', 'repository')
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- print "Could not read bcfg2.conf; exiting"
- raise SystemExit, 1
- try:
- statsdata = XML(open(statpath).read())
- except (IOError, XMLSyntaxError):
- print("StatReports: Failed to parse %s"%(statpath))
- raise SystemExit, 1
-
- if not clientpath:
- try:
- clientspath = "%s/Metadata/clients.xml" % \
- cf.get('server', 'repository')
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- print "Could not read bcfg2.conf; exiting"
- raise SystemExit, 1
- try:
- clientsdata = XML(open(clientspath).read())
- except (IOError, XMLSyntaxError):
- print("StatReports: Failed to parse %s"%(clientspath))
- raise SystemExit, 1
-
- q = '-O3' in sys.argv
- # Be sure the database is ready for new schema
- update_database()
- load_stats(clientsdata, statsdata, verb, logger, quick=q, location=platform.node())
diff --git a/build/lib/Bcfg2/Server/Reports/manage.py b/build/lib/Bcfg2/Server/Reports/manage.py
deleted file mode 100644
index 5e78ea979..000000000
--- a/build/lib/Bcfg2/Server/Reports/manage.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-from django.core.management import execute_manager
-try:
- import settings # Assumed to be in the same directory.
-except ImportError:
- import sys
- sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
- sys.exit(1)
-
-if __name__ == "__main__":
- execute_manager(settings)
diff --git a/build/lib/Bcfg2/Server/Reports/nisauth.py b/build/lib/Bcfg2/Server/Reports/nisauth.py
deleted file mode 100644
index b4be0e391..000000000
--- a/build/lib/Bcfg2/Server/Reports/nisauth.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import os
-import crypt, nis
-from Bcfg2.Server.Reports.settings import AUTHORIZED_GROUP
-
-"""Checks with NIS to see if the current user is in the support group"""
-
-__revision__ = "$Revision: $"
-
-class NISAUTHError(Exception):
- """NISAUTHError is raised when somehting goes boom."""
- pass
-
-class nisauth(object):
- group_test = False
- samAcctName = None
- distinguishedName = None
- sAMAccountName = None
- telephoneNumber = None
- title = None
- memberOf = None
- department = None #this will be a list
- mail = None
- extensionAttribute1 = None #badgenumber
- badge_no = None
- uid = None
-
- def __init__(self,login,passwd=None):
- """get user profile from NIS"""
- try:
- p = nis.match(login, 'passwd.byname').split(":")
- print p
- except:
- raise NISAUTHError('username')
- # check user password using crypt and 2 character salt from passwd file
- if p[1] == crypt.crypt(passwd, p[1][:2]):
- # check to see if user is in valid support groups
- # will have to include these groups in a settings file eventually
- if not login in nis.match(AUTHORIZED_GROUP, 'group.byname').split(':')[-1].split(','):
- raise NISAUTHError('group')
- self.uid = p[2]
- print self.uid
- else:
- raise NISAUTHError('password')
diff --git a/build/lib/Bcfg2/Server/Reports/reports/__init__.py b/build/lib/Bcfg2/Server/Reports/reports/__init__.py
deleted file mode 100644
index ccdce8943..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-__all__ = ['templatetags']
diff --git a/build/lib/Bcfg2/Server/Reports/reports/fixtures/initial_version.xml b/build/lib/Bcfg2/Server/Reports/reports/fixtures/initial_version.xml
deleted file mode 100644
index 1b1359eed..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/fixtures/initial_version.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<django-objects version="1.0">
- <object pk="1" model="reports.internaldatabaseversion">
- <field type="IntegerField" name="version">0</field>
- <field type="DateTimeField" name="updated">2008-08-05 11:03:50</field>
- </object>
- <object pk="2" model="reports.internaldatabaseversion">
- <field type="IntegerField" name="version">1</field>
- <field type="DateTimeField" name="updated">2008-08-05 11:04:10</field>
- </object>
- <object pk="3" model="reports.internaldatabaseversion">
- <field type="IntegerField" name="version">2</field>
- <field type="DateTimeField" name="updated">2008-08-05 13:37:19</field>
- </object>
- <object pk="4" model="reports.internaldatabaseversion">
- <field type='IntegerField' name='version'>3</field>
- <field type='DateTimeField' name='updated'>2008-08-11 08:44:36</field>
- </object>
- <object pk="5" model="reports.internaldatabaseversion">
- <field type='IntegerField' name='version'>10</field>
- <field type='DateTimeField' name='updated'>2008-08-22 11:28:50</field>
- </object>
- <object pk="5" model="reports.internaldatabaseversion">
- <field type='IntegerField' name='version'>11</field>
- <field type='DateTimeField' name='updated'>2009-01-13 12:26:10</field>
- </object>
- <object pk="6" model="reports.internaldatabaseversion">
- <field type='IntegerField' name='version'>16</field>
- <field type='DateTimeField' name='updated'>2010-06-01 12:26:10</field>
- </object>
- <object pk="7" model="reports.internaldatabaseversion">
- <field type='IntegerField' name='version'>17</field>
- <field type='DateTimeField' name='updated'>2010-07-02 00:00:00</field>
- </object>
-</django-objects>
diff --git a/build/lib/Bcfg2/Server/Reports/reports/models.py b/build/lib/Bcfg2/Server/Reports/reports/models.py
deleted file mode 100644
index 1963a9090..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/models.py
+++ /dev/null
@@ -1,328 +0,0 @@
-"""Django models for Bcfg2 reports."""
-from django.db import models
-from django.db import connection, transaction
-from django.db.models import Q
-from datetime import datetime, timedelta
-from time import strptime
-
-KIND_CHOICES = (
- #These are the kinds of config elements
- ('Package', 'Package'),
- ('Path', 'directory'),
- ('Path', 'file'),
- ('Path', 'permissions'),
- ('Path', 'symlink'),
- ('Service', 'Service'),
-)
-PING_CHOICES = (
- #These are possible ping states
- ('Up (Y)', 'Y'),
- ('Down (N)', 'N')
-)
-TYPE_BAD = 1
-TYPE_MODIFIED = 2
-TYPE_EXTRA = 3
-
-TYPE_CHOICES = (
- (TYPE_BAD, 'Bad'),
- (TYPE_MODIFIED, 'Modified'),
- (TYPE_EXTRA, 'Extra'),
-)
-
-def convert_entry_type_to_id(type_name):
- """Convert a entry type to its entry id"""
- for e_id, e_name in TYPE_CHOICES:
- if e_name.lower() == type_name.lower():
- return e_id
- return -1
-
-class ClientManager(models.Manager):
- """Extended client manager functions."""
- def active(self, timestamp=None):
- """returns a set of clients that have been created and have not yet been
- expired as of optional timestmamp argument. Timestamp should be a
- datetime object."""
-
- if timestamp == None:
- timestamp = datetime.now()
- elif not isinstance(timestamp, datetime):
- raise ValueError, 'Expected a datetime object'
- else:
- try:
- timestamp = datetime(*strptime(timestamp, "%Y-%m-%d %H:%M:%S")[0:6])
- except ValueError:
- return self.none()
-
- return self.filter(Q(expiration__gt=timestamp) | Q(expiration__isnull=True),
- creation__lt=timestamp)
-
-
-class Client(models.Model):
- """Object representing every client we have seen stats for."""
- creation = models.DateTimeField(auto_now_add=True)
- name = models.CharField(max_length=128,)
- current_interaction = models.ForeignKey('Interaction',
- null=True, blank=True,
- related_name="parent_client")
- expiration = models.DateTimeField(blank=True, null=True)
-
- def __str__(self):
- return self.name
-
- objects = ClientManager()
-
- class Admin:
- pass
-
-class Ping(models.Model):
- """Represents a ping of a client (sparsely)."""
- client = models.ForeignKey(Client, related_name="pings")
- starttime = models.DateTimeField()
- endtime = models.DateTimeField()
- status = models.CharField(max_length=4, choices=PING_CHOICES)#up/down
-
- class Meta:
- get_latest_by = 'endtime'
-
-class InteractiveManager(models.Manager):
- """Manages interactions objects."""
-
- def recent_interactions_dict(self, maxdate=None, active_only=True):
- """
- Return the most recent interactions for clients as of a date.
-
- This method uses aggregated queries to return a ValuesQueryDict object.
- Faster then raw sql since this is executed as a single query.
- """
-
- return self.values('client').annotate(max_timestamp=Max('timestamp')).values()
-
- def interaction_per_client(self, maxdate = None, active_only=True):
- """
- Returns the most recent interactions for clients as of a date
-
- Arguments:
- maxdate -- datetime object. Most recent date to pull. (dafault None)
- active_only -- Include only active clients (default True)
-
- """
-
- if maxdate and not isinstance(maxdate,datetime):
- raise ValueError, 'Expected a datetime object'
- return self.filter(id__in = self.get_interaction_per_client_ids(maxdate, active_only))
-
- def get_interaction_per_client_ids(self, maxdate = None, active_only=True):
- """
- Returns the ids of most recent interactions for clients as of a date.
-
- Arguments:
- maxdate -- datetime object. Most recent date to pull. (dafault None)
- active_only -- Include only active clients (default True)
-
- """
- from django.db import connection
- cursor = connection.cursor()
- cfilter = "expiration is null"
-
- sql = 'select reports_interaction.id, x.client_id from (select client_id, MAX(timestamp) ' + \
- 'as timer from reports_interaction'
- if maxdate:
- if not isinstance(maxdate,datetime):
- raise ValueError, 'Expected a datetime object'
- sql = sql + " where timestamp <= '%s' " % maxdate
- cfilter = "(expiration is null or expiration > '%s') and creation <= '%s'" % (maxdate,maxdate)
- sql = sql + ' GROUP BY client_id) x, reports_interaction where ' + \
- 'reports_interaction.client_id = x.client_id AND reports_interaction.timestamp = x.timer'
- if active_only:
- sql = sql + " and x.client_id in (select id from reports_client where %s)" % \
- cfilter
- try:
- cursor.execute(sql)
- return [item[0] for item in cursor.fetchall()]
- except:
- '''FIXME - really need some error hadling'''
- pass
- return []
-
-class Interaction(models.Model):
- """Models each reconfiguration operation interaction between client and server."""
- client = models.ForeignKey(Client, related_name="interactions",)
- timestamp = models.DateTimeField()#Timestamp for this record
- state = models.CharField(max_length=32)#good/bad/modified/etc
- repo_rev_code = models.CharField(max_length=64)#repo revision at time of interaction
- client_version = models.CharField(max_length=32)#Client Version
- goodcount = models.IntegerField()#of good config-items
- totalcount = models.IntegerField()#of total config-items
- server = models.CharField(max_length=256) # Name of the server used for the interaction
- bad_entries = models.IntegerField(default=-1)
- modified_entries = models.IntegerField(default=-1)
- extra_entries = models.IntegerField(default=-1)
-
- def __str__(self):
- return "With " + self.client.name + " @ " + self.timestamp.isoformat()
-
- def percentgood(self):
- if not self.totalcount == 0:
- return (self.goodcount/float(self.totalcount))*100
- else:
- return 0
-
- def percentbad(self):
- if not self.totalcount == 0:
- return ((self.totalcount-self.goodcount)/(float(self.totalcount)))*100
- else:
- return 0
-
- def isclean(self):
- if (self.bad_entry_count() == 0 and self.goodcount == self.totalcount):
- return True
- else:
- return False
-
- def isstale(self):
- if (self == self.client.current_interaction):#Is Mostrecent
- if(datetime.now()-self.timestamp > timedelta(hours=25) ):
- return True
- else:
- return False
- else:
- #Search for subsequent Interaction for this client
- #Check if it happened more than 25 hrs ago.
- if (self.client.interactions.filter(timestamp__gt=self.timestamp)
- .order_by('timestamp')[0].timestamp -
- self.timestamp > timedelta(hours=25)):
- return True
- else:
- return False
- def save(self):
- super(Interaction, self).save() #call the real save...
- self.client.current_interaction = self.client.interactions.latest()
- self.client.save()#save again post update
-
- def delete(self):
- '''Override the default delete. Allows us to remove Performance items'''
- pitems = list(self.performance_items.all())
- super(Interaction, self).delete()
- for perf in pitems:
- if perf.interaction.count() == 0:
- perf.delete()
-
- def badcount(self):
- return self.totalcount - self.goodcount
-
- def bad(self):
- return Entries_interactions.objects.select_related().filter(interaction=self, type=TYPE_BAD)
-
- def bad_entry_count(self):
- """Number of bad entries. Store the count in the interation field to save db queries."""
- if self.bad_entries < 0:
- self.bad_entries = Entries_interactions.objects.filter(interaction=self, type=TYPE_BAD).count()
- self.save()
- return self.bad_entries
-
- def modified(self):
- return Entries_interactions.objects.select_related().filter(interaction=self, type=TYPE_MODIFIED)
-
- def modified_entry_count(self):
- """Number of modified entries. Store the count in the interation field to save db queries."""
- if self.modified_entries < 0:
- self.modified_entries = Entries_interactions.objects.filter(interaction=self, type=TYPE_MODIFIED).count()
- self.save()
- return self.modified_entries
-
- def extra(self):
- return Entries_interactions.objects.select_related().filter(interaction=self, type=TYPE_EXTRA)
-
- def extra_entry_count(self):
- """Number of extra entries. Store the count in the interation field to save db queries."""
- if self.extra_entries < 0:
- self.extra_entries = Entries_interactions.objects.filter(interaction=self, type=TYPE_EXTRA).count()
- self.save()
- return self.extra_entries
-
- objects = InteractiveManager()
-
- class Admin:
- list_display = ('client', 'timestamp', 'state')
- list_filter = ['client', 'timestamp']
- pass
- class Meta:
- get_latest_by = 'timestamp'
- ordering = ['-timestamp']
- unique_together = ("client", "timestamp")
-
-class Reason(models.Model):
- """reason why modified or bad entry did not verify, or changed."""
- owner = models.TextField(max_length=128, blank=True)
- current_owner = models.TextField(max_length=128, blank=True)
- group = models.TextField(max_length=128, blank=True)
- current_group = models.TextField(max_length=128, blank=True)
- perms = models.TextField(max_length=4, blank=True)#txt fixes typing issue
- current_perms = models.TextField(max_length=4, blank=True)
- status = models.TextField(max_length=3, blank=True)#on/off/(None)
- current_status = models.TextField(max_length=1, blank=True)#on/off/(None)
- to = models.TextField(max_length=256, blank=True)
- current_to = models.TextField(max_length=256, blank=True)
- version = models.TextField(max_length=128, blank=True)
- current_version = models.TextField(max_length=128, blank=True)
- current_exists = models.BooleanField()#False means its missing. Default True
- current_diff = models.TextField(max_length=1280, blank=True)
- is_binary = models.BooleanField(default=False)
- def _str_(self):
- return "Reason"
-
- @staticmethod
- @transaction.commit_on_success
- def prune_orphans():
- '''Prune oprhaned rows... no good way to use the ORM'''
- cursor = connection.cursor()
- cursor.execute('delete from reports_reason where not exists (select rei.id from reports_entries_interactions rei where rei.reason_id = reports_reason.id)')
- transaction.set_dirty()
-
-
-class Entries(models.Model):
- """Contains all the entries feed by the client."""
- name = models.CharField(max_length=128, db_index=True)
- kind = models.CharField(max_length=16, choices=KIND_CHOICES, db_index=True)
-
- def __str__(self):
- return self.name
-
- @staticmethod
- @transaction.commit_on_success
- def prune_orphans():
- '''Prune oprhaned rows... no good way to use the ORM'''
- cursor = connection.cursor()
- cursor.execute('delete from reports_entries where not exists (select rei.id from reports_entries_interactions rei where rei.entry_id = reports_entries.id)')
- transaction.set_dirty()
-
-class Entries_interactions(models.Model):
- """Define the relation between the reason, the interaction and the entry."""
- entry = models.ForeignKey(Entries)
- reason = models.ForeignKey(Reason)
- interaction = models.ForeignKey(Interaction)
- type = models.IntegerField(choices=TYPE_CHOICES)
-
-class Performance(models.Model):
- """Object representing performance data for any interaction."""
- interaction = models.ManyToManyField(Interaction, related_name="performance_items")
- metric = models.CharField(max_length=128)
- value = models.DecimalField(max_digits=32, decimal_places=16)
- def __str__(self):
- return self.metric
-
- @staticmethod
- @transaction.commit_on_success
- def prune_orphans():
- '''Prune oprhaned rows... no good way to use the ORM'''
- cursor = connection.cursor()
- cursor.execute('delete from reports_performance where not exists (select ri.id from reports_performance_interaction ri where ri.performance_id = reports_performance.id)')
- transaction.set_dirty()
-
-class InternalDatabaseVersion(models.Model):
- """Object that tell us to witch version is the database."""
- version = models.IntegerField()
- updated = models.DateTimeField(auto_now_add=True)
-
- def __str__(self):
- return "version %d updated the %s" % (self.version, self.updated.isoformat())
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/404.html b/build/lib/Bcfg2/Server/Reports/reports/templates/404.html
deleted file mode 100644
index 168bd9fec..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/404.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{% extends 'base.html' %}
-{% block title %}Bcfg2 - Page not found{% endblock %}
-{% block fullcontent %}
-<h2>Page not found</h2>
-<p>
-The page or object requested could not be found.
-</p>
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/base-timeview.html b/build/lib/Bcfg2/Server/Reports/reports/templates/base-timeview.html
deleted file mode 100644
index 842de36f0..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/base-timeview.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends "base.html" %}
-
-{% block timepiece %}
-<script type="text/javascript">
-function showCalendar() {
- var cal = new CalendarPopup("calendar_div");
- cal.showYearNavigation();
- cal.select(document.forms['cal_form'].cal_date,'cal_link',
- 'yyyy/MM/dd' {% if timestamp %}, '{{ timestamp|date:"Y/m/d" }}'{% endif %} );
- return false;
-}
-function bcfg2_check_date() {
- var new_date = document.getElementById('cal_date').value;
- if(new_date) {
- document.cal_form.submit();
- }
-}
-document.write(getCalendarStyles());
-</script>
-{% if not timestamp %}Rendered at {% now "Y-m-d H:i" %} | {% else %}View as of {{ timestamp|date:"Y-m-d H:i" }} | {% endif %}{% spaceless %}
- <a id='cal_link' name='cal_link' href='#' onclick='showCalendar(); return false;'
- >[change]</a>
- <form method='post' action='{{ path }}' id='cal_form' name='cal_form'><input id='cal_date' name='cal_date' type='hidden' value=''/></form>
-{% endspaceless %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/base.html b/build/lib/Bcfg2/Server/Reports/reports/templates/base.html
deleted file mode 100644
index 9bd9da218..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/base.html
+++ /dev/null
@@ -1,95 +0,0 @@
-{% load bcfg2_tags %}
-
-<?xml version="1.0"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<title>{% block title %}Bcfg2 Reporting System{% endblock %}</title>
-
-<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
-<meta http-equiv="Content-language" content="en" />
-<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
-<meta name="robots" content="noindex, nofollow" />
-<meta http-equiv="cache-control" content="no-cache" />
-
-<link rel="stylesheet" type="text/css" href="{% to_media_url bcfg2_base.css %}" media="all" />
-<script type="text/javascript" src="{% to_media_url bcfg2.js %}"></script>
-<script type="text/javascript" src="{% to_media_url date.js %}"></script>
-<script type="text/javascript" src="{% to_media_url AnchorPosition.js %}"></script>
-<script type="text/javascript" src="{% to_media_url CalendarPopup.js %}"></script>
-<script type="text/javascript" src="{% to_media_url PopupWindow.js %}"></script>
-{% block extra_header_info %}{% endblock %}
-
-</head>
-<body onload="{% block body_onload %}{% endblock %}">
-
- <div id="header">
- <a href="http://bcfg2.org"><img src='{% to_media_url bcfg2_logo.png %}'
- height='115' width='300' alt='Bcfg2' style='float:left; height: 115px' /></a>
- </div>
-
-<div id="document">
- <div id="content"><div id="contentwrapper">
- {% block fullcontent %}
- <div class='page_name'>
- <h1>{% block pagebanner %}Page Banner{% endblock %}</h1>
- <div id="timepiece">{% block timepiece %}Rendered at {% now "Y-m-d H:i" %}{% endblock %}</div>
- </div>
- <div class='detail_wrapper'>
- {% block content %}{% endblock %}
- </div>
- {% endblock %}
- </div></div><!-- content -->
- <div id="sidemenucontainer"><div id="sidemenu">
- {% block sidemenu %}
- <ul class='menu-level1'>
- <li>Overview</li>
- </ul>
- <ul class='menu-level2'>
- <li><a href="{% url reports_summary %}">Summary</a></li>
- <li><a href="{% url reports_history %}">Recent Interactions</a></li>
- <li><a href="{% url reports_timing %}">Timing</a></li>
- </ul>
- <ul class='menu-level1'>
- <li>Clients</li>
- </ul>
- <ul class='menu-level2'>
- <li><a href="{% url reports_grid_view %}">Grid View</a></li>
- <li><a href="{% url reports_detailed_list %}">Detailed List</a></li>
- <li><a href="{% url reports_client_manage %}">Manage</a></li>
- </ul>
- <ul class='menu-level1'>
- <li>Entries Configured</li>
- </ul>
- <ul class='menu-level2'>
- <li><a href="{% url reports_item_list "bad" %}">Bad</a></li>
- <li><a href="{% url reports_item_list "modified" %}">Modified</a></li>
- <li><a href="{% url reports_item_list "extra" %}">Extra</a></li>
- </ul>
-{% comment %}
- TODO
- <ul class='menu-level1'>
- <li>Entry Types</li>
- </ul>
- <ul class='menu-level2'>
- <li><a href="#">Action</a></li>
- <li><a href="#">Package</a></li>
- <li><a href="#">Path</a></li>
- <li><a href="#">Service</a></li>
- </ul>
-{% endcomment %}
- <ul class='menu-level1'>
- <li><a href="http://bcfg2.org">Homepage</a></li>
- <li><a href="http://docs.bcfg2.org">Documentation</a></li>
- </ul>
- {% endblock %}
- </div></div><!-- sidemenu -->
- <div style='clear:both'></div>
-</div><!-- document -->
- <div id="footer">
- <span>Bcfg2 Version 1.1.0</span>
- </div>
-
-<div id="calendar_div" style='position:absolute; visibility:hidden; background-color:white; layer-background-color:white;'></div>
-</body>
-</html>
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/detail.html b/build/lib/Bcfg2/Server/Reports/reports/templates/clients/detail.html
deleted file mode 100644
index efd5f9e00..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/detail.html
+++ /dev/null
@@ -1,127 +0,0 @@
-{% extends "base.html" %}
-{% load bcfg2_tags %}
-
-{% block title %}Bcfg2 - Client {{client.name}}{% endblock %}
-
-{% block extra_header_info %}
-<style type="text/css">
-.node_data {
- border: 1px solid #98DBCC;
- margin: 10px;
- padding-left: 18px;
-}
-.node_data td {
- padding: 1px 20px 1px 2px;
-}
-span.history_links {
- font-size: 90%;
- margin-left: 50px;
-}
-span.history_links a {
- font-size: 90%;
-}
-</style>
-{% endblock %}
-
-{% block body_onload %}javascript:clientdetailload(){% endblock %}
-
-{% block pagebanner %}Client Details{% endblock %}
-
-{% block content %}
- <div class='detail_header'>
- <h2>{{client.name}}</h2>
- <a href='{% url reports_client_manage %}#{{ client.name }}'>[manage]</a>
- <span class='history_links'><a href="{% url reports_client_history client.name %}">View History</a> | Jump to&nbsp;
- <select id="quick" name="quick" onchange="javascript:pageJump('quick');">
- <option value="" selected="selected">--- Time ---</option>
- {% for i in client.interactions.all|slice:":25" %}
- <option value="{% url reports_client_detail_pk hostname=client.name, pk=i.id %}">{{i.timestamp}}</option>
- {% endfor %}
- </select></span>
- </div>
-
- {% if interaction.isstale %}
- <div class="warningbox">
- This node did not run within the last 24 hours &#8212; it may be out of date.
- </div>
- {% endif %}
- <table class='node_data'>
- <tr><td>Timestamp</td><td>{{interaction.timestamp}}</td></tr>
- {% if interaction.server %}
- <tr><td>Served by</td><td>{{interaction.server}}</td></tr>
- {% endif %}
- {% if interaction.repo_rev_code %}
- <tr><td>Revision</td><td>{{interaction.repo_rev_code}}</td></tr>
- {% endif %}
- <tr><td>State</td><td class='{{interaction.state}}-lineitem'>{{interaction.state|capfirst}}</td></tr>
- <tr><td>Managed entries</td><td>{{interaction.totalcount}}</td></tr>
- {% if not interaction.isclean %}
- <tr><td>Deviation</td><td>{{interaction.percentbad|floatformat:"3"}}%</td></tr>
- {% endif %}
- </table>
-
- {% if interaction.bad_entry_count %}
- <div class='entry_list'>
- <div class='entry_list_head dirty-lineitem'>
- <div class='entry_expand_tab' onclick='javascript:toggleMe("bad_table");'>[+]</div>
- <h3>Bad Entries &#8212; {{ interaction.bad_entry_count }}</h3>
- </div>
- <table id='bad_table' class='entry_list'>
- {% for e in interaction.bad|sortwell %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td class='entry_list_type'>{{e.entry.kind}}:</td>
- <td><a href="{% url reports_item "bad",e.id %}">
- {{e.entry.name}}</a></td>
- </tr>
- {% endfor %}
- </table>
- </div>
- {% endif %}
-
- {% if interaction.modified_entry_count %}
- <div class='entry_list'>
- <div class='entry_list_head modified-lineitem'>
- <div class='entry_expand_tab' onclick='javascript:toggleMe("modified_table");'>[+]</div>
- <h3>Modified Entries &#8212; {{ interaction.modified_entry_count }}</h3>
- </div>
- <table id='modified_table' class='entry_list'>
- {% for e in interaction.modified|sortwell %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td class='entry_list_type'>{{e.entry.kind}}:</td>
- <td><a href="{% url reports_item "modified",e.id %}">
- {{e.entry.name}}</a></td>
- </tr>
- {% endfor %}
- </table>
- </div>
- {% endif %}
-
- {% if interaction.extra_entry_count %}
- <div class='entry_list'>
- <div class='entry_list_head extra-lineitem'>
- <div class='entry_expand_tab' onclick='javascript:toggleMe("extra_table");'>[+]</div>
- <h3>Extra Entries &#8212; {{ interaction.extra_entry_count }}</h3>
- </div>
- <table id='extra_table' class='entry_list'>
- {% for e in interaction.extra|sortwell %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td class='entry_list_type'>{{e.entry.kind}}:</td>
- <td><a href="{% url reports_item "extra",e.id %}">{{e.entry.name}}</a></td>
- </tr>
- {% endfor %}
- </table>
- </div>
- {% endif %}
-
- {% if entry_list %}
- <div class="entry_list recent_history_wrapper">
- <div class="entry_list_head" style="border-bottom: 2px solid #98DBCC;">
- <h4 style="display: inline"><a href="{% url reports_client_history client.name %}">Recent Interactions</a></h4>
- </div>
- <div class='recent_history_box'>
- {% include "widgets/interaction_list.inc" %}
- <div style='padding-left: 5px'><a href="{% url reports_client_history client.name %}">more...</a></div>
- </div>
- </div>
- {% endif %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html b/build/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html
deleted file mode 100644
index 0c1fae8d5..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends "base-timeview.html" %}
-{% load bcfg2_tags %}
-
-{% block title %}Bcfg2 - Detailed Client Listing{% endblock %}
-{% block pagebanner %}Clients - Detailed View{% endblock %}
-
-{% block content %}
-<div class='client_list_box'>
-{% if entry_list %}
- {% filter_navigator %}
- <table cellpadding="3">
- <tr id='table_list_header' class='listview'>
- <td class='left_column'>Node</td>
- <td class='right_column' style='width:75px'>State</td>
- <td class='right_column_narrow'>Good</td>
- <td class='right_column_narrow'>Bad</td>
- <td class='right_column_narrow'>Modified</td>
- <td class='right_column_narrow'>Extra</td>
- <td class='right_column'>Last Run</td>
- <td class='right_column_wide'>Server</td>
- </tr>
- {% for entry in entry_list %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td class='left_column'><a href='{% url Bcfg2.Server.Reports.reports.views.client_detail hostname=entry.client.name, pk=entry.id %}'>{{ entry.client.name }}</a></td>
- <td class='right_column' style='width:75px'><a href='{% add_url_filter state=entry.state %}'
- {% ifequal entry.state 'dirty' %}class='dirty-lineitem'{% endifequal %}>{{ entry.state }}</a></td>
- <td class='right_column_narrow'>{{ entry.goodcount }}</td>
- <td class='right_column_narrow'>{{ entry.bad_entry_count }}</td>
- <td class='right_column_narrow'>{{ entry.modified_entry_count }}</td>
- <td class='right_column_narrow'>{{ entry.extra_entry_count }}</td>
- <td class='right_column'><span {% if entry.timestamp|isstale:entry_max %}class='dirty-lineitem'{% endif %}>{{ entry.timestamp|date:"Y-m-d\&\n\b\s\p\;H:i"|safe }}</span></td>
- <td class='right_column_wide'>
- {% if entry.server %}
- <a href='{% add_url_filter server=entry.server %}'>{{ entry.server }}</a>
- {% else %}
- &nbsp;
- {% endif %}
- </td>
- </tr>
- {% endfor %}
- </table>
-{% else %}
- <p>No client records are available.</p>
-{% endif %}
-</div>
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/history.html b/build/lib/Bcfg2/Server/Reports/reports/templates/clients/history.html
deleted file mode 100644
index 01d4ec2f4..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/history.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends "base.html" %}
-{% load bcfg2_tags %}
-
-{% block title %}Bcfg2 - Interaction History{% endblock %}
-{% block pagebanner %}Interaction history{% if client %} for {{ client.name }}{% endif %}{% endblock %}
-
-{% block extra_header_info %}
-{% endblock %}
-
-{% block content %}
-<div class='client_list_box'>
-{% if entry_list %}
- {% filter_navigator %}
- {% include "widgets/interaction_list.inc" %}
-{% else %}
- <p>No client records are available.</p>
-{% endif %}
-</div>
-{% page_navigator %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html b/build/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html
deleted file mode 100644
index e0c0d2d7a..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{% extends "base-timeview.html" %}
-
-{% block extra_header_info %}
-{% endblock%}
-
-{% block title %}Bcfg2 - Client Grid View{% endblock %}
-
-{% block pagebanner %}Clients - Grid View{% endblock %}
-
-{% block content %}
-
-{% if inter_list %}
- <table class='grid-view' align='center'>
- {% for inter in inter_list %}
- {% if forloop.first %}<tr>{% endif %}
- <td class="{{inter.state}}-lineitem">
- <a href="{% spaceless %}{% if not timestamp %}
- {% url reports_client_detail inter.client.name %}
- {% else %}
- {% url reports_client_detail_pk inter.client.name,inter.id %}
- {% endif %}
- {% endspaceless %}">{{ inter.client.name }}</a>
- </td>
- {% if forloop.last %}
- </tr>
- {% else %}
- {% if forloop.counter|divisibleby:"4" %}</tr><tr>{% endif %}
- {% endif %}
- {% endfor %}
- </table>
-{% else %}
- <p>No client records are available.</p>
-{% endif %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/manage.html b/build/lib/Bcfg2/Server/Reports/reports/templates/clients/manage.html
deleted file mode 100644
index 5725ae577..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/clients/manage.html
+++ /dev/null
@@ -1,45 +0,0 @@
-{% extends "base.html" %}
-
-{% block extra_header_info %}
-{% endblock%}
-
-{% block title %}Bcfg2 - Manage Clients{% endblock %}
-
-{% block pagebanner %}Clients - Manage{% endblock %}
-
-{% block content %}
-<div class='client_list_box'>
- {% if message %}
- <div class="warningbox">{{ message }}</div>
- {% endif %}
-{% if clients %}
- <table cellpadding="3">
- <tr id='table_list_header' class='listview'>
- <td class='left_column'>Node</td>
- <td class='right_column'>Expiration</td>
- <td class='right_column_narrow'>Manage</td>
- </tr>
- {% for client in clients %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td><span id="{{ client.name }}"> </span>
- <span id="ttag-{{ client.name }}"> </span>
- <span id="s-ttag-{{ client.name }}"> </span>
- <a href="{% url reports_client_detail client.name %}">{{ client.name }}</a></td>
- <td>{% firstof client.expiration 'Active' %}</td>
- <td>
- <form method="post" action="{% url reports_client_manage %}">
- <div> {# here for no reason other then to validate #}
- <input type="hidden" name="client_name" value="{{ client.name }}" />
- <input type="hidden" name="client_action" value="{% if client.expiration %}unexpire{% else %}expire{% endif %}" />
- <input type="submit" value="{% if client.expiration %}Activate{% else %}Expire Now{% endif %}" />
- </div>
- </form>
- </td>
- </tr>
- {% endfor %}
- </table>
- </div>
-{% else %}
- <p>No client records are available.</p>
-{% endif %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html b/build/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html
deleted file mode 100644
index 58aed1684..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html
+++ /dev/null
@@ -1,109 +0,0 @@
-{% extends "base.html" %}
-{% load syntax_coloring %}
-
-
-{% block title %}Bcfg2 - Element Details{% endblock %}
-
-
-{% block extra_header_info %}
-<style type="text/css">
-#table_list_header {
- font-size: 100%;
-}
-table.entry_list {
- width: auto;
-}
-div.information_wrapper {
- margin: 15px;
-}
-div.diff_wrapper {
- overflow: auto;
-}
-div.entry_list h3 {
- font-size: 90%;
- padding: 5px;
-}
-</style>
-{% endblock%}
-
-{% block pagebanner %}Element Details{% endblock %}
-
-{% block content %}
- <div class='detail_header'>
- <h3>{{mod_or_bad|capfirst}} {{item.entry.kind}}: {{item.entry.name}}</h3>
- </div>
-
- <div class="information_wrapper">
-
- {% if isextra %}
- <p>This item exists on the host but is not defined in the configuration.</p>
- {% endif %}
-
- {% if not item.reason.current_exists %}
- <div class="warning">This item does not currently exist on the host but is specified to exist in the configuration.</div>
- {% endif %}
-
- {% if item.reason.current_owner or item.reason.current_group or item.reason.current_perms or item.reason.current_status or item.reason.current_status or item.reason.current_to or item.reason.current_version %}
- <table class='entry_list'>
- <tr id='table_list_header'>
- <td style='text-align: right;'>Problem Type</td><td>Expected</td><td style='border-bottom: 1px solid #98DBCC;'>Found</td></tr>
- {% if item.reason.current_owner %}
- <tr><td style='text-align: right'><b>Owner</b></td><td>{{item.reason.owner}}</td>
- <td>{{item.reason.current_owner}}</td></tr>
- {% endif %}
- {% if item.reason.current_group %}
- <tr><td style='text-align: right'><b>Group</b></td><td>{{item.reason.group}}</td>
- <td>{{item.reason.current_group}}</td></tr>
- {% endif %}
- {% if item.reason.current_perms %}
- <tr><td style='text-align: right'><b>Permissions</b></td><td>{{item.reason.perms}}</td>
- <td>{{item.reason.current_perms}}</td></tr>
- {% endif %}
- {% if item.reason.current_status %}
- <tr><td style='text-align: right'><b>Status</b></td><td>{{item.reason.status}}</td>
- <td>{{item.reason.current_status}}</td></tr>
- {% endif %}
- {% if item.reason.current_to %}
- <tr><td style='text-align: right'><b>Symlink Target</b></td><td>{{item.reason.to}}</td>
- <td>{{item.reason.current_to}}</td></tr>
- {% endif %}
- {% if item.reason.current_version %}
- <tr><td style='text-align: right'><b>Package Version</b></td><td>{{item.reason.version|cut:"("|cut:")"}}</td>
- <td>{{item.reason.current_version|cut:"("|cut:")"}}</td></tr>
- {% endif %}
- </table>
- {% endif %}
-
- {% if item.reason.current_diff %}
- <div class='entry_list'>
- <div class='entry_list_head'>
- <h3>Incorrect file contents</h3>
- </div>
- <div class='diff_wrapper'>
- {{ item.reason.current_diff|syntaxhilight }}
- </div>
- </div>
- {% endif %}
-
-
- <div class='entry_list'>
- <div class='entry_list_head'>
- <h3>Occurences on {{ timestamp|date:"Y-m-d" }}</h3>
- </div>
- {% if associated_list %}
- <table class="entry_list" cellpadding="3">
- {% for inter in associated_list %}
- <tr><td><a href="{% url reports_client_detail inter.client.name %}"
- >{{inter.client.name}}</a></td>
- <td><a href="{% url reports_client_detail_pk hostname=inter.client.name,pk=inter.id %}"
- >{{inter.timestamp}}</a></td>
- </tr>
- {% endfor %}
- </table>
- {% else %}
- <p>Missing client list</p>
- {% endif %}
- </div>
-
- </div><!-- information_wrapper -->
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/config_items/listing.html b/build/lib/Bcfg2/Server/Reports/reports/templates/config_items/listing.html
deleted file mode 100644
index 572249470..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/config_items/listing.html
+++ /dev/null
@@ -1,33 +0,0 @@
-{% extends "base-timeview.html" %}
-{% load bcfg2_tags %}
-
-{% block title %}Bcfg2 - Element Listing{% endblock %}
-
-{% block extra_header_info %}
-{% endblock%}
-
-{% block pagebanner %}{{mod_or_bad|capfirst}} Element Listing{% endblock %}
-
-{% block content %}
-{% if item_list_dict %}
- {% for kind, entries in item_list_dict.items %}
-
- <div class='entry_list'>
- <div class='entry_list_head element_list_head'>
- <div class='entry_expand_tab' onclick='javascript:toggleMe("table_{{ kind }}");'>[+]</div>
- <h3>{{ kind }} &#8212; {{ entries|length }}</h3>
- </div>
-
- <table id='table_{{ kind }}' class='entry_list'>
- {% for e in entries %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td><a href="{% url reports_item type=mod_or_bad,pk=e.id %}">{{e.entry.name}}</a></td>
- </tr>
- {% endfor %}
- </table>
- </div>
- {% endfor %}
-{% else %}
- <p>There are currently no inconsistent configuration entries.</p>
-{% endif %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/displays/summary.html b/build/lib/Bcfg2/Server/Reports/reports/templates/displays/summary.html
deleted file mode 100644
index 0124f635d..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/displays/summary.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% extends "base-timeview.html" %}
-{% load bcfg2_tags %}
-
-{% block title %}Bcfg2 - Client Summary{% endblock %}
-{% block pagebanner %}Clients - Summary{% endblock %}
-
-{% block body_onload %}javascript:hide_table_array(hide_tables){% endblock %}
-
-{% block extra_header_info %}
-<script type="text/javascript">
-var hide_tables = new Array({{ summary_data|length }});
-{% for summary in summary_data %}
-hide_tables[{{ forloop.counter0 }}] = "table_{{ summary.name }}";
-{% endfor %}
-</script>
-{% endblock%}
-
-{% block content %}
- <div class='detail_header'>
- <h2>{{ node_count }} nodes reporting in</h2>
- </div>
-{% if summary_data %}
- {% for summary in summary_data %}
- <div class='entry_list'>
- <div class='entry_list_head element_list_head'>
- <div class='entry_expand_tab' onclick='javascript:toggleMe("table_{{ summary.name }}");'>[+]</div>
- <h3>{{ summary.nodes|length }} {{ summary.label }}</h3>
- </div>
-
- <table id='table_{{ summary.name }}' class='entry_list'>
- {% for node in summary.nodes|sort_interactions_by_name %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td><a href="{% url reports_client_detail_pk hostname=node.client.name,pk=node.id %}">{{ node.client.name }}</a></td>
- </tr>
- {% endfor %}
- </table>
- </div>
- {% endfor %}
-{% else %}
- <p>No data to report on</p>
-{% endif %}
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/displays/timing.html b/build/lib/Bcfg2/Server/Reports/reports/templates/displays/timing.html
deleted file mode 100644
index 47accb2cb..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/displays/timing.html
+++ /dev/null
@@ -1,38 +0,0 @@
-{% extends "base-timeview.html" %}
-{% load bcfg2_tags %}
-
-{% block title %}Bcfg2 - Performance Metrics{% endblock %}
-{% block pagebanner %}Performance Metrics{% endblock %}
-
-
-{% block extra_header_info %}
-{% endblock%}
-
-{% block content %}
-<div class='client_list_box'>
- {% if metrics %}
- <table cellpadding="3">
- <tr id='table_list_header' class='listview'>
- <td>Name</td>
- <td>Parse</td>
- <td>Probe</td>
- <td>Inventory</td>
- <td>Install</td>
- <td>Config</td>
- <td>Total</td>
- </tr>
- {% for metric in metrics|dictsort:"name" %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td><a style='font-size: 100%'
- href="{% url reports_client_detail hostname=metric.name %}">{{ metric.name }}</a></td>
- {% for mitem in metric|build_metric_list %}
- <td>{{ mitem }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </table>
- {% else %}
- <p>No metric data available</p>
- {% endif %}
-</div>
-{% endblock %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/filter_bar.html b/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/filter_bar.html
deleted file mode 100644
index 6b57baf6a..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/filter_bar.html
+++ /dev/null
@@ -1,13 +0,0 @@
-{% spaceless %}
-{% if filters %}
-{% for filter, filter_url in filters %}
- {% if forloop.first %}
- <div class="filter_bar">Active filters (click to remove):
- {% endif %}
- <a href='{{ filter_url }}'>{{ filter|capfirst }}</a>{% if not forloop.last %}, {% endif %}
- {% if forloop.last %}
- </div>
- {% endif %}
-{% endfor %}
-{% endif %}
-{% endspaceless %}
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc b/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc
deleted file mode 100644
index 8f2dec1dc..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc
+++ /dev/null
@@ -1,38 +0,0 @@
-{% load bcfg2_tags %}
-<div class='interaction_history_widget'>
- <table cellpadding="3">
- <tr id='table_list_header' class='listview'>
- <td class='left_column'>Timestamp</td>
- {% if not client %}
- <td class='right_column_wide'>Client</td>
- {% endif %}
- <td class='right_column' style='width:75px'>State</td>
- <td class='right_column_narrow'>Good</td>
- <td class='right_column_narrow'>Bad</td>
- <td class='right_column_narrow'>Modified</td>
- <td class='right_column_narrow'>Extra</td>
- <td class='right_column_wide'>Server</td>
- </tr>
- {% for entry in entry_list %}
- <tr class='{% cycle listview,listview_alt %}'>
- <td class='left_column'><a href='{% url reports_client_detail_pk hostname=entry.client.name, pk=entry.id %}'>{{ entry.timestamp|date:"Y-m-d\&\n\b\s\p\;H:i"|safe }}</a></td>
- {% if not client %}
- <td class='right_column_wide'><a href='{% add_url_filter hostname=entry.client.name %}'>{{ entry.client.name }}</a></td>
- {% endif %}
- <td class='right_column' style='width:75px'><a href='{% add_url_filter state=entry.state %}'
- {% ifequal entry.state 'dirty' %}class='dirty-lineitem'{% endifequal %}>{{ entry.state }}</a></td>
- <td class='right_column_narrow'>{{ entry.goodcount }}</td>
- <td class='right_column_narrow'>{{ entry.bad_entry_count }}</td>
- <td class='right_column_narrow'>{{ entry.modified_entry_count }}</td>
- <td class='right_column_narrow'>{{ entry.extra_entry_count }}</td>
- <td class='right_column_wide'>
- {% if entry.server %}
- <a href='{% add_url_filter server=entry.server %}'>{{ entry.server }}</a>
- {% else %}
- &nbsp;
- {% endif %}
- </td>
- </tr>
- {% endfor %}
- </table>
-</div>
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/page_bar.html b/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/page_bar.html
deleted file mode 100644
index aa0def83e..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templates/widgets/page_bar.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% spaceless %}
-{% for page, page_url in pager %}
- {% if forloop.first %}
- <div class="page_bar">
- {% if prev_page %}<a href="{{ prev_page }}">&lt; Prev</a><span>&nbsp;</span>{% endif %}
- {% if first_page %}<a href="{{ first_page }}">1</a><span>&nbsp;...&nbsp;</span>{% endif %}
- {% endif %}
- {% ifequal page current_page %}
- <span class='nav_bar_current'>{{ page }}</span>
- {% else %}
- <a href="{{ page_url }}">{{ page }}</a>
- {% endifequal %}
- {% if forloop.last %}
- {% if last_page %}<span>&nbsp;...&nbsp;</span><a href="{{ last_page }}">{{ total_pages }}</a><span>&nbsp;</span>{% endif %}
- {% if next_page %}<a href="{{ next_page }}">Next &gt;</a><span>&nbsp;</span>{% endif %}
- |{% for limit, limit_url in page_limits %}&nbsp;<a href="{{ limit_url }}">{{ limit }}</a>{% endfor %}
- </div>
- {% else %}
- <span>&nbsp;</span>
- {% endif %}
-{% endfor %}
-{% endspaceless %}
-<!-- {{ path }} -->
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templatetags/__init__.py b/build/lib/Bcfg2/Server/Reports/reports/templatetags/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templatetags/__init__.py
+++ /dev/null
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py b/build/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py
deleted file mode 100644
index 7fffe289d..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py
+++ /dev/null
@@ -1,274 +0,0 @@
-from django import template
-from django.core.urlresolvers import resolve, reverse, Resolver404, NoReverseMatch
-from django.utils.encoding import smart_unicode, smart_str
-from datetime import datetime, timedelta
-from Bcfg2.Server.Reports.utils import filter_list
-
-register = template.Library()
-
-__PAGE_NAV_LIMITS__ = (10, 25, 50, 100)
-
-@register.inclusion_tag('widgets/page_bar.html', takes_context=True)
-def page_navigator(context):
- """
- Creates paginated links.
-
- Expects the context to be a RequestContext and views.prepare_paginated_list()
- to have populated page information.
- """
- fragment = dict()
- try:
- path = context['request'].META['PATH_INFO']
- total_pages = int(context['total_pages'])
- records_per_page = int(context['records_per_page'])
- except KeyError, e:
- return fragment
- except ValueError, e:
- return fragment
-
- if total_pages < 2:
- return {}
-
- try:
- view, args, kwargs = resolve(path)
- current_page = int(kwargs.get('page_number',1))
- fragment['current_page'] = current_page
- fragment['page_number'] = current_page
- fragment['total_pages'] = total_pages
- fragment['records_per_page'] = records_per_page
- if current_page > 1:
- kwargs['page_number'] = current_page - 1
- fragment['prev_page'] = reverse(view, args=args, kwargs=kwargs)
- if current_page < total_pages:
- kwargs['page_number'] = current_page + 1
- fragment['next_page'] = reverse(view, args=args, kwargs=kwargs)
-
- view_range = 5
- if total_pages > view_range:
- pager_start = current_page - 2
- pager_end = current_page + 2
- if pager_start < 1:
- pager_end += (1 - pager_start)
- pager_start = 1
- if pager_end > total_pages:
- pager_start -= (pager_end - total_pages)
- pager_end = total_pages
- else:
- pager_start = 1
- pager_end = total_pages
-
- if pager_start > 1:
- kwargs['page_number'] = 1
- fragment['first_page'] = reverse(view, args=args, kwargs=kwargs)
- if pager_end < total_pages:
- kwargs['page_number'] = total_pages
- fragment['last_page'] = reverse(view, args=args, kwargs=kwargs)
-
- pager = []
- for page in range(pager_start, int(pager_end) + 1):
- kwargs['page_number'] = page
- pager.append( (page, reverse(view, args=args, kwargs=kwargs)) )
-
- kwargs['page_number'] = 1
- page_limits = []
- for limit in __PAGE_NAV_LIMITS__:
- kwargs['page_limit'] = limit
- page_limits.append( (limit, reverse(view, args=args, kwargs=kwargs)) )
- # resolver doesn't like this
- del kwargs['page_number']
- del kwargs['page_limit']
- page_limits.append( ('all', reverse(view, args=args, kwargs=kwargs) + "|all") )
-
- fragment['pager'] = pager
- fragment['page_limits'] = page_limits
-
- except Resolver404:
- path = "404"
- except NoReverseMatch, nr:
- path = "NoReverseMatch: %s" % nr
- except ValueError:
- path = "ValueError"
- #FIXME - Handle these
-
- fragment['path'] = path
- return fragment
-
-@register.inclusion_tag('widgets/filter_bar.html', takes_context=True)
-def filter_navigator(context):
- try:
- path = context['request'].META['PATH_INFO']
- view, args, kwargs = resolve(path)
-
- # Strip any page limits and numbers
- if 'page_number' in kwargs:
- del kwargs['page_number']
- if 'page_limit' in kwargs:
- del kwargs['page_limit']
-
- filters = []
- for filter in filter_list:
- if filter in kwargs:
- myargs = kwargs.copy()
- del myargs[filter]
- filters.append( (filter, reverse(view, args=args, kwargs=myargs) ) )
- filters.sort(lambda x,y: cmp(x[0], y[0]))
- return { 'filters': filters }
- except (Resolver404, NoReverseMatch, ValueError, KeyError):
- pass
- return dict()
-
-def _subtract_or_na(mdict, x, y):
- """
- Shortcut for build_metric_list
- """
- try:
- return round(mdict[x] - mdict[y], 4)
- except:
- return "n/a"
-
-@register.filter
-def build_metric_list(mdict):
- """
- Create a list of metric table entries
-
- Moving this here it simplify the view. Should really handle the case where these
- are missing...
- """
- td_list = []
- # parse
- td_list.append( _subtract_or_na(mdict, 'config_parse', 'config_download'))
- #probe
- td_list.append( _subtract_or_na(mdict, 'probe_upload', 'start'))
- #inventory
- td_list.append( _subtract_or_na(mdict, 'inventory', 'initialization'))
- #install
- td_list.append( _subtract_or_na(mdict, 'install', 'inventory'))
- #cfg download & parse
- td_list.append( _subtract_or_na(mdict, 'config_parse', 'probe_upload'))
- #total
- td_list.append( _subtract_or_na(mdict, 'finished', 'start'))
- return td_list
-
-@register.filter
-def isstale(timestamp, entry_max=None):
- """
- Check for a stale timestamp
-
- Compares two timestamps and returns True if the
- difference is greater then 24 hours.
- """
- if not entry_max:
- entry_max = datetime.now()
- return entry_max - timestamp > timedelta(hours=24)
-
-@register.filter
-def sort_interactions_by_name(value):
- """
- Sort an interaction list by client name
- """
- inters = list(value)
- inters.sort(lambda a,b: cmp(a.client.name, b.client.name))
- return inters
-
-class AddUrlFilter(template.Node):
- def __init__(self, filter_name, filter_value):
- self.filter_name = filter_name
- self.filter_value = filter_value
- self.fallback_view = 'Bcfg2.Server.Reports.reports.views.render_history_view'
-
- def render(self, context):
- link = '#'
- try:
- path = context['request'].META['PATH_INFO']
- view, args, kwargs = resolve(path)
- filter_value = self.filter_value.resolve(context, True)
- if filter_value:
- filter_name = smart_str(self.filter_name)
- filter_value = smart_unicode(filter_value)
- kwargs[filter_name] = filter_value
- # These two don't make sense
- if filter_name == 'server' and 'hostname' in kwargs:
- del kwargs['hostname']
- elif filter_name == 'hostname' and 'server' in kwargs:
- del kwargs['server']
- try:
- link = reverse(view, args=args, kwargs=kwargs)
- except NoReverseMatch, rm:
- link = reverse(self.fallback_view, args=None,
- kwargs={ filter_name: filter_value })
- except NoReverseMatch, rm:
- raise rm
- except (Resolver404, ValueError), e:
- pass
- return link
-
-@register.tag
-def add_url_filter(parser, token):
- """
- Return a url with the filter added to the current view.
-
- Takes a new filter and resolves the current view with the new filter
- applied. Resolves to Bcfg2.Server.Reports.reports.views.client_history
- by default.
-
- {% add_url_filter server=interaction.server %}
- """
- try:
- tag_name, filter_pair = token.split_contents()
- filter_name, filter_value = filter_pair.split('=', 1)
- filter_name = filter_name.strip()
- filter_value = parser.compile_filter(filter_value)
- except ValueError:
- raise template.TemplateSyntaxError, "%r tag requires exactly one argument" % token.contents.split()[0]
- if not filter_name or not filter_value:
- raise template.TemplateSyntaxError, "argument should be a filter=value pair"
-
- return AddUrlFilter(filter_name, filter_value)
-
-@register.filter
-def sortwell(value):
- """
- Sorts a list(or evaluates queryset to list) of bad, extra, or modified items in the best
- way for presentation
- """
-
- configItems = list(value)
- configItems.sort(lambda x,y: cmp(x.entry.name, y.entry.name))
- configItems.sort(lambda x,y: cmp(x.entry.kind, y.entry.kind))
- return configItems
-
-class MediaTag(template.Node):
- def __init__(self, filter_value):
- self.filter_value = filter_value
-
- def render(self, context):
- base = context['MEDIA_URL']
- try:
- request = context['request']
- try:
- base = request.environ['bcfg2.media_url']
- except:
- if request.path != request.META['PATH_INFO']:
- offset = request.path.find(request.META['PATH_INFO'])
- if offset > 0:
- base = "%s/%s" % (request.path[:offset], \
- context['MEDIA_URL'].strip('/'))
- except:
- pass
- return "%s/%s" % (base, self.filter_value)
-
-@register.tag
-def to_media_url(parser, token):
- """
- Return a url relative to the media_url.
-
- {% to_media_url /bcfg2.css %}
- """
- try:
- tag_name, filter_value = token.split_contents()
- filter_value = parser.compile_filter(filter_value)
- except ValueError:
- raise template.TemplateSyntaxError, "%r tag requires exactly one argument" % token.contents.split()[0]
-
- return MediaTag(filter_value)
-
diff --git a/build/lib/Bcfg2/Server/Reports/reports/templatetags/syntax_coloring.py b/build/lib/Bcfg2/Server/Reports/reports/templatetags/syntax_coloring.py
deleted file mode 100644
index 43dafb262..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/templatetags/syntax_coloring.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from django import template
-from django.utils.encoding import smart_unicode, smart_str
-from django.utils.html import conditional_escape
-from django.utils.safestring import mark_safe
-
-register = template.Library()
-
-try:
- from pygments import highlight
- from pygments.lexers import get_lexer_by_name
- from pygments.formatters import HtmlFormatter
- colorize = True
-
-except:
- colorize = False
-
-@register.filter
-def syntaxhilight(value, arg="diff", autoescape=None):
- """
- Returns a syntax-hilighted version of Code; requires code/language arguments
- """
-
- if autoescape:
- value = conditional_escape(value)
- arg = conditional_escape(arg)
-
- if colorize:
- try:
- output = u'<style type="text/css">' \
- + smart_unicode(HtmlFormatter().get_style_defs('.highlight')) \
- + u'</style>'
-
- lexer = get_lexer_by_name(arg)
- output += highlight(value, lexer, HtmlFormatter())
- return mark_safe(output)
- except:
- return value
- else:
- return mark_safe(u'<div class="note-box">Tip: Install pygments for highlighting</div><pre>%s</pre>' % value)
-syntaxhilight.needs_autoescape = True
-
diff --git a/build/lib/Bcfg2/Server/Reports/reports/urls.py b/build/lib/Bcfg2/Server/Reports/reports/urls.py
deleted file mode 100644
index 9970d26a1..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/urls.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from django.conf.urls.defaults import *
-from django.core.urlresolvers import reverse, NoReverseMatch
-from django.http import HttpResponsePermanentRedirect
-from Bcfg2.Server.Reports.utils import filteredUrls, paginatedUrls, timeviewUrls
-
-def newRoot(request):
- try:
- grid_view = reverse('reports_grid_view')
- except NoReverseMatch:
- grid_view = '/grid'
- return HttpResponsePermanentRedirect(grid_view)
-
-urlpatterns = patterns('Bcfg2.Server.Reports.reports',
- (r'^$', newRoot),
-
- url(r'^manage/?$', 'views.client_manage', name='reports_client_manage'),
- url(r'^client/(?P<hostname>\S+)/(?P<pk>\d+)/?$', 'views.client_detail', name='reports_client_detail_pk'),
- url(r'^client/(?P<hostname>\S+)/?$', 'views.client_detail', name='reports_client_detail'),
- url(r'^elements/(?P<type>\w+)/(?P<pk>\d+)/?$', 'views.config_item', name='reports_item'),
-)
-
-urlpatterns += patterns('Bcfg2.Server.Reports.reports',
- *timeviewUrls(
- (r'^grid/?$', 'views.client_index', None, 'reports_grid_view'),
- (r'^summary/?$', 'views.display_summary', None, 'reports_summary'),
- (r'^timing/?$', 'views.display_timing', None, 'reports_timing'),
- (r'^elements/(?P<type>\w+)/?$', 'views.config_item_list', None, 'reports_item_list'),
-))
-
-urlpatterns += patterns('Bcfg2.Server.Reports.reports',
- *filteredUrls(*timeviewUrls(
- (r'^detailed/?$',
- 'views.client_detailed_list', None, 'reports_detailed_list')
-)))
-
-urlpatterns += patterns('Bcfg2.Server.Reports.reports',
- *paginatedUrls( *filteredUrls(
- (r'^history/?$',
- 'views.render_history_view', None, 'reports_history'),
- (r'^history/(?P<hostname>[\w\-\.]+)/?$',
- 'views.render_history_view', None, 'reports_client_history'),
-)))
-
- # Uncomment this for admin:
- #(r'^admin/', include('django.contrib.admin.urls')),
-
-
-## Uncomment this section if using authentication
-#urlpatterns += patterns('',
-# (r'^login/$', 'django.contrib.auth.views.login',
-# {'template_name': 'auth/login.html'}),
-# (r'^logout/$', 'django.contrib.auth.views.logout',
-# {'template_name': 'auth/logout.html'})
-# )
-
diff --git a/build/lib/Bcfg2/Server/Reports/reports/views.py b/build/lib/Bcfg2/Server/Reports/reports/views.py
deleted file mode 100644
index 00d35c092..000000000
--- a/build/lib/Bcfg2/Server/Reports/reports/views.py
+++ /dev/null
@@ -1,379 +0,0 @@
-"""
-Report views
-
-Functions to handle all of the reporting views.
-"""
-from django.template import Context, RequestContext, loader
-from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError, Http404
-from django.shortcuts import render_to_response, get_object_or_404
-from django.core.urlresolvers import resolve, reverse, Resolver404, NoReverseMatch
-from django.db import connection
-from django.db.backends import util
-
-from Bcfg2.Server.Reports.reports.models import *
-from datetime import datetime, timedelta
-from time import strptime
-import sys
-
-class PaginationError(Exception):
- """This error is raised when pagination cannot be completed."""
- pass
-
-def server_error(request):
- """
- 500 error handler.
-
- For now always return the debug response. Mailing isn't appropriate here.
-
- """
- from django.views import debug
- return debug.technical_500_response(request, *sys.exc_info())
-
-def timeview(fn):
- """
- Setup a timeview view
-
- Handles backend posts from the calendar and converts date pieces
- into a 'timestamp' parameter
-
- """
- def _handle_timeview(request, **kwargs):
- """Send any posts back."""
- if request.method == 'POST':
- cal_date = request.POST['cal_date']
- try:
- fmt = "%Y/%m/%d"
- if cal_date.find(' ') > -1:
- fmt += " %H:%M"
- timestamp = datetime(*strptime(cal_date, fmt)[0:6])
- view, args, kw = resolve(request.META['PATH_INFO'])
- kw['year'] = "%0.4d" % timestamp.year
- kw['month'] = "%02.d" % timestamp.month
- kw['day'] = "%02.d" % timestamp.day
- if cal_date.find(' ') > -1:
- kw['hour'] = timestamp.hour
- kw['minute'] = timestamp.minute
- return HttpResponseRedirect(reverse(view, args=args, kwargs=kw))
- except KeyError:
- pass
- except:
- pass
- # FIXME - Handle this
-
- """Extract timestamp from args."""
- timestamp = None
- try:
- timestamp = datetime(int(kwargs.pop('year')), int(kwargs.pop('month')),
- int(kwargs.pop('day')), int(kwargs.pop('hour', 0)),
- int(kwargs.pop('minute', 0)), 0)
- kwargs['timestamp'] = timestamp
- except KeyError:
- pass
- except:
- raise
- return fn(request, **kwargs)
-
- return _handle_timeview
-
-def config_item(request, pk, type="bad"):
- """
- Display a single entry.
-
- Dispalys information about a single entry.
-
- """
- item = get_object_or_404(Entries_interactions, id=pk)
- timestamp=item.interaction.timestamp
- time_start=item.interaction.timestamp.replace(\
- hour=0, minute=0, second=0, microsecond=0)
- time_end=time_start + timedelta(days=1)
-
- todays_data = Interaction.objects.filter(\
- timestamp__gte=time_start,\
- timestamp__lt=time_end)
- shared_entries = Entries_interactions.objects.filter(entry=item.entry,\
- reason=item.reason, type=item.type,
- interaction__in=[x['id']\
- for x in todays_data.values('id')])
-
- associated_list = Interaction.objects.filter(id__in=[x['interaction']\
- for x in shared_entries.values('interaction')])\
- .order_by('client__name','timestamp').select_related().all()
-
- return render_to_response('config_items/item.html',
- {'item':item,
- 'isextra': item.type == TYPE_EXTRA,
- 'mod_or_bad': type,
- 'associated_list':associated_list,
- 'timestamp' : timestamp},
- context_instance=RequestContext(request))
-
-@timeview
-def config_item_list(request, type, timestamp=None):
- """Render a listing of affected elements"""
- mod_or_bad = type.lower()
- type = convert_entry_type_to_id(type)
- if type < 0:
- raise Http404
-
- current_clients = Interaction.objects.get_interaction_per_client_ids(timestamp)
- item_list_dict = {}
- seen = dict()
- for x in Entries_interactions.objects.filter(interaction__in=current_clients, type=type).select_related():
- if (x.entry, x.reason) in seen:
- continue
- seen[(x.entry, x.reason)] = 1
- if item_list_dict.get(x.entry.kind, None):
- item_list_dict[x.entry.kind].append(x)
- else:
- item_list_dict[x.entry.kind] = [x]
-
- for kind in item_list_dict:
- item_list_dict[kind].sort(lambda a,b: cmp(a.entry.name, b.entry.name))
-
- return render_to_response('config_items/listing.html', {'item_list_dict':item_list_dict,
- 'mod_or_bad':mod_or_bad,
- 'timestamp' : timestamp},
- context_instance=RequestContext(request))
-
-@timeview
-def client_index(request, timestamp=None):
- """
- Render a grid view of active clients.
-
- Keyword parameters:
- timestamp -- datetime objectto render from
-
- """
- list = Interaction.objects.interaction_per_client(timestamp).select_related()\
- .order_by("client__name").all()
-
- return render_to_response('clients/index.html',
- { 'inter_list': list, 'timestamp' : timestamp},
- context_instance=RequestContext(request))
-
-@timeview
-def client_detailed_list(request, timestamp=None, **kwargs):
- """
- Provides a more detailed list view of the clients. Allows for extra
- filters to be passed in.
-
- """
-
- kwargs['interaction_base'] = Interaction.objects.interaction_per_client(timestamp).select_related()
- kwargs['orderby'] = "client__name"
- kwargs['page_limit'] = 0
- return render_history_view(request, 'clients/detailed-list.html', **kwargs)
-
-def client_detail(request, hostname = None, pk = None):
- context = dict()
- client = get_object_or_404(Client, name=hostname)
- if(pk == None):
- context['interaction'] = client.current_interaction
- return render_history_view(request, 'clients/detail.html', page_limit=5,
- client=client, context=context)
- else:
- context['interaction'] = client.interactions.get(pk=pk)
- return render_history_view(request, 'clients/detail.html', page_limit=5,
- client=client, maxdate=context['interaction'].timestamp, context=context)
-
-def client_manage(request):
- """Manage client expiration"""
- message = ''
- if request.method == 'POST':
- try:
- client_name = request.POST.get('client_name', None)
- client_action = request.POST.get('client_action', None)
- client = Client.objects.get(name=client_name)
- if client_action == 'expire':
- client.expiration = datetime.now();
- client.save()
- message = "Expiration for %s set to %s." % \
- (client_name, client.expiration.strftime("%Y-%m-%d %H:%M:%S"))
- elif client_action == 'unexpire':
- client.expiration = None;
- client.save()
- message = "%s is now active." % client_name
- else:
- message = "Missing action"
- except Client.DoesNotExist:
- if not client_name:
- client_name = "<none>"
- message = "Couldn't find client \"%s\"" % client_name
-
- return render_to_response('clients/manage.html',
- {'clients': Client.objects.order_by('name').all(), 'message': message},
- context_instance=RequestContext(request))
-
-@timeview
-def display_summary(request, timestamp=None):
- """
- Display a summary of the bcfg2 world
- """
- query = Interaction.objects.interaction_per_client(timestamp).select_related()
- node_count = query.count()
- recent_data = query.all()
- if not timestamp:
- timestamp = datetime.now()
-
- collected_data = dict(clean=[],bad=[],modified=[],extra=[],stale=[],pings=[])
- for node in recent_data:
- if timestamp - node.timestamp > timedelta(hours=24):
- collected_data['stale'].append(node)
- # If stale check for uptime
- try:
- if node.client.pings.latest().status == 'N':
- collected_data['pings'].append(node)
- except Ping.DoesNotExist:
- collected_data['pings'].append(node)
- continue
- if node.bad_entry_count() > 0:
- collected_data['bad'].append(node)
- else:
- collected_data['clean'].append(node)
- if node.modified_entry_count() > 0:
- collected_data['modified'].append(node)
- if node.extra_entry_count() > 0:
- collected_data['extra'].append(node)
-
- # label, header_text, node_list
- summary_data = []
- get_dict = lambda name, label: { 'name': name,
- 'nodes': collected_data[name],
- 'label': label }
- if len(collected_data['clean']) > 0:
- summary_data.append( get_dict('clean', 'nodes are clean.') )
- if len(collected_data['bad']) > 0:
- summary_data.append( get_dict('bad', 'nodes are bad.') )
- if len(collected_data['modified']) > 0:
- summary_data.append( get_dict('modified', 'nodes were modified.') )
- if len(collected_data['extra']) > 0:
- summary_data.append( get_dict('extra',
- 'nodes have extra configurations.') )
- if len(collected_data['stale']) > 0:
- summary_data.append( get_dict('stale',
- 'nodes did not run within the last 24 hours.') )
- if len(collected_data['pings']) > 0:
- summary_data.append( get_dict('pings',
- 'are down.') )
-
- return render_to_response('displays/summary.html',
- {'summary_data': summary_data, 'node_count': node_count,
- 'timestamp': timestamp},
- context_instance=RequestContext(request))
-
-@timeview
-def display_timing(request, timestamp=None):
- mdict = dict()
- inters = Interaction.objects.interaction_per_client(timestamp).select_related().all()
- [mdict.__setitem__(inter, {'name': inter.client.name}) \
- for inter in inters]
- for metric in Performance.objects.filter(interaction__in=mdict.keys()).all():
- for i in metric.interaction.all():
- mdict[i][metric.metric] = metric.value
- return render_to_response('displays/timing.html',
- {'metrics': mdict.values(), 'timestamp': timestamp},
- context_instance=RequestContext(request))
-
-
-def render_history_view(request, template='clients/history.html', **kwargs):
- """
- Provides a detailed history of a clients interactions.
-
- Renders a detailed history of a clients interactions. Allows for various
- filters and settings. Automatically sets pagination data into the context.
-
- Keyword arguments:
- interaction_base -- Interaction QuerySet to build on
- (default Interaction.objects)
- context -- Additional context data to render with
- page_number -- Page to display (default 1)
- page_limit -- Number of results per page, if 0 show all (default 25)
- client -- Client object to render
- hostname -- Client hostname to lookup and render. Returns a 404 if
- not found
- server -- Filter interactions by server
- state -- Filter interactions by state
- entry_max -- Most recent interaction to display
- orderby -- Sort results using this field
-
- """
-
- context = kwargs.get('context', dict())
- max_results = int(kwargs.get('page_limit', 25))
- page = int(kwargs.get('page_number', 1))
-
- client=kwargs.get('client', None)
- if not client and 'hostname' in kwargs:
- client = get_object_or_404(Client, name=kwargs['hostname'])
- if client:
- context['client'] = client
-
- entry_max = kwargs.get('maxdate', None)
- context['entry_max'] = entry_max
-
- # Either filter by client or limit by clients
- iquery = kwargs.get('interaction_base', Interaction.objects)
- if client:
- iquery = iquery.filter(client__exact=client).select_related()
-
- if 'orderby' in kwargs and kwargs['orderby']:
- iquery = iquery.order_by(kwargs['orderby'])
-
- if 'state' in kwargs and kwargs['state']:
- iquery = iquery.filter(state__exact=kwargs['state'])
- if 'server' in kwargs and kwargs['server']:
- iquery = iquery.filter(server__exact=kwargs['server'])
-
- if entry_max:
- iquery = iquery.filter(timestamp__lte=entry_max)
-
- if max_results < 0:
- max_results = 1
- entry_list = []
- if max_results > 0:
- try:
- rec_start, rec_end = prepare_paginated_list(request, context, iquery, page, max_results)
- except PaginationError, page_error:
- if isinstance(page_error[0], HttpResponse):
- return page_error[0]
- return HttpResponseServerError(page_error)
- context['entry_list'] = iquery.all()[rec_start:rec_end]
- else:
- context['entry_list'] = iquery.all()
-
- return render_to_response(template, context,
- context_instance=RequestContext(request))
-
-def prepare_paginated_list(request, context, paged_list, page=1, max_results=25):
- """
- Prepare context and slice an object for pagination.
- """
- if max_results < 1:
- raise PaginationError, "Max results less then 1"
- if paged_list == None:
- raise PaginationError, "Invalid object"
-
- try:
- nitems = paged_list.count()
- except TypeError:
- nitems = len(paged_list)
-
- rec_start = (page - 1) * int(max_results)
- try:
- total_pages = (nitems / int(max_results)) + 1
- except:
- total_pages = 1
- if page > total_pages:
- # If we passed beyond the end send back
- try:
- view, args, kwargs = resolve(request.META['PATH_INFO'])
- kwargs['page_number'] = total_pages
- raise PaginationError, HttpResponseRedirect( reverse(view, kwargs=kwargs) )
- except (Resolver404, NoReverseMatch, ValueError):
- raise "Accessing beyond last page. Unable to resolve redirect."
-
- context['total_pages'] = total_pages
- context['records_per_page'] = max_results
- return (rec_start, rec_start + int(max_results))
-
diff --git a/build/lib/Bcfg2/Server/Reports/settings.py b/build/lib/Bcfg2/Server/Reports/settings.py
deleted file mode 100644
index 9efe38552..000000000
--- a/build/lib/Bcfg2/Server/Reports/settings.py
+++ /dev/null
@@ -1,144 +0,0 @@
-import django
-
-# Django settings for bcfg2 reports project.
-from ConfigParser import ConfigParser, NoSectionError, NoOptionError
-c = ConfigParser()
-c.read(['/etc/bcfg2.conf', '/etc/bcfg2-web.conf'])
-
-try:
- dset = c.get('statistics', 'web_debug')
-except:
- dset = 'false'
-
-if dset == "True":
- DEBUG = True
-else:
- DEBUG = False
-
-TEMPLATE_DEBUG = DEBUG
-
-ADMINS = (
- ('Bcfg2', 'admin@email.address'),
-)
-
-MANAGERS = ADMINS
-
-DATABASE_ENGINE = c.get('statistics', 'database_engine')
-# 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
-if c.has_option('statistics', 'database_name'):
- DATABASE_NAME = c.get('statistics', 'database_name')
-else:
- DATABASE_NAME = ''
-# Or path to database file if using sqlite3.
-#<repository>/etc/brpt.sqlite is default path
-
-if DATABASE_ENGINE != 'sqlite3':
- DATABASE_USER = c.get('statistics', 'database_user')
- # Not used with sqlite3.
- DATABASE_PASSWORD = c.get('statistics', 'database_password')
- # Not used with sqlite3.
- DATABASE_HOST = c.get('statistics', 'database_host')
- # Set to empty string for localhost. Not used with sqlite3.
- DATABASE_PORT = c.get('statistics', 'database_port')
- # Set to empty string for default. Not used with sqlite3.
-if DATABASE_ENGINE == 'sqlite3' and DATABASE_NAME == '':
- DATABASE_NAME = "%s/etc/brpt.sqlite" % c.get('server', 'repository')
-
-# Local time zone for this installation. All choices can be found here:
-# http://docs.djangoproject.com/en/dev/ref/settings/#time-zone
-try:
- TIME_ZONE = c.get('statistics', 'time_zone')
-except:
- if django.VERSION[0] == 1 and django.VERSION[1] > 2:
- TIME_ZONE = None
-
-# Language code for this installation. All choices can be found here:
-# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
-# http://blogs.law.harvard.edu/tech/stories/storyReader$15
-LANGUAGE_CODE = 'en-us'
-
-SITE_ID = 1
-
-# Absolute path to the directory that holds media.
-# Example: "/home/media/media.lawrence.com/"
-MEDIA_ROOT = ''
-
-# URL that handles the media served from MEDIA_ROOT.
-# Example: "http://media.lawrence.com"
-MEDIA_URL = '/site_media'
-if c.has_option('statistics', 'web_prefix'):
- MEDIA_URL = c.get('statistics', 'web_prefix').rstrip('/') + MEDIA_URL
-
-# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
-# trailing slash.
-# Examples: "http://foo.com/media/", "/media/".
-ADMIN_MEDIA_PREFIX = '/media/'
-
-# Make this unique, and don't share it with anybody.
-SECRET_KEY = 'eb5+y%oy-qx*2+62vv=gtnnxg1yig_odu0se5$h0hh#pc*lmo7'
-
-# List of callables that know how to import templates from various sources.
-TEMPLATE_LOADERS = (
- 'django.template.loaders.filesystem.load_template_source',
- 'django.template.loaders.app_directories.load_template_source',
- 'django.template.loaders.eggs.load_template_source',
-)
-
-MIDDLEWARE_CLASSES = (
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.middleware.doc.XViewMiddleware',
-)
-
-ROOT_URLCONF = 'Bcfg2.Server.Reports.urls'
-
-# Authentication Settings
-# Use NIS authentication backend defined in backends.py
-AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
- 'Bcfg2.Server.Reports.backends.NISBackend')
-# The NIS group authorized to login to BCFG2's reportinvg system
-AUTHORIZED_GROUP = ''
-#create login url area:
-try:
- import django.contrib.auth
-except ImportError:
- print('Import of Django module failed. Is Django installed?')
-django.contrib.auth.LOGIN_URL = '/login'
-
-SESSION_EXPIRE_AT_BROWSER_CLOSE = True
-
-
-
-TEMPLATE_DIRS = (
- # Put strings here, like "/home/html/django_templates".
- # Always use forward slashes, even on Windows.
- '/usr/share/python-support/python-django/django/contrib/admin/templates/',
- 'Bcfg2.Server.Reports.reports'
-)
-
-if django.VERSION[0] == 1 and django.VERSION[1] < 2:
- TEMPLATE_CONTEXT_PROCESSORS = (
- 'django.core.context_processors.auth',
- 'django.core.context_processors.debug',
- 'django.core.context_processors.i18n',
- 'django.core.context_processors.media',
- 'django.core.context_processors.request'
- )
-else:
- TEMPLATE_CONTEXT_PROCESSORS = (
- 'django.contrib.auth.context_processors.auth',
- 'django.core.context_processors.debug',
- 'django.core.context_processors.i18n',
- 'django.core.context_processors.media',
- 'django.core.context_processors.request'
- )
-
-INSTALLED_APPS = (
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.sites',
- 'django.contrib.admin',
- 'Bcfg2.Server.Reports.reports'
-)
diff --git a/build/lib/Bcfg2/Server/Reports/updatefix.py b/build/lib/Bcfg2/Server/Reports/updatefix.py
deleted file mode 100644
index f8fca1f90..000000000
--- a/build/lib/Bcfg2/Server/Reports/updatefix.py
+++ /dev/null
@@ -1,184 +0,0 @@
-import Bcfg2.Server.Reports.settings
-
-from django.db import connection
-import django.core.management
-from Bcfg2.Server.Reports.reports.models import InternalDatabaseVersion, \
- TYPE_BAD, TYPE_MODIFIED, TYPE_EXTRA
-
-import logging, traceback
-logger = logging.getLogger('Bcfg2.Server.Reports.UpdateFix')
-
-# all update function should go here
-def _merge_database_table_entries():
- cursor = connection.cursor()
- insert_cursor = connection.cursor()
- find_cursor = connection.cursor()
- cursor.execute("""
- Select name, kind from reports_bad
- union
- select name, kind from reports_modified
- union
- select name, kind from reports_extra
- """)
- # this fetch could be better done
- entries_map={}
- for row in cursor.fetchall():
- insert_cursor.execute("insert into reports_entries (name, kind) \
- values (%s, %s)", (row[0], row[1]))
- entries_map[(row[0], row[1])] = insert_cursor.lastrowid
-
- cursor.execute("""
- Select name, kind, reason_id, interaction_id, 1 from reports_bad
- inner join reports_bad_interactions on reports_bad.id=reports_bad_interactions.bad_id
- union
- Select name, kind, reason_id, interaction_id, 2 from reports_modified
- inner join reports_modified_interactions on reports_modified.id=reports_modified_interactions.modified_id
- union
- Select name, kind, reason_id, interaction_id, 3 from reports_extra
- inner join reports_extra_interactions on reports_extra.id=reports_extra_interactions.extra_id
- """)
- for row in cursor.fetchall():
- key = (row[0], row[1])
- if entries_map.get(key, None):
- entry_id = entries_map[key]
- else:
- find_cursor.execute("Select id from reports_entries where name=%s and kind=%s", key)
- rowe = find_cursor.fetchone()
- entry_id = rowe[0]
- insert_cursor.execute("insert into reports_entries_interactions \
- (entry_id, interaction_id, reason_id, type) values (%s, %s, %s, %s)", (entry_id, row[3], row[2], row[4]))
-
-def _interactions_constraint_or_idx():
- '''sqlite doesn't support alter tables.. or constraints'''
- cursor = connection.cursor()
- try:
- cursor.execute('alter table reports_interaction add constraint reports_interaction_20100601 unique (client_id,timestamp)')
- except:
- cursor.execute('create unique index reports_interaction_20100601 on reports_interaction (client_id,timestamp)')
-
-
-def _populate_interaction_entry_counts():
- '''Populate up the type totals for the interaction table'''
- cursor = connection.cursor()
- count_field = { TYPE_BAD: 'bad_entries',
- TYPE_MODIFIED: 'modified_entries',
- TYPE_EXTRA: 'extra_entries' }
-
- for type in count_field.keys():
- cursor.execute("select count(type), interaction_id "+
- "from reports_entries_interactions where type = %s group by interaction_id" % type)
- updates = []
- for row in cursor.fetchall():
- updates.append(row)
- try:
- cursor.executemany("update reports_interaction set " + count_field[type] + "=%s where id = %s", updates)
- except Exception, e:
- print e
- cursor.close()
-
-
-# be sure to test your upgrade query before reflecting the change in the models
-# the list of function and sql command to do should go here
-_fixes = [_merge_database_table_entries,
- # this will remove unused tables
- "drop table reports_bad;",
- "drop table reports_bad_interactions;",
- "drop table reports_extra;",
- "drop table reports_extra_interactions;",
- "drop table reports_modified;",
- "drop table reports_modified_interactions;",
- "drop table reports_repository;",
- "drop table reports_metadata;",
- "alter table reports_interaction add server varchar(256) not null default 'N/A';",
- # fix revision data type to support $VCS hashes
- "alter table reports_interaction add repo_rev_code varchar(64) default '';",
- # Performance enhancements for large sites
- 'alter table reports_interaction add column bad_entries integer not null default -1;',
- 'alter table reports_interaction add column modified_entries integer not null default -1;',
- 'alter table reports_interaction add column extra_entries integer not null default -1;',
- _populate_interaction_entry_counts,
- _interactions_constraint_or_idx,
- 'alter table reports_reason add is_binary bool NOT NULL default False;',
-]
-
-# this will calculate the last possible version of the database
-lastversion = len(_fixes)
-
-def rollupdate(current_version):
- """ function responsible to coordinates all the updates
- need current_version as integer
- """
- ret = None
- if current_version < lastversion:
- for i in range(current_version, lastversion):
- try:
- if type(_fixes[i]) == str:
- connection.cursor().execute(_fixes[i])
- else:
- _fixes[i]()
- except:
- logger.error("Failed to perform db update %s" % (_fixes[i]), exc_info=1)
- # since array start at 0 but version start at 1 we add 1 to the normal count
- ret = InternalDatabaseVersion.objects.create(version=i+1)
- return ret
- else:
- return None
-
-def dosync():
- """Function to do the syncronisation for the models"""
- # try to detect if it's a fresh new database
- try:
- cursor = connection.cursor()
- # If this table goes missing then don't forget to change it to the new one
- cursor.execute("Select * from reports_client")
- # if we get here with no error then the database has existing tables
- fresh = False
- except:
- logger.debug("there was an error while detecting the freshness of the database")
- #we should get here if the database is new
- fresh = True
-
- # ensure database connection are close, so that the management can do it's job right
- try:
- cursor.close()
- connection.close()
- except:
- # ignore any errors from missing/invalid dbs
- pass
- # Do the syncdb according to the django version
- if "call_command" in dir(django.core.management):
- # this is available since django 1.0 alpha.
- # not yet tested for full functionnality
- django.core.management.call_command("syncdb", interactive=False, verbosity=0)
- if fresh:
- django.core.management.call_command("loaddata", 'initial_version.xml', verbosity=0)
- elif "syncdb" in dir(django.core.management):
- # this exist only for django 0.96.*
- django.core.management.syncdb(interactive=False, verbosity=0)
- if fresh:
- logger.debug("loading the initial_version fixtures")
- django.core.management.load_data(fixture_labels=['initial_version'], verbosity=0)
- else:
- logger.warning("Don't forget to run syncdb")
-
-
-def update_database():
- ''' methode to search where we are in the revision of the database models and update them '''
- try :
- logger.debug("Running upgrade of models to the new one")
- dosync()
- know_version = InternalDatabaseVersion.objects.order_by('-version')
- if not know_version:
- logger.debug("No version, creating initial version")
- know_version = InternalDatabaseVersion.objects.create(version=0)
- else:
- know_version = know_version[0]
- logger.debug("Presently at %s" % know_version)
- if know_version.version < lastversion:
- new_version = rollupdate(know_version.version)
- if new_version:
- logger.debug("upgraded to %s" % new_version)
- except:
- logger.error("Error while updating the database")
- for x in traceback.format_exc().splitlines():
- logger.error(x)
diff --git a/build/lib/Bcfg2/Server/Reports/urls.py b/build/lib/Bcfg2/Server/Reports/urls.py
deleted file mode 100644
index d7ff1eee5..000000000
--- a/build/lib/Bcfg2/Server/Reports/urls.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from django.conf.urls.defaults import *
-from django.http import HttpResponsePermanentRedirect
-
-handler500 = 'Bcfg2.Server.Reports.reports.views.server_error'
-
-urlpatterns = patterns('',
- (r'^', include('Bcfg2.Server.Reports.reports.urls'))
-)
-
-#urlpatterns += patterns("django.views",
-# url(r"media/(?P<path>.*)$", "static.serve", {
-# "document_root": '/Users/tlaszlo/svn/bcfg2/reports/site_media/',
-# })
-#)
diff --git a/build/lib/Bcfg2/Server/Reports/utils.py b/build/lib/Bcfg2/Server/Reports/utils.py
deleted file mode 100644
index b74f09e74..000000000
--- a/build/lib/Bcfg2/Server/Reports/utils.py
+++ /dev/null
@@ -1,116 +0,0 @@
-"""Helper functions for reports"""
-from Bcfg2.Server.Reports.reports.models import TYPE_CHOICES
-from django.conf.urls.defaults import *
-import re
-
-"""List of filters provided by filteredUrls"""
-filter_list = ('server', 'state')
-
-class BatchFetch(object):
- """Fetch Django objects in smaller batches to save memory"""
-
- def __init__(self, obj, step=10000):
- self.count = 0
- self.block_count = 0
- self.obj = obj
- self.data = None
- self.step = step
- self.max = obj.count()
-
- def __iter__(self):
- return self
-
- def next(self):
- """Return the next object from our array and fetch from the
- database when needed"""
- if self.block_count + self.count - self.step == self.max:
- raise StopIteration
- if self.block_count == 0 or self.count == self.step:
- # Without list() this turns into LIMIT 1 OFFSET x queries
- self.data = list(self.obj.all()[self.block_count: \
- (self.block_count + self.step)])
- self.block_count += self.step
- self.count = 0
- self.count += 1
- return self.data[self.count - 1]
-
-def generateUrls(fn):
- """
- Parse url tuples and send to functions.
-
- Decorator for url generators. Handles url tuple parsing
- before the actual function is called.
- """
- def url_gen(*urls):
- results = []
- for url_tuple in urls:
- if isinstance(url_tuple, (list, tuple)):
- results += fn(*url_tuple)
- else:
- raise ValueError("Unable to handle compiled urls")
- return results
- return url_gen
-
-@generateUrls
-def paginatedUrls(pattern, view, kwargs=None, name=None):
- """
- Takes a group of url tuples and adds paginated urls.
-
- Extends a url tuple to include paginated urls. Currently doesn't handle url() compiled
- patterns.
-
- """
- results = [(pattern, view, kwargs, name)]
- tail = ''
- mtail = re.search('(/+\+?\\*?\??\$?)$', pattern)
- if mtail:
- tail = mtail.group(1)
- pattern = pattern[:len(pattern) - len(tail)]
- results += [(pattern + "/(?P<page_number>\d+)" + tail, view, kwargs)]
- results += [(pattern + "/(?P<page_number>\d+)\|(?P<page_limit>\d+)" + tail, view, kwargs)]
- if not kwargs:
- kwargs = dict()
- kwargs['page_limit'] = 0
- results += [(pattern + "/?\|(?P<page_limit>all)" + tail, view, kwargs)]
- return results
-
-@generateUrls
-def filteredUrls(pattern, view, kwargs=None, name=None):
- """
- Takes a url and adds filtered urls.
-
- Extends a url tuple to include filtered view urls. Currently doesn't
- handle url() compiled patterns.
- """
- results = [(pattern, view, kwargs, name)]
- tail = ''
- mtail = re.search('(/+\+?\\*?\??\$?)$', pattern)
- if mtail:
- tail = mtail.group(1)
- pattern = pattern[:len(pattern) - len(tail)]
- for filter in ('/state/(?P<state>\w+)',
- '/server/(?P<server>[\w\-\.]+)',
- '/server/(?P<server>[\w\-\.]+)/(?P<state>[A-Za-z]+)'):
- results += [(pattern + filter + tail, view, kwargs)]
- return results
-
-@generateUrls
-def timeviewUrls(pattern, view, kwargs=None, name=None):
- """
- Takes a url and adds timeview urls
-
- Extends a url tuple to include filtered view urls. Currently doesn't
- handle url() compiled patterns.
- """
- results = [(pattern, view, kwargs, name)]
- tail = ''
- mtail = re.search('(/+\+?\\*?\??\$?)$', pattern)
- if mtail:
- tail = mtail.group(1)
- pattern = pattern[:len(pattern) - len(tail)]
- for filter in ('/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/' + \
- '(?P<hour>\d\d)-(?P<minute>\d\d)',
- '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'):
- results += [(pattern + filter + tail, view, kwargs)]
- return results
-
diff --git a/build/lib/Bcfg2/Server/Snapshots/__init__.py b/build/lib/Bcfg2/Server/Snapshots/__init__.py
deleted file mode 100644
index 6018377cb..000000000
--- a/build/lib/Bcfg2/Server/Snapshots/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-__all__ = ['models', 'db_from_config', 'setup_session']
-
-import sqlalchemy
-import sqlalchemy.orm
-import ConfigParser
-
-
-def db_from_config(cfile):
- cp = ConfigParser.ConfigParser()
- cp.read([cfile])
- driver = cp.get('snapshots', 'driver')
- if driver == 'sqlite':
- path = cp.get('snapshots', 'database')
- return 'sqlite:///%s' % path
- elif driver in ['mysql', 'postgres']:
- user = cp.get('snapshots', 'user')
- password = cp.get('snapshots', 'password')
- host = cp.get('snapshots', 'host')
- db = cp.get('snapshots', 'database')
- return '%s://%s:%s@%s/%s' % (driver, user, password, host, db)
- else:
- raise Exception, "unsupported db driver %s" % driver
-
-
-def setup_session(cfile, debug=False):
- engine = sqlalchemy.create_engine(db_from_config(cfile),
- echo=debug)
- Session = sqlalchemy.orm.sessionmaker()
- Session.configure(bind=engine)
- return Session()
diff --git a/build/lib/Bcfg2/Server/Snapshots/model.py b/build/lib/Bcfg2/Server/Snapshots/model.py
deleted file mode 100644
index cbb14be79..000000000
--- a/build/lib/Bcfg2/Server/Snapshots/model.py
+++ /dev/null
@@ -1,278 +0,0 @@
-from sqlalchemy import Table, Column, Integer, Unicode, ForeignKey, Boolean, \
- DateTime, UnicodeText, desc
-import datetime
-import sqlalchemy.exceptions
-from sqlalchemy.orm import relation, backref
-from sqlalchemy.ext.declarative import declarative_base
-
-
-class Uniquer(object):
- force_rt = True
-
- @classmethod
- def by_value(cls, session, **kwargs):
- if cls.force_rt:
- try:
- return session.query(cls).filter_by(**kwargs).one()
- except sqlalchemy.exceptions.InvalidRequestError:
- return cls(**kwargs)
- else:
- return cls(**kwargs)
-
- @classmethod
- def from_record(cls, session, data):
- return cls.by_value(session, **data)
-
-Base = declarative_base()
-
-
-class Administrator(Uniquer, Base):
- __tablename__ = 'administrator'
- id = Column(Integer, primary_key=True)
- name = Column(Unicode(20), unique=True)
- email = Column(Unicode(64))
-
-admin_client = Table('admin_client', Base.metadata,
- Column('admin_id', Integer, ForeignKey('administrator.id')),
- Column('client_id', Integer, ForeignKey('client.id')))
-
-admin_group = Table('admin_group', Base.metadata,
- Column('admin_id', Integer, ForeignKey('administrator.id')),
- Column('group_id', Integer, ForeignKey('group.id')))
-
-
-class Client(Uniquer, Base):
- __tablename__ = 'client'
- id = Column(Integer, primary_key=True)
- name = Column(Unicode(64), unique=True)
- admins = relation("Administrator", secondary=admin_client,
- backref='clients')
- active = Column(Boolean, default=True)
- online = Column(Boolean, default=True)
- online_ts = Column(DateTime)
-
-
-class Group(Uniquer, Base):
- __tablename__ = 'group'
- id = Column(Integer, primary_key=True)
- name = Column(Unicode(32), unique=True)
- admins = relation("Administrator", secondary=admin_group,
- backref='groups')
-
-
-class ConnectorKeyVal(Uniquer, Base):
- __tablename__ = 'connkeyval'
- id = Column(Integer, primary_key=True)
- connector = Column(Unicode(16))
- key = Column(Unicode(32))
- value = Column(UnicodeText)
-
-meta_group = Table('meta_group', Base.metadata,
- Column('metadata_id', Integer, ForeignKey('metadata.id')),
- Column('group_id', Integer, ForeignKey('group.id')))
-
-meta_conn = Table('meta_conn', Base.metadata,
- Column('metadata_id', Integer, ForeignKey('metadata.id')),
- Column('connkeyval_id', Integer, ForeignKey('connkeyval.id')))
-
-
-class Metadata(Base):
- __tablename__ = 'metadata'
- id = Column(Integer, primary_key=True)
- client_id = Column(Integer, ForeignKey('client.id'))
- client = relation(Client)
- groups = relation("Group", secondary=meta_group)
- keyvals = relation(ConnectorKeyVal, secondary=meta_conn)
- timestamp = Column(DateTime)
-
- @classmethod
- def from_metadata(cls, mysession, mymetadata):
- client = Client.by_value(mysession, name=unicode(mymetadata.hostname))
- m = cls(client=client)
- for group in mymetadata.groups:
- m.groups.append(Group.by_value(mysession, name=unicode(group)))
- for connector in mymetadata.connectors:
- data = getattr(mymetadata, connector)
- if not isinstance(data, dict):
- continue
- for key, value in data.iteritems():
- if not isinstance(value, str):
- continue
- m.keyvals.append(ConnectorKeyVal.by_value(mysession,
- connector=unicode(connector),
- key=unicode(key),
- value=unicode(value)))
- return m
-
-
-class Package(Base, Uniquer):
- __tablename__ = 'package'
- id = Column(Integer, primary_key=True)
- name = Column(Unicode(24))
- type = Column(Unicode(16))
- version = Column(Unicode(16))
- verification_status = Column(Boolean)
-
-
-class CorrespondenceType(object):
- mtype = Package
-
- @classmethod
- def from_record(cls, mysession, record):
- (mod, corr, name, s_dict, e_dict) = record
- if not s_dict:
- start = None
- else:
- start = cls.mtype.by_value(mysession, name=name, **s_dict)
- if s_dict != e_dict:
- end = cls.mtype.by_value(mysession, name=name, **e_dict)
- else:
- end = start
- return cls(start=start, end=end, modified=mod, correct=corr)
-
-
-class PackageCorrespondence(Base, CorrespondenceType):
- mtype = Package
- __tablename__ = 'package_pair'
- id = Column(Integer, primary_key=True)
- start_id = Column(Integer, ForeignKey('package.id'))
- start = relation(Package, primaryjoin=start_id == Package.id)
- end_id = Column(Integer, ForeignKey('package.id'), nullable=True)
- end = relation(Package, primaryjoin=end_id == Package.id)
- modified = Column(Boolean)
- correct = Column(Boolean)
-
-package_snap = Table('package_snap', Base.metadata,
- Column('ppair_id', Integer, ForeignKey('package_pair.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-
-class Service(Base, Uniquer):
- __tablename__ = 'service'
- id = Column(Integer, primary_key=True)
- name = Column(Unicode(16))
- type = Column(Unicode(12))
- status = Column(Boolean)
-
-
-class ServiceCorrespondence(Base, CorrespondenceType):
- mtype = Service
- __tablename__ = 'service_pair'
- id = Column(Integer, primary_key=True)
- start_id = Column(Integer, ForeignKey('service.id'))
- start = relation(Service, primaryjoin=start_id == Service.id)
- end_id = Column(Integer, ForeignKey('service.id'), nullable=True)
- end = relation(Service, primaryjoin=end_id == Service.id)
- modified = Column(Boolean)
- correct = Column(Boolean)
-
-service_snap = Table('service_snap', Base.metadata,
- Column('spair_id', Integer, ForeignKey('service_pair.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-
-class File(Base, Uniquer):
- __tablename__ = 'file'
- id = Column(Integer, primary_key=True)
- name = Column(UnicodeText)
- type = Column(Unicode(12))
- owner = Column(Unicode(12))
- group = Column(Unicode(16))
- perms = Column(Integer(5))
- contents = Column(UnicodeText)
-
-
-class FileCorrespondence(Base, CorrespondenceType):
- mtype = File
- __tablename__ = 'file_pair'
- id = Column(Integer, primary_key=True)
- start_id = Column(Integer, ForeignKey('file.id'))
- start = relation(File, primaryjoin=start_id == File.id)
- end_id = Column(Integer, ForeignKey('file.id'), nullable=True)
- end = relation(File, primaryjoin=end_id == File.id)
- modified = Column(Boolean)
- correct = Column(Boolean)
-
-file_snap = Table('file_snap', Base.metadata,
- Column('fpair_id', Integer, ForeignKey('file_pair.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-extra_pkg_snap = Table('extra_pkg_snap', Base.metadata,
- Column('package_id', Integer, ForeignKey('package.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-extra_file_snap = Table('extra_file_snap', Base.metadata,
- Column('file_id', Integer, ForeignKey('file.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-extra_service_snap = Table('extra_service_snap', Base.metadata,
- Column('service_id', Integer, ForeignKey('service.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-
-class Action(Base):
- __tablename__ = 'action'
- id = Column(Integer, primary_key=True)
- command = Column(UnicodeText)
- return_code = Column(Integer)
- output = Column(UnicodeText)
-
-action_snap = Table('action_snap', Base.metadata,
- Column('action_id', Integer, ForeignKey('action.id')),
- Column('snapshot_id', Integer, ForeignKey('snapshot.id')))
-
-
-class Snapshot(Base):
- __tablename__ = 'snapshot'
- id = Column(Integer, primary_key=True)
- correct = Column(Boolean)
- revision = Column(Unicode(36))
- metadata_id = Column(Integer, ForeignKey('metadata.id'))
- client_metadata = relation(Metadata, primaryjoin=metadata_id==Metadata.id)
- timestamp = Column(DateTime, default=datetime.datetime.now)
- client_id = Column(Integer, ForeignKey('client.id'))
- client = relation(Client, backref=backref('snapshots'))
- packages = relation(PackageCorrespondence, secondary=package_snap)
- services = relation(ServiceCorrespondence, secondary=service_snap)
- files = relation(FileCorrespondence, secondary=file_snap)
- actions = relation(Action, secondary=action_snap)
- extra_packages = relation(Package, secondary=extra_pkg_snap)
- extra_services = relation(Service, secondary=extra_service_snap)
- extra_files = relation(File, secondary=extra_file_snap)
-
- c_dispatch = dict([('Package', ('packages', PackageCorrespondence)),
- ('Service', ('services', ServiceCorrespondence)),
- ('Path', ('files', FileCorrespondence))])
- e_dispatch = dict([('Package', ('extra_packages', Package)),
- ('Service', ('extra_services', Service)),
- ('Path', ('extra_files', File))])
-
- @classmethod
- def from_data(cls, session, correct, revision, metadata, entries, extra):
- dbm = Metadata.from_metadata(session, metadata)
- snap = cls(correct=correct, client_metadata=dbm, revision=revision,
- timestamp=datetime.datetime.now(), client=dbm.client)
- for (dispatch, data) in [(cls.c_dispatch, entries),
- (cls.e_dispatch, extra)]:
- for key in dispatch:
- dest, ecls = dispatch[key]
- for edata in data[key].values():
- getattr(snap, dest).append(ecls.from_record(session, edata))
- return snap
-
- @classmethod
- def by_client(cls, session, clientname):
- return session.query(cls).join(cls.client_metadata, Metadata.client).filter(Client.name==clientname)
-
- @classmethod
- def get_current(cls, session, clientname):
- return session.query(Snapshot).join(Snapshot.client_metadata, Metadata.client).filter(Client.name==clientname).order_by(desc(Snapshot.timestamp)).first()
-
- @classmethod
- def get_by_date(cls, session, clientname, timestamp):
- return session.query(Snapshot)\
- .join(Snapshot.client_metadata, Metadata.client)\
- .filter(Snapshot.timestamp < timestamp)\
- .filter(Client.name==clientname)\
- .order_by(desc(Snapshot.timestamp))\
- .first()
diff --git a/build/lib/Bcfg2/Server/__init__.py b/build/lib/Bcfg2/Server/__init__.py
deleted file mode 100644
index 25f397565..000000000
--- a/build/lib/Bcfg2/Server/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# $Id$
-"""This is the set of modules for Bcfg2.Server."""
-
-__revision__ = '$Revision$'
-__all__ = ["Admin", "Core", "FileMonitor", "Plugin", "Plugins",
- "Hostbase", "Reports", "Snapshots"]
diff --git a/build/lib/Bcfg2/Statistics.py b/build/lib/Bcfg2/Statistics.py
deleted file mode 100644
index b2240db98..000000000
--- a/build/lib/Bcfg2/Statistics.py
+++ /dev/null
@@ -1,32 +0,0 @@
-
-class Statistic(object):
- def __init__(self, name, initial_value):
- self.name = name
- self.min = float(initial_value)
- self.max = float(initial_value)
- self.ave = float(initial_value)
- self.count = 1
-
- def add_value(self, value):
- if value < self.min:
- self.min = value
- if value > self.max:
- self.max = value
- self.count += 1
- self.ave = (((self.ave * (self.count - 1)) + value) / self.count)
-
- def get_value(self):
- return (self.name, (self.min, self.max, self.ave, self.count))
-
-class Statistics(object):
- def __init__(self):
- self.data = dict()
-
- def add_value(self, name, value):
- if name not in self.data:
- self.data[name] = Statistic(name, value)
- else:
- self.data[name].add_value(value)
-
- def display(self):
- return dict([value.get_value() for value in self.data.values()])
diff --git a/build/lib/Bcfg2/__init__.py b/build/lib/Bcfg2/__init__.py
deleted file mode 100644
index d36c0a00a..000000000
--- a/build/lib/Bcfg2/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""Base modules definition."""
-__revision__ = '$Revision$'
-
-__all__ = ['Server', 'Client', 'Component', 'Logger', 'Options', 'Proxy', 'Statistics']
diff --git a/build/scripts-2.7/bcfg2 b/build/scripts-2.7/bcfg2
deleted file mode 100755
index 9f56481bf..000000000
--- a/build/scripts-2.7/bcfg2
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/usr/bin/python
-
-"""Bcfg2 Client"""
-__revision__ = '$Revision$'
-
-import logging
-import os
-import signal
-import sys
-import tempfile
-import time
-import xmlrpclib
-import fcntl
-import Bcfg2.Options
-import Bcfg2.Client.XML
-import Bcfg2.Client.Frame
-import Bcfg2.Client.Tools
-
-import Bcfg2.Proxy
-import Bcfg2.Logger
-
-logger = logging.getLogger('bcfg2')
-
-def cb_sigint_handler(signum, frame):
- """Exit upon CTRL-C."""
- os._exit(1)
-
-DECISION_LIST = Bcfg2.Options.Option('Decision List', default=False,
- cmd="--decision-list", odesc='<file>',
- long_arg=True)
-
-
-class Client:
- """The main bcfg2 client class"""
-
- def __init__(self):
- self.toolset = None
- self.config = None
-
- optinfo = {
- # 'optname': (('-a', argdesc, optdesc),
- # env, cfpath, default, boolean)),
- 'verbose': Bcfg2.Options.VERBOSE,
- 'extra': Bcfg2.Options.CLIENT_EXTRA_DISPLAY,
- 'quick': Bcfg2.Options.CLIENT_QUICK,
- 'debug': Bcfg2.Options.DEBUG,
- 'lockfile': Bcfg2.Options.LOCKFILE,
- 'drivers': Bcfg2.Options.CLIENT_DRIVERS,
- 'dryrun': Bcfg2.Options.CLIENT_DRYRUN,
- 'paranoid': Bcfg2.Options.CLIENT_PARANOID,
- 'bundle': Bcfg2.Options.CLIENT_BUNDLE,
- 'bundle-quick': Bcfg2.Options.CLIENT_BUNDLEQUICK,
- 'indep': Bcfg2.Options.CLIENT_INDEP,
- 'file': Bcfg2.Options.CLIENT_FILE,
- 'interactive': Bcfg2.Options.INTERACTIVE,
- 'cache': Bcfg2.Options.CLIENT_CACHE,
- 'profile': Bcfg2.Options.CLIENT_PROFILE,
- 'remove': Bcfg2.Options.CLIENT_REMOVE,
- 'help': Bcfg2.Options.HELP,
- 'setup': Bcfg2.Options.CFILE,
- 'server': Bcfg2.Options.SERVER_LOCATION,
- 'user': Bcfg2.Options.CLIENT_USER,
- 'password': Bcfg2.Options.SERVER_PASSWORD,
- 'retries': Bcfg2.Options.CLIENT_RETRIES,
- 'kevlar': Bcfg2.Options.CLIENT_KEVLAR,
- 'decision-list': DECISION_LIST,
- 'encoding': Bcfg2.Options.ENCODING,
- 'omit-lock-check': Bcfg2.Options.OMIT_LOCK_CHECK,
- 'filelog': Bcfg2.Options.LOGGING_FILE_PATH,
- 'decision': Bcfg2.Options.CLIENT_DLIST,
- 'servicemode': Bcfg2.Options.CLIENT_SERVICE_MODE,
- 'key': Bcfg2.Options.CLIENT_KEY,
- 'certificate': Bcfg2.Options.CLIENT_CERT,
- 'ca': Bcfg2.Options.CLIENT_CA,
- 'serverCN': Bcfg2.Options.CLIENT_SCNS,
- }
-
- self.setup = Bcfg2.Options.OptionParser(optinfo)
- self.setup.parse(sys.argv[1:])
-
- if self.setup['args']:
- print("Bcfg2 takes no arguments, only options")
- print(self.setup.buildHelpMessage())
- raise SystemExit(1)
- level = 30
- if self.setup['verbose']:
- level = 20
- if self.setup['debug']:
- level = 0
- Bcfg2.Logger.setup_logging('bcfg2',
- to_syslog=False,
- level=level,
- to_file=self.setup['filelog'])
- self.logger = logging.getLogger('bcfg2')
- self.logger.debug(self.setup)
- if self.setup['bundle-quick']:
- if self.setup['bundle'] == []:
- self.logger.error("-Q option requires -b")
- raise SystemExit(1)
- elif self.setup['remove'] != False:
- self.logger.error("-Q option incompatible with -r")
- raise SystemExit(1)
- if 'drivers' in self.setup and self.setup['drivers'] == 'help':
- self.logger.info("The following drivers are available:")
- self.logger.info(Bcfg2.Client.Tools.drivers)
- raise SystemExit(0)
- if self.setup['remove'] and 'services' in self.setup['remove']:
- self.logger.error("Service removal is nonsensical, disable services to get former behavior")
- if self.setup['remove'] not in [False, 'all', 'services', 'packages']:
- self.logger.error("Got unknown argument %s for -r" % (self.setup['remove']))
- if (self.setup["file"] != False) and (self.setup["cache"] != False):
- print("cannot use -f and -c together")
- raise SystemExit(1)
-
- def run_probe(self, probe):
- """Execute probe."""
- name = probe.get('name')
- self.logger.info("Running probe %s" % name)
- ret = Bcfg2.Client.XML.Element("probe-data",
- name=name,
- source=probe.get('source'))
- try:
- scripthandle, scriptname = tempfile.mkstemp()
- script = open(scriptname, 'w+')
- try:
- script.write("#!%s\n" %
- (probe.attrib.get('interpreter', '/bin/sh')))
- script.write(probe.text)
- script.close()
- os.close(scripthandle)
- os.chmod(script.name, 0755)
- ret.text = os.popen(script.name).read().strip()
- self.logger.info("Probe %s has result:\n%s" % (name, ret.text))
- finally:
- os.unlink(script.name)
- except:
- self.logger.error("Failed to execute probe: %s" % (name), exc_info=1)
- raise SystemExit(1)
- return ret
-
- def fatal_error(self, message):
- """Signal a fatal error."""
- self.logger.error("Fatal error: %s" % (message))
- os._exit(1)
-
- def run(self):
- """Perform client execution phase."""
- times = {}
-
- # begin configuration
- times['start'] = time.time()
-
- if self.setup['file']:
- # read config from file
- try:
- self.logger.debug("Reading cached configuration from %s" %
- (self.setup['file']))
- configfile = open(self.setup['file'], 'r')
- rawconfig = configfile.read()
- configfile.close()
- except IOError:
- self.fatal_error("Failed to read cached configuration from: %s"
- % (self.setup['file']))
- return(1)
- else:
- # retrieve config from server
- proxy = Bcfg2.Proxy.ComponentProxy(self.setup['server'],
- self.setup['user'],
- self.setup['password'],
- key = self.setup['key'],
- cert = self.setup['certificate'],
- ca = self.setup['ca'],
- allowedServerCNs = self.setup['serverCN'])
-
- if self.setup['profile']:
- try:
- proxy.AssertProfile(self.setup['profile'])
- except xmlrpclib.Fault:
- self.fatal_error("Failed to set client profile")
- return(1)
-
- try:
- probe_data = proxy.GetProbes()
- except xmlrpclib.Fault, flt:
- self.logger.error("Failed to download probes from bcfg2")
- self.logger.error(flt.faultString)
- raise SystemExit(1)
-
- times['probe_download'] = time.time()
-
- try:
- probes = Bcfg2.Client.XML.XML(probe_data)
- except Bcfg2.Client.XML.ParseError, syntax_error:
- self.fatal_error(
- "Server returned invalid probe requests: %s" %
- (syntax_error))
- return(1)
-
- # execute probes
- try:
- probedata = Bcfg2.Client.XML.Element("ProbeData")
- [probedata.append(self.run_probe(probe))
- for probe in probes.findall(".//probe")]
- except:
- self.logger.error("Failed to execute probes")
- raise SystemExit(1)
-
- if len(probes.findall(".//probe")) > 0:
- try:
- # upload probe responses
- proxy.RecvProbeData(Bcfg2.Client.XML.tostring(probedata, encoding='UTF-8', xml_declaration=True))
- except:
- self.logger.error("Failed to upload probe data", exc_info=1)
- raise SystemExit(1)
-
- times['probe_upload'] = time.time()
-
- if self.setup['decision'] in ['whitelist', 'blacklist']:
- try:
- self.setup['decision_list'] = proxy.GetDecisionList( \
- self.setup['decision'])
- self.logger.info("Got decision list from server:")
- self.logger.info(self.setup['decision_list'])
- except xmlrpclib.Fault, f:
- if f.faultCode == 1:
- print("GetDecisionList method not supported by server")
- else:
- self.logger.error("Failed to de", exc_info=1)
- raise SystemExit(1)
-
- try:
- rawconfig = proxy.GetConfig()
- except xmlrpclib.Fault:
- self.logger.error("Failed to download configuration from Bcfg2")
- raise SystemExit(2)
-
- times['config_download'] = time.time()
-
- if self.setup['cache']:
- try:
- open(self.setup['cache'], 'w').write(rawconfig.encode(self.setup['encoding']))
- os.chmod(self.setup['cache'], 33152)
- except IOError:
- self.logger.warning("Failed to write config cache file %s" %
- (self.setup['cache']))
- times['caching'] = time.time()
-
- try:
- self.config = Bcfg2.Client.XML.XML(rawconfig)
- except Bcfg2.Client.XML.ParseError, syntax_error:
- self.fatal_error("The configuration could not be parsed: %s" %
- (syntax_error))
- return(1)
-
- times['config_parse'] = time.time()
-
- if self.config.tag == 'error':
- self.fatal_error("Server error: %s" % (self.config.text))
- return(1)
-
- if self.setup['bundle-quick']:
- newconfig = Bcfg2.Client.XML.XML('<Configuration/>')
- [newconfig.append(bundle) for bundle in self.config.getchildren() if \
- bundle.tag == 'Bundle' and bundle.get('name') in self.setup['bundle']]
- self.config = newconfig
-
- self.tools = Bcfg2.Client.Frame.Frame(self.config,
- self.setup,
- times, self.setup['drivers'],
- self.setup['dryrun'])
-
- if not self.setup['omit-lock-check']:
- #check lock here
- try:
- lockfile = open(self.setup['lockfile'], 'w')
- try:
- fcntl.lockf(lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- #otherwise exit and give a warning to the user
- self.fatal_error("An other instance of Bcfg2 is running. If you what to bypass the check, run with %s option" %
- (Bcfg2.Options.OMIT_LOCK_CHECK.cmd))
- except:
- lockfile = None
- self.logger.error("Failed to open lockfile")
- # execute the said configuration
- self.tools.Execute()
-
- if not self.setup['omit-lock-check']:
- #unlock here
- if lockfile:
- try:
- fcntl.lockf(lockfile.fileno(), fcntl.LOCK_UN)
- os.remove(self.setup['lockfile'])
- except OSError:
- self.logger.error("Failed to unlock lockfile %s" % lockfile.name)
-
- if not self.setup['file'] and not self.setup['bundle-quick']:
- # upload statistics
- feedback = self.tools.GenerateStats()
-
- try:
- proxy.RecvStats(Bcfg2.Client.XML.tostring(feedback,
- encoding='UTF-8',
- xml_declaration=True))
- except xmlrpclib.Fault:
- self.logger.error("Failed to upload configuration statistics")
- raise SystemExit(2)
-
-if __name__ == '__main__':
- signal.signal(signal.SIGINT, cb_sigint_handler)
- client = Client()
- spid = os.getpid()
- client.run()
diff --git a/build/scripts-2.7/bcfg2-admin b/build/scripts-2.7/bcfg2-admin
deleted file mode 100755
index 4d5ab2e5b..000000000
--- a/build/scripts-2.7/bcfg2-admin
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/python
-"""bcfg2-admin is a script that helps to administrate a Bcfg2 deployment."""
-
-from optparse import OptionParser
-from StringIO import StringIO
-import logging
-import Bcfg2.Server.Core
-import Bcfg2.Logger
-import Bcfg2.Options
-
-log = logging.getLogger('bcfg2-admin')
-
-import Bcfg2.Server.Admin
-
-def mode_import(modename):
- """Load Bcfg2.Server.Admin.<mode>."""
- modname = modename.capitalize()
- mod = getattr(__import__("Bcfg2.Server.Admin.%s" %
- (modname)).Server.Admin, modname)
- return getattr(mod, modname)
-
-def get_modes():
- """Get all available modes, except for the base mode."""
- return [x.lower() for x in Bcfg2.Server.Admin.__all__ if x != 'mode']
-
-def create_description():
- """Create the description string from the list of modes."""
- modes = get_modes()
- description = StringIO()
- description.write("Available modes are:\n\n")
- for mode in modes:
- try:
- description.write((" %-15s %s\n" %
- (mode, mode_import(mode).__shorthelp__)))
- except ImportError:
- continue
- return description.getvalue()
-
-def main():
- Bcfg2.Logger.setup_logging('bcfg2-admin', to_console=True, level=40)
- usage = "Usage: %prog [options] MODE [args]"
- parser = OptionParser(usage=usage)
- parser.set_defaults(configfile=Bcfg2.Options.CFILE.default)
- parser.add_option("-C", "--configfile",
- dest="configfile",
- help="Path to bcfg2.conf",
- metavar="FILE")
- parser.disable_interspersed_args()
- (options, args) = parser.parse_args()
-
- # Provide help if requested or no args were specified
- if len(args) < 1 or args[0] == 'help':
- if len(args) > 1:
- # Get help for a specific mode by passing it the help argument
- args = [args[1], args[0]]
- else:
- # Print short help for all modes
- parser.print_help()
- print create_description()
- raise SystemExit(0)
-
- if args[0] in get_modes():
- modname = args[0].capitalize()
- try:
- mode_cls = mode_import(modname)
- except ImportError, e:
- log.error("Failed to load admin mode %s: %s" % (modname, e))
- raise SystemExit(1)
- mode = mode_cls(options.configfile)
- mode(args[1:])
- if hasattr(mode, 'bcore'):
- mode.bcore.shutdown()
- else:
- log.error("Unknown mode %s" % args[0])
- parser.print_help()
- print create_description()
- raise SystemExit(1)
-
-if __name__ == '__main__':
- main()
diff --git a/build/scripts-2.7/bcfg2-build-reports b/build/scripts-2.7/bcfg2-build-reports
deleted file mode 100755
index 575a1b7a4..000000000
--- a/build/scripts-2.7/bcfg2-build-reports
+++ /dev/null
@@ -1,319 +0,0 @@
-#!/usr/bin/python
-
-"""
-bcfg2-build-reports generates & distributes reports of statistic
-information for Bcfg2."""
-
-__revision__ = '$Revision$'
-
-import copy
-import getopt
-import re
-import os
-import socket
-import sys
-from time import asctime, strptime
-from ConfigParser import ConfigParser, NoSectionError, NoOptionError
-from lxml.etree import XML, XSLT, parse, Element, ElementTree, SubElement, tostring, XMLSyntaxError
-
-def generatereport(rspec, nrpt):
- """
- generatereport creates and returns an ElementTree representation
- of a report adhering to the XML spec for intermediate reports.
- """
- reportspec = copy.deepcopy(rspec)
- nodereprt = copy.deepcopy(nrpt)
-
- reportgood = reportspec.get("good", default = 'Y')
- reportmodified = reportspec.get("modified", default = 'Y')
- current_date = asctime()[:10]
-
- """Build regex of all the nodes we are reporting about."""
- pattern = re.compile( '|'.join([item.get("name") for item in reportspec.findall('Machine')]))
-
- for node in nodereprt.findall('Node'):
- if not (node.findall("Statistics") and pattern.match(node.get('name'))):
- # Don't know enough about node.
- nodereprt.remove(node)
- continue
-
- # Reduce to most recent Statistics entry.
- statisticslist = node.findall('Statistics')
- # This line actually sorts from most recent to oldest.
- statisticslist.sort(lambda y, x: cmp(strptime(x.get("time")), strptime(y.get("time"))))
- stats = statisticslist[0]
-
- [node.remove(item) for item in node.findall('Statistics')]
-
- # Add a good tag if node is good and we wnat to report such.
- if reportgood == 'Y' and stats.get('state') == 'clean':
- SubElement(stats,"Good")
-
- [stats.remove(item) for item in stats.findall("Bad") + stats.findall("Modified") if \
- item.getchildren() == []]
- [stats.remove(item) for item in stats.findall("Modified") if reportmodified == 'N']
-
- # Test for staleness -if stale add Stale tag.
- if stats.get("time").find(current_date) == -1:
- SubElement(stats,"Stale")
- node.append(stats)
- return nodereprt
-
-def mail(mailbody, confi):
- """mail mails a previously generated report."""
-
- try:
- mailer = confi.get('statistics', 'sendmailpath')
- except (NoSectionError, NoOptionError):
- mailer = "/usr/sbin/sendmail"
- # Open a pipe to the mail program and
- # write the data to the pipe.
- pipe = os.popen("%s -t" % mailer, 'w')
- pipe.write(mailbody)
- exitcode = pipe.close()
- if exitcode:
- print "Exit code: %s" % exitcode
-
-def rss(reportxml, delivery, report):
- """rss appends a new report to the specified rss file
- keeping the last 9 articles.
- """
- # Check and see if rss file exists.
- for destination in delivery.findall('Destination'):
- try:
- fil = open(destination.attrib['address'], 'r')
- olddoc = XML(fil.read())
-
- # Defines the number of recent articles to keep.
- items = olddoc.find("channel").findall("item")[0:9]
- fil.close()
- fil = open(destination.attrib['address'], 'w')
- except (IOError, XMLSyntaxError):
- fil = open(destination.attrib['address'], 'w')
- items = []
-
- rssdata = Element("rss")
- channel = SubElement(rssdata, "channel")
- rssdata.set("version", "2.0")
- chantitle = SubElement(channel, "title")
- chantitle.text = report.attrib['name']
- chanlink = SubElement(channel, "link")
-
- # This can later link to WWW report if one gets published
- # simultaneously?
- chanlink.text = "http://www.mcs.anl.gov/cobalt/bcfg2"
- chandesc = SubElement(channel, "description")
- chandesc.text = "Information regarding the 10 most recent bcfg2 runs."
-
- channel.append(XML(reportxml))
-
- if items != []:
- for item in items:
- channel.append(item)
-
- tree = tostring(rssdata, encoding='UTF-8', xml_declaration=True)
- fil.write(tree)
- fil.close()
-
-def www(reportxml, delivery):
- """www outputs report to."""
-
- # This can later link to WWW report if one gets published
- # simultaneously?
- for destination in delivery.findall('Destination'):
- fil = open(destination.attrib['address'], 'w')
-
- fil.write(reportxml)
- fil.close()
-
-def fileout(reportxml, delivery):
- """Outputs to plain text file."""
- for destination in delivery.findall('Destination'):
- fil = open(destination.attrib['address'], 'w')
-
- fil.write(reportxml)
- fil.close()
-
-def pretty_print(element, level=0):
- """Produce a pretty-printed text representation of element."""
- if element.text:
- fmt = "%s<%%s %%s>%%s</%%s>" % (level*" ")
- data = (element.tag, (" ".join(["%s='%s'" % keyval for keyval in element.attrib.iteritems()])),
- element.text, element.tag)
- if element._children:
- fmt = "%s<%%s %%s>\n" % (level*" ",) + (len(element._children) * "%s") + "%s</%%s>\n" % (level*" ")
- data = (element.tag, ) + (" ".join(["%s='%s'" % keyval for keyval in element.attrib.iteritems()]),)
- data += tuple([pretty_print(entry, level+2) for entry in element._children]) + (element.tag, )
- else:
- fmt = "%s<%%s %%s/>\n" % (level * " ")
- data = (element.tag, " ".join(["%s='%s'" % keyval for keyval in element.attrib.iteritems()]))
- return fmt % data
-
-
-if __name__ == '__main__':
- ping=True
- all=False
- if '-C' in sys.argv:
- cfpath = sys.argv[sys.argv.index('-C') + 1]
- else:
- cfpath = '/etc/bcfg2.conf'
- c = ConfigParser()
- c.read([cfpath])
- configpath = "%s/etc/report-configuration.xml" % c.get('server', 'repository')
- statpath = "%s/etc/statistics.xml" % c.get('server', 'repository')
- clientsdatapath = "%s/Metadata/clients.xml" % c.get('server', 'repository')
- try:
- prefix = c.get('server', 'prefix')
- except (NoSectionError, NoOptionError):
- prefix = '/usr'
-
- transformpath = "/%s/share/bcfg2/xsl-transforms/" % (prefix)
- #websrcspath = "/usr/share/bcfg2/web-rprt-srcs/"
-
- try:
- opts, args = getopt.getopt(sys.argv[1:], "C:hAc:Ns:", ["help", "all", "config=","no-ping", "stats="])
- except getopt.GetoptError, mesg:
- # Print help information and exit:
- print "%s\nUsage:\nbcfg2-build-reports [-h][-A (include ALL clients)] [-c <configuration-file>] [-s <statistics-file>][-N (do not ping clients)]" % (mesg)
- raise SystemExit, 2
- for o, a in opts:
- if o in ("-h", "--help"):
- print "Usage:\nbcfg2-build-reports [-h] [-c <configuration-file>] [-s <statistics-file>]"
- raise SystemExit
- if o in ("-A", "--all"):
- all=True
- if o in ("-c", "--config"):
- configpath = a
- if o in ("-N", "--no-ping"):
- ping = False
- if o in ("-s", "--stats"):
- statpath = a
-
-
- # See if hostinfo.xml exists, and is less than 23.5 hours old
- #try:
- #hostinstat = os.stat(hostinfopath)
- #if (time() - hostinstat[9])/(60*60) > 23.5:
- if ping:
- os.system('bcfg2-ping-sweep -C %s' % cfpath) # bcfg2-ping-sweep needs to be in path
- #except OSError:
- # os.system('GenerateHostInfo')#Generate HostInfo needs to be in path
-
-
- """Reads data & config files."""
- try:
- statsdata = XML(open(statpath).read())
- except (IOError, XMLSyntaxError):
- print("bcfg2-build-reports: Failed to parse %s"%(statpath))
- raise SystemExit, 1
- try:
- configdata = XML(open(configpath).read())
- except (IOError, XMLSyntaxError):
- print("bcfg2-build-reports: Failed to parse %s"%(configpath))
- raise SystemExit, 1
- try:
- clientsdata = XML(open(clientsdatapath).read())
- except (IOError, XMLSyntaxError):
- print("bcfg2-build-reports: Failed to parse %s"%(clientsdatapath))
- raise SystemExit, 1
-
- # Merge data from three sources.
- nodereport = Element("Report", attrib={"time" : asctime()})
- # Should all of the other info in Metadata be appended?
- # What about all of the package stuff for other types of reports?
- for client in clientsdata.findall("Client"):
- nodel = Element("Node", attrib={"name" : client.get("name")})
- nodel.append(client)
- for nod in statsdata.findall("Node"):
- if client.get('name').find(nod.get('name')) == 0:
- for statel in nod.findall("Statistics"):
- nodel.append(statel)
- nodereport.append(nodel)
-
- if all:
- for nod in statsdata.findall("Node"):
- for client in clientsdata.findall("Client"):
- if client.get('name').find(nod.get('name')) == 0:
- break
- else:
- nodel = Element("Node", attrib={"name" : nod.get("name")})
- client = Element("Client", attrib={"name" : nod.get("name"), "profile" : "default"})
- nodel.append(client)
- for statel in nod.findall("Statistics"):
- nodel.append(statel)
- nodereport.append(nodel)
-
-
- for reprt in configdata.findall('Report'):
- nodereport.set("name", reprt.get("name", default="BCFG Report"))
-
- if reprt.get('refresh-time') != None:
- nodereport.set("refresh-time", reprt.get("refresh-time", default="600"))
-
- procnodereport = generatereport(reprt, nodereport)
-
- for deliv in reprt.findall('Delivery'):
- # Is a deepcopy of procnodereport necessary?
-
- delivtype = deliv.get('type', default='nodes-digest')
- deliverymechanism = deliv.get('mechanism', default='www')
-
- # Apply XSLT, different ones based on report type, and options
- if deliverymechanism == 'null-operator': # Special Cases
- fileout(tostring(ElementTree(procnodereport).getroot(), encoding='UTF-8', xml_declaration=True), deliv)
- break
- transform = delivtype + '-' + deliverymechanism + '.xsl'
-
- try: # Make sure valid stylesheet is selected.
- os.stat(transformpath + transform)
- except:
- print("bcfg2-build-reports: Invalid report type or delivery mechanism.\n Can't find: "\
- + transformpath + transform)
- raise SystemExit, 1
-
- try: # Try to parse stylesheet.
- stylesheet = XSLT(parse(transformpath + transform))
- except:
- print("bcfg2-build-reports: invalid XSLT transform file.")
- raise SystemExit, 1
-
- if deliverymechanism == 'mail':
- if delivtype == 'nodes-individual':
- reportdata = copy.deepcopy(procnodereport)
- for noden in reportdata.findall("Node"):
- [reportdata.remove(y) for y in reportdata.findall("Node")]
- reportdata.append(noden)
- result = stylesheet.apply(ElementTree(reportdata))
- outputstring = stylesheet.tostring(result)
-
- if not outputstring == None:
- toastring = ''
- for desti in deliv.findall("Destination"):
- toastring = "%s%s " % \
- (toastring, desti.get('address'))
- # Prepend To: and From:
- outputstring = "To: %s\nFrom: root@%s\n%s"% \
- (toastring, socket.getfqdn(), outputstring)
- mail(outputstring, c) #call function to send
-
- else:
- reportdata = copy.deepcopy(procnodereport)
-
- result = stylesheet.apply(ElementTree(reportdata))
- outputstring = stylesheet.tostring(result)
-
- if not outputstring == None:
- toastring = ''
- for desti in deliv.findall("Destination"):
- toastring = "%s%s " % \
- (toastring, desti.get('address'))
- # Prepend To: and From:
- outputstring = "To: %s\nFrom: root@%s\n%s"% \
- (toastring, socket.getfqdn(), outputstring)
- mail(outputstring, c) #call function to send
- else:
- outputstring = tostring(stylesheet.apply(ElementTree(procnodereport)).getroot(), encoding='UTF-8', xml_declaration=True)
- if deliverymechanism == 'rss':
- rss(outputstring, deliv, reprt)
- else: # Must be deliverymechanism == 'www':
- www(outputstring, deliv)
diff --git a/build/scripts-2.7/bcfg2-info b/build/scripts-2.7/bcfg2-info
deleted file mode 100755
index 9721122f3..000000000
--- a/build/scripts-2.7/bcfg2-info
+++ /dev/null
@@ -1,468 +0,0 @@
-#!/usr/bin/python
-
-"""This tool loads the Bcfg2 core into an interactive debugger."""
-__revision__ = '$Revision$'
-
-from code import InteractiveConsole
-import cmd
-import errno
-import getopt
-import logging
-import lxml.etree
-import os
-import sys
-import tempfile
-
-try:
- import profile
- import pstats
- have_profile = True
-except:
- have_profile = False
-
-import Bcfg2.Logger
-import Bcfg2.Options
-import Bcfg2.Server.Core
-import Bcfg2.Server.Plugins.Metadata
-import Bcfg2.Server.Plugin
-
-logger = logging.getLogger('bcfg2-info')
-
-class dummyError(Exception):
- pass
-
-class FileNotBuilt(Exception):
- """Thrown when File entry contains no content."""
- def __init__(self, value):
- Exception.__init__(self)
- self.value = value
- def __str__(self):
- return repr(self.value)
-
-def printTabular(rows):
- """Print data in tabular format."""
- cmax = tuple([max([len(str(row[index])) for row in rows]) + 1 \
- for index in range(len(rows[0]))])
- fstring = (" %%-%ss |" * len(cmax)) % cmax
- fstring = ('|'.join([" %%-%ss "] * len(cmax))) % cmax
- print(fstring % rows[0])
- print((sum(cmax) + (len(cmax) * 2) + (len(cmax) - 1)) * '=')
- for row in rows[1:]:
- print(fstring % row)
-
-def displayTrace(trace, num=80, sort=('time', 'calls')):
- stats = pstats.Stats(trace)
- stats.sort_stats('cumulative', 'calls', 'time')
- stats.print_stats(200)
-
-def write_config_file(outputdir, cfg):
- """Store file content of an <ConfigFile name='/path/to/file' ...>...</ConfigFile> entry
- in the appropriate directory under the output directory.
- """
- name = cfg.get('name')
-
- # directory creation
- try:
- os.makedirs(os.path.dirname(outputdir + name))
- except OSError, err:
- if err.errno != errno.EEXIST:
- raise
- except:
- raise
-
- # write config file
- config_file = open(outputdir + name, "w")
- try:
- config_file.write(cfg.text)
- except: # plugin throw an exception and therefore there is no content => None
- raise FileNotBuilt(name)
- config_file.close()
-
-class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core):
-
- def __init__(self, repo, plgs, passwd, encoding, event_debug):
- cmd.Cmd.__init__(self)
- try:
- Bcfg2.Server.Core.Core.__init__(self, repo, plgs, passwd,
- encoding)
- if event_debug:
- self.fam.debug = True
- except Bcfg2.Server.Core.CoreInitError, msg:
- print("Core load failed because %s" % msg)
- raise SystemExit(1)
- self.prompt = '> '
- self.cont = True
- self.fam.handle_events_in_interval(4)
-
- def do_loop(self):
- self.cont = True
- while self.cont:
- try:
- self.cmdloop('Welcome to bcfg2-info\n'
- 'Type "help" for more information')
- except SystemExit, val:
- raise
- except Bcfg2.Server.Plugin.PluginExecutionError:
- continue
- except KeyboardInterrupt:
- print("Ctrl-C pressed exiting...")
- self.do_exit([])
- except dummyError:
- continue
- except:
- logger.error("command failure", exc_info=1)
-
- def do_debug(self, args):
- try:
- opts, _ = getopt.getopt(args.split(), 'nf:')
- except:
- print "Usage: debug [-n] [-f <command list>]"
- return
- self.cont = False
- scriptmode = False
- interactive = True
- for opt in opts:
- if opt[0] == '-f':
- scriptmode = True
- spath = opt[1]
- elif opt[0] == '-n':
- interactive = False
- sh = InteractiveConsole(locals())
- if scriptmode:
- for command in [c.strip() for c in open(spath).readlines()]:
- if command:
- sh.push(command)
- if interactive:
- print("dropping to python interpreter; press ^D to resume")
- try:
- import IPython
- shell = IPython.Shell.IPShell(argv=[], user_ns=locals())
- shell.mainloop()
- except ImportError:
- sh.interact()
-
- def do_quit(self, _):
- """
- Exit program.
- Usage: [quit|exit]
- """
- for plugin in self.plugins.values():
- plugin.shutdown()
- os._exit(0)
-
- do_EOF = do_quit
- do_exit = do_quit
-
- def do_help(self, _):
- """Print out usage info."""
- print 'Commands:'
- print 'build <hostname> <filename> - build config for hostname, writing to filename'
- print 'builddir <hostname> <dirname> - build config for hostname, writing separate files to dirname'
- print 'buildall <directory> - build configs for all clients in directory'
- print 'buildfile <filename> <hostname> - build config file for hostname (not written to disk)'
- print 'bundles - print out group/bundle information'
- print 'clients - print out client/profile information'
- print 'debug - shell out to native python interpreter'
- print 'event_debug - display filesystem events as they are processed'
- print 'generators - list current versions of generators'
- print 'groups - list groups'
- print 'help - print this list of available commands'
- print 'mappings <type*> <name*> - print generator mappings for optional type and name'
- print 'profile <command> <args> - profile a single bcfg2-info command'
- print 'quit - Exit the bcfg2-info command line'
- print 'showentries <hostname> <type> - show abstract configuration entries for a given host'
- print 'showclient <client1> <client2> - show metadata for given hosts'
- print 'update - process pending file events'
- print 'version - print version of this tool'
-
-
- def do_update(self, _):
- """Process pending fs events."""
- self.fam.handle_events_in_interval(0.1)
-
- def do_version(self, _):
- """Print out code version."""
- print(__revision__)
-
- def do_build(self, args):
- """Build client configuration."""
- alist = args.split()
- path_force = False
- if '-f' in args:
- alist.remove('-f')
- path_force = True
- if len(alist) == 2:
- client, ofile = alist
- if not ofile.startswith('/tmp') and not path_force:
- print("Refusing to write files outside of /tmp without -f option")
- return
- output = open(ofile, 'w')
- data = lxml.etree.tostring(self.BuildConfiguration(client),
- encoding='UTF-8', xml_declaration=True,
- pretty_print=True)
- output.write(data)
- output.close()
- else:
- print('Usage: build [-f] <hostname> <output file>')
-
- def help_builddir(self):
- """Display help for builddir command."""
- print('Usage: builddir [-f] <hostname> <output dir>')
- print('')
- print('Generates a config for client <hostname> and writes the')
- print('individual configuration files out separately in a tree')
- print('under <output dir>. The <output dir> directory must be')
- print('rooted under /tmp unless the -f argument is provided, in')
- print('which case it can be located anywhere.')
- print('')
- print('NOTE: Currently only handles ConfigFile entries and writes')
- print('all content with the default owner and permissions. These')
- print('could be much more permissive than would be created by the')
- print('bcfg2 client itself.')
-
- def do_builddir(self, args):
- """Build client configuration as separate files within a dir."""
- alist = args.split()
- path_force = False
- if '-f' in args:
- alist.remove('-f')
- path_force = True
- if len(alist) == 2:
- client, odir = alist
- if not odir.startswith('/tmp') and not path_force:
- print("Refusing to write files outside of /tmp without -f option")
- return
- client_config = self.BuildConfiguration(client)
- if client_config.tag == 'error':
- print("Building client configuration failed.")
- return
-
- # handle <Path type='file'> entries
- for configfile in [cfile for cfile in client_config.findall(".//Path[@type = 'file']")]:
- try:
- write_config_file(odir, configfile)
- except FileNotBuilt, ex:
- print("Warning: No file content generated for ConfigFile %s!" % ex)
- pass
- except Exception, ex:
- print("unknown error, I give up: %s" %ex)
- return
-
- print("Config for %s written to %s" % (client, odir))
-
- else:
- print('Error: Incorrect number of parameters')
- self.help_builddir()
-
- def do_buildall(self, args):
- if len(args.split()) != 1:
- print("Usage: buildall <directory>")
- return
- try:
- os.mkdir(args)
- except:
- pass
- for client in self.metadata.clients:
- self.do_build("%s %s/%s.xml" % (client, args, client))
-
- def do_buildfile(self, args):
- """Build a config file for client."""
- if len(args.split()) == 2:
- fname, client = args.split()
- entry = lxml.etree.Element('Path', type='file', name=fname)
- metadata = self.build_metadata(client)
- self.Bind(entry, metadata)
- print(lxml.etree.tostring(entry, encoding="UTF-8", xml_declaration=True))
- else:
- print('Usage: buildfile filename hostname')
-
- def do_bundles(self, _):
- """Print out group/bundle info."""
- data = [('Group', 'Bundles')]
- groups = list(self.metadata.groups.keys())
- groups.sort()
- for group in groups:
- data.append((group,
- ','.join(self.metadata.groups[group][0])))
- printTabular(data)
-
- def do_clients(self, _):
- """Print out client info."""
- data = [('Client', 'Profile')]
- clist = list(self.metadata.clients.keys())
- clist.sort()
- for client in clist:
- data.append((client, self.metadata.clients[client]))
- printTabular(data)
-
- def do_generators(self, _):
- """Print out generator info."""
- for generator in self.generators:
- print(generator.__version__)
-
- def do_showentries(self, args):
- """Show abstract configuration entries for a given host."""
- arglen = len(args.split())
- if arglen not in [1, 2]:
- print("Usage: showentries <hostname> <type>")
- return
- client = args.split()[0]
- try:
- meta = self.build_metadata(client)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- print("Unable to find metadata for host %s" % client)
- return
- structures = self.GetStructures(meta)
- output = [('entrytype', 'name')]
- if arglen == 1:
- for item in structures:
- for child in item.getchildren():
- output.append((child.tag, child.get('name')))
- if arglen == 2:
- etype = args.split()[1]
- for item in structures:
- for child in item.getchildren():
- if child.tag in [etype, "Bound%s" % etype]:
- output.append((child.tag, child.get('name')))
- printTabular(output)
-
- def do_groups(self, _):
- """Print out group info."""
- data = [("Groups", "Profile", "Category", "Contains")]
- grouplist = list(self.metadata.groups.keys())
- grouplist.sort()
- for group in grouplist:
- if group in self.metadata.profiles:
- prof = 'yes'
- else:
- prof = 'no'
- if group in self.metadata.categories:
- cat = self.metadata.categories[group]
- else:
- cat = ''
- gdata = [grp for grp in self.metadata.groups[group][1]]
- if group in gdata:
- gdata.remove(group)
- data.append((group, prof, cat, ','.join(gdata)))
- printTabular(data)
-
- def do_showclient(self, args):
- """Print host metadata."""
- data = [('Client', 'Profile', "Groups", "Bundles")]
- if not len(args):
- print("Usage:\nshowclient <client> ... <clientN>")
- return
- for client in args.split():
- try:
- client_meta = self.build_metadata(client)
- except:
- print("Client %s not defined" % client)
- continue
- print "Hostname:\t", client_meta.hostname
- print "Profile:\t", client_meta.profile
- print "Groups:\t\t", list(client_meta.groups)[0]
- for grp in list(client_meta.groups)[1:]:
- print '\t\t%s' % grp
- if client_meta.bundles:
- print "Bundles:\t", list(client_meta.bundles)[0]
- for bnd in list(client_meta.bundles)[1:]:
- print '\t\t%s' % bnd
- if client_meta.connectors:
- print "Connector data"
- print "=" * 80
- for conn in client_meta.connectors:
- if getattr(client_meta, conn):
- print "%s:\t" % (conn), getattr(client_meta, conn)
- print "=" * 80
-
- def do_mappings(self, args):
- """Print out mapping info."""
- # dump all mappings unless type specified
- data = [('Plugin', 'Type', 'Name')]
- arglen = len(args.split())
- for generator in self.generators:
- if arglen == 0:
- etypes = list(generator.Entries.keys())
- else:
- etypes = [args.split()[0]]
- if arglen == 2:
- interested = [(etype, [args.split()[1]]) \
- for etype in etypes]
- else:
- interested = [(etype, generator.Entries[etype]) \
- for etype in etypes \
- if etype in generator.Entries]
- for etype, names in interested:
- for name in [name for name in names if name in \
- generator.Entries.get(etype, {})]:
- data.append((generator.name, etype, name))
- printTabular(data)
-
- def do_event_debug(self, args):
- self.fam.debug = True
-
- def do_cfgdebug(self, args):
- try:
- meta = self.build_metadata(args)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- print("Unable to find metadata for host %s" % client)
- return
- structures = self.GetStructures(meta)
- for clist in [struct.findall('Path') for struct in structures]:
- for cfile in clist:
- if cfile.get('name') in self.plugins['Cfg'].Entries['ConfigFile']:
- cset = self.plugins['Cfg'].entries[cfile.get('name')]
- cand = cset.get_matching(meta)
- fields = ['all', 'group']
- while len(cand) > 1 and fields:
- field = fields.pop(0)
- [cand.remove(c) for c in cand[:]
- if getattr(c.specific, field)]
- if len(cand) != 1:
- sys.stderr.write("Entry %s failed" % cfile.get('name'))
- continue
- print(cand[0].name)
-
- def do_profile(self, arg):
- if not have_profile:
- print("Profiling functionality not available")
- return
- tracefname = tempfile.mktemp()
- p = profile.Profile()
- p.runcall(self.onecmd, arg)
- displayTrace(p)
-
- def Run(self, args):
- if args:
- self.onecmd(" ".join(args))
- os._exit(0)
- else:
- self.do_loop()
-
-if __name__ == '__main__':
- Bcfg2.Logger.setup_logging('bcfg2-info', to_syslog=False)
- optinfo = {
- 'configfile': Bcfg2.Options.CFILE,
- 'help': Bcfg2.Options.HELP,
- }
- optinfo.update({'repo': Bcfg2.Options.SERVER_REPOSITORY,
- 'plugins': Bcfg2.Options.SERVER_PLUGINS,
- 'password': Bcfg2.Options.SERVER_PASSWORD,
- 'event debug': Bcfg2.Options.DEBUG,
- 'profile': Bcfg2.Options.CORE_PROFILE,
- 'encoding': Bcfg2.Options.ENCODING})
- setup = Bcfg2.Options.OptionParser(optinfo)
- setup.parse(sys.argv[1:])
- if setup['profile'] and have_profile:
- prof = profile.Profile()
- loop = prof.runcall(infoCore, setup['repo'], setup['plugins'],
- setup['password'], setup['encoding'],
- setup['event debug'])
- displayTrace(prof)
- else:
- if setup['profile']:
- print("Profiling functionality not available")
- loop = infoCore(setup['repo'], setup['plugins'], setup['password'],
- setup['encoding'], setup['event debug'])
-
- loop.Run(setup['args'])
diff --git a/build/scripts-2.7/bcfg2-ping-sweep b/build/scripts-2.7/bcfg2-ping-sweep
deleted file mode 100755
index b3905e3a0..000000000
--- a/build/scripts-2.7/bcfg2-ping-sweep
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/python
-#GenerateHostInfo - Joey Hagedorn - hagedorn@mcs.anl.gov
-
-"""Generates hostinfo.xml at a regular interval."""
-
-__revision__ = '$Revision$'
-
-from os import dup2, execl, fork, uname, wait
-import sys
-import time
-import lxml.etree
-
-import Bcfg2.Options
-
-if __name__ == '__main__':
- opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY,
- 'configfile': Bcfg2.Options.CFILE}
- setup = Bcfg2.Options.OptionParser(opts)
- setup.parse(sys.argv[1:])
-
- cfpath = setup['configfile']
- clientdatapath = "%s/Metadata/clients.xml" % setup['repo']
-
- clientElement = lxml.etree.parse(clientdatapath)
- hostlist = [client.get('name') for client in clientElement.findall("Client")]
-
- pids = {}
- null = open('/dev/null', 'w+')
-
- #use uname to detect OS and use -t for darwin and -w for linux
- #/bin/ping on linux /sbin/ping on os x
- osname = uname()[0]
-
-
- while hostlist or pids:
- if hostlist and len(pids.keys()) < 15:
- host = hostlist.pop()
- pid = fork()
- if pid == 0:
- # in child
- dup2(null.fileno(), sys.__stdin__.fileno())
- dup2(null.fileno(), sys.__stdout__.fileno())
- dup2(null.fileno(), sys.__stderr__.fileno())
- if osname == 'Linux':
- execl('/bin/ping', 'ping', '-w', '5', '-c', '1', host)
- elif osname in ['Darwin', 'FreeBSD']:
- execl('/sbin/ping', 'ping', '-t', '5', '-c', '1', host)
- elif osname == 'SunOS':
- execl('/usr/sbin/ping', 'ping', host, '56', '1')
- else: #default
- execl('/bin/ping', 'ping', '-w', '5', '-c', '1', host)
- else:
- pids[pid] = host
- else:
- try:
- (cpid, status) = wait()
- except OSError:
- continue
- chost = pids[cpid]
- del pids[cpid]
- elm = clientElement.xpath("//Client[@name='%s']"%chost)[0]
- if status == 0:
- elm.set("pingable",'Y')
- elm.set("pingtime", str(time.time()))
- else:
- elm.set("pingable",'N')
-
- fout = open(clientdatapath, 'w')
- fout.write(lxml.etree.tostring(clientElement.getroot(), encoding='UTF-8', xml_declaration=True))
- fout.close()
-
diff --git a/build/scripts-2.7/bcfg2-repo-validate b/build/scripts-2.7/bcfg2-repo-validate
deleted file mode 100755
index 4606ab10e..000000000
--- a/build/scripts-2.7/bcfg2-repo-validate
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/python
-
-"""
-bcfg2-repo-validate checks all xml files in Bcfg2
-repos against their respective XML schemas.
-"""
-__revision__ = '$Revision$'
-
-import glob
-import lxml.etree
-import os
-import sys
-import Bcfg2.Options
-
-if __name__ == '__main__':
- opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY,
- 'prefix': Bcfg2.Options.INSTALL_PREFIX,
- 'verbose': Bcfg2.Options.VERBOSE,
- 'configfile': Bcfg2.Options.CFILE}
- setup = Bcfg2.Options.OptionParser(opts)
- setup.parse(sys.argv[1:])
- verbose = setup['verbose']
- cpath = setup['configfile']
- prefix = setup['prefix']
- schemadir = "%s/share/bcfg2/schemas" % (prefix)
- os.chdir(schemadir)
- repo = setup['repo']
-
- # Get a list of all info.xml files in the bcfg2 repository
- info_list = []
- for infodir in ['Cfg', 'TGenshi', 'TCheetah']:
- for root, dirs, files in os.walk('%s/%s' % (repo, infodir)):
- for filename in files:
- if filename == 'info.xml':
- info_list.append(os.path.join(root, filename))
-
- # get metadata list (with all included files)
- metadata_list = glob.glob("%s/Metadata/groups.xml" % repo)
- ref_bundles = set()
- xdata = lxml.etree.parse("%s/Metadata/groups.xml" % repo)
- included = set([ent.get('href') for ent in \
- xdata.findall('./{http://www.w3.org/2001/XInclude}include')])
- while included:
- try:
- filename = included.pop()
- except KeyError:
- continue
- metadata_list.append("%s/Metadata/%s" % (repo, filename))
- groupdata = lxml.etree.parse("%s/Metadata/%s" % (repo, filename))
- group_ents = [ent.get('href') for ent in \
- groupdata.
- findall('./{http://www.w3.org/2001/XInclude}include')]
- for ent in group_ents:
- included.add(ent)
- included.discard(filename)
-
- # check for multiple default group definitions
- default_groups = []
- for grp in lxml.etree.parse("%s/Metadata/groups.xml" \
- % repo).findall('.//Group'):
- if grp.get('default') == 'true':
- default_groups.append(grp)
- if len(default_groups) > 1:
- print("*** Warning: Multiple default groups defined")
- for grp in default_groups:
- print(" %s" % grp.get('name'))
-
- # get all XIncluded bundles
- xdata.xinclude()
- for bundle in xdata.findall("//Bundle"):
- ref_bundles.add("%s/Bundler/%s" % (repo, bundle.get('name')))
-
- # get lists of all other xml files to validate
- clients_list = glob.glob("%s/Metadata/clients.xml" % repo)
- bundle_list = glob.glob("%s/Bundler/*.xml" % repo)
- genshibundle_list = glob.glob("%s/Bundler/*.genshi" % repo)
- pkg_list = glob.glob("%s/Pkgmgr/*.xml" % repo)
- base_list = glob.glob("%s/Base/*.xml" % repo)
- rules_list = glob.glob("%s/Rules/*.xml" % repo)
- imageinfo_list = glob.glob("%s/etc/report-configuration.xml" % repo)
- services_list = glob.glob("%s/Svcmgr/*.xml" % repo)
- deps_list = glob.glob("%s/Deps/*.xml" % repo)
- dec_list = glob.glob("%s/Decisions/*" % repo)
- pkgcfg_list = glob.glob("%s/Packages/config.xml" % repo)
- gp_list = glob.glob('%s/GroupPatterns/config.xml' % repo)
-
- # verify attributes for configuration entries
- # (as defined in doc/server/configurationentries)
- # TODO: See if it is possible to do this in the schema instead
- required_configuration_attrs = {
- 'device': ['name', 'owner', 'group', 'dev_type'],
- 'directory': ['name', 'owner', 'group', 'perms'],
- 'file': ['name', 'owner', 'group', 'perms'],
- 'hardlink': ['name', 'to'],
- 'symlink': ['name', 'to'],
- 'ignore': ['name'],
- 'nonexist': ['name'],
- 'permissions': ['name', 'owner', 'group', 'perms']}
- for rfile in rules_list:
- try:
- xdata = lxml.etree.parse(rfile)
- except lxml.etree.XMLSyntaxError, e:
- print("Failed to parse %s: %s" % (rfile, e))
- for posixpath in xdata.findall("//Path"):
- pathname = posixpath.get('name')
- pathtype = posixpath.get('type')
- pathset = set(posixpath.attrib.keys())
- try:
- required_attrs = set(required_configuration_attrs[pathtype] \
- + ['type'])
- except KeyError:
- continue
- if 'dev_type' in required_attrs:
- dev_type = posixpath.get('dev_type')
- if dev_type in ['block', 'char']:
- # check if major/minor are specified
- required_attrs |= set(['major', 'minor'])
- if pathset.issuperset(required_attrs):
- continue
- else:
- print("The following required attributes are missing for"
- " Path %s in %s: %s" % (pathname, rfile,
- [attr for attr in required_attrs.difference(pathset)]))
-
- # warn on duplicate Pkgmgr entries with the same priority
- pset = set()
- for plist in pkg_list:
- try:
- xdata = lxml.etree.parse(plist)
- except lxml.etree.XMLSyntaxError, e:
- print("Failed to parse %s: %s" % (plist, e))
- # get priority, type, group
- priority = xdata.getroot().get('priority')
- ptype = xdata.getroot().get('type')
- for pkg in xdata.findall("//Package"):
- if pkg.getparent().tag == 'Group':
- grp = pkg.getparent().get('name')
- if type(grp) is not str and grp.getparent().tag == 'Group':
- pgrp = grp.getparent().get('name')
- else:
- pgrp = 'none'
- else:
- grp = 'none'
- pgrp = 'none'
- ptuple = (pkg.get('name'), priority, ptype, grp, pgrp)
- # check if package is already listed with same priority,
- # type, grp
- if ptuple in pset:
- print("Duplicate Package %s, priority:%s, type:%s"\
- % (pkg.get('name'), priority, ptype))
- else:
- pset.add(ptuple)
-
- filesets = {'metadata': (metadata_list, "%s/metadata.xsd"),
- 'clients': (clients_list, "%s/clients.xsd"),
- 'info': (info_list, "%s/info.xsd"),
- 'bundle': (bundle_list, "%s/bundle.xsd"),
- 'pkglist': (pkg_list, "%s/pkglist.xsd"),
- 'base': (base_list, "%s/base.xsd"),
- 'rules': (rules_list, "%s/rules.xsd"),
- 'imageinfo': (imageinfo_list, "%s/report-configuration.xsd"),
- 'services': (services_list, "%s/services.xsd"),
- 'deps': (deps_list, "%s/deps.xsd"),
- 'decisions': (dec_list, "%s/decisions.xsd"),
- 'packages': (pkgcfg_list, "%s/packages.xsd"),
- 'grouppatterns': (gp_list, "%s/grouppatterns.xsd"),
- }
-
- failures = 0
- for k, (filelist, schemaname) in list(filesets.items()):
- try:
- schema = lxml.etree.XMLSchema(lxml.etree.parse(open(schemaname%(schemadir))))
- except:
- print("Failed to process schema %s" % (schemaname%(schemadir)))
- failures = 1
- continue
- for filename in filelist:
- try:
- datafile = lxml.etree.parse(open(filename))
- except SyntaxError:
- print("%s ***FAILS*** to parse \t\t<----" % (filename))
- os.system("xmllint %s" % filename)
- failures = 1
- continue
- except IOError:
- print("Failed to open file %s \t\t<---" % (filename))
- failures = 1
- continue
- if schema.validate(datafile):
- if verbose:
- print("%s checks out" % (filename))
- else:
- rc = os.system("xmllint --noout --xinclude --schema \
- %s %s > /dev/null 2>/dev/null" % \
- (schemaname % schemadir, filename))
- if rc:
- failures = 1
- print("%s ***FAILS*** to verify \t\t<----" % (filename))
- os.system("xmllint --noout --xinclude --schema %s %s" % \
- (schemaname % schemadir, filename))
- elif verbose:
- print("%s checks out" % (filename))
-
- # print out missing bundle information
- if verbose:
- print("")
- for bundle in ref_bundles:
- # check for both regular and genshi bundles
- xmlbundle = "%s.xml" % bundle
- genshibundle = "%s.genshi" % bundle
- allbundles = bundle_list + genshibundle_list
- if xmlbundle not in allbundles and \
- genshibundle not in allbundles:
- print("*** Warning: Bundle %s referenced, but does not "
- "exist." % bundle)
- # verify bundle name attribute matches filename
- for bundle in (bundle_list + genshibundle_list):
- fname = bundle.split('Bundler/')[1].split('.')[0]
- xdata = lxml.etree.parse(bundle)
- bname = xdata.getroot().get('name')
- if fname != bname:
- print("The following names are inconsistent:")
- print(" Filename is %s" % fname)
- print(" Bundle name found in %s is %s" % (fname, bname))
-
-
- raise SystemExit, failures
diff --git a/build/scripts-2.7/bcfg2-reports b/build/scripts-2.7/bcfg2-reports
deleted file mode 100755
index 85338b0d8..000000000
--- a/build/scripts-2.7/bcfg2-reports
+++ /dev/null
@@ -1,282 +0,0 @@
-#!/usr/bin/python
-"""Query reporting system for client status."""
-__revision__ = '$Revision$'
-
-import os
-import sys
-
-import Bcfg2.Server.Reports.settings
-
-project_directory = os.path.dirname(Bcfg2.Server.Reports.settings.__file__)
-project_name = os.path.basename(project_directory)
-sys.path.append(os.path.join(project_directory, '..'))
-project_module = __import__(project_name, '', '', [''])
-sys.path.pop()
-# Set DJANGO_SETTINGS_MODULE appropriately.
-os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
-
-from Bcfg2.Server.Reports.reports.models import Client
-from getopt import getopt
-import datetime
-import fileinput
-
-def timecompare(client1, client2):
- """Compares two clients by their timestamps."""
- return cmp(client1.current_interaction.timestamp, \
- client2.current_interaction.timestamp)
-
-def namecompare(client1, client2):
- """Compares two clients by their names."""
- return cmp(client1.name, client2.name)
-
-def statecompare(client1, client2):
- """Compares two clients by their states."""
- clean1 = client1.current_interaction.isclean()
- clean2 = client2.current_interaction.isclean()
-
- if clean1 and not clean2:
- return -1
- elif clean2 and not clean1:
- return 1
- else:
- return 0
-
-def crit_compare(criterion, client1, client2):
- """Compares two clients by the criteria provided in criterion."""
- for crit in criterion:
- comp = 0
- if crit == 'name':
- comp = namecompare(client1, client2)
- elif crit == 'state':
- comp = statecompare(client1, client2)
- elif crit == 'time':
- comp = timecompare(client1, client2)
-
- if comp != 0:
- return comp
-
- return 0
-
-def print_fields(fields, cli, max_name, entrydict):
- """
- Prints the fields specified in fields of cli, max_name
- specifies the column width of the name column.
- """
- fmt = ''
- for field in fields:
- if field == 'name':
- fmt += ("%%-%ds " % (max_name))
- else:
- fmt += "%s "
- fdata = []
- for field in fields:
- if field == 'time':
- fdata.append(str(cli.current_interaction.timestamp))
- elif field == 'state':
- if cli.current_interaction.isclean():
- fdata.append("clean")
- else:
- fdata.append("dirty")
- else:
- try:
- fdata.append(getattr(cli, field))
- except:
- fdata.append("N/A")
-
- display = fmt % tuple(fdata)
- if len(entrydict) > 0:
- display += " "
- display += str(entrydict[cli])
- print display
-
-def print_entry(item, max_name):
- fmt = ("%%-%ds " % (max_name))
- fdata = item.entry.kind + ":" + item.entry.name
- display = fmt % (fdata)
- print display
-
-fields = ""
-sort = ""
-badentry = ""
-extraentry = ""
-expire = ""
-singlehost = ""
-
-c_list = Client.objects.all()
-
-result = list()
-entrydict = dict()
-
-args = sys.argv[1:]
-opts, pargs = getopt(args, 'ab:cde:hs:x:',
- ['stale', 'sort=', 'fields=', 'badentry=', 'extraentry='])
-
-for option in opts:
- if len(option) > 0:
- if option[0] == '--fields':
- fields = option[1]
- if option[0] == '--sort':
- sort = option[1]
- if option[0] == '--badentry':
- badentry = option[1]
- if option[0] == '--extraentry':
- extraentry = option[1]
- if option[0] == '-x':
- expire = option[1]
- if option[0] == '-s' or option[0] == '-b' or option[0] == '-e':
- singlehost = option[1]
-
-if expire != "":
- for c_inst in c_list:
- if expire == c_inst.name:
- if c_inst.expiration == None:
- c_inst.expiration = datetime.datetime.now()
- print "Host expired."
- else:
- c_inst.expiration = None
- print "Host un-expired."
- c_inst.save()
-
-elif '-h' in args:
- print """Usage: python bcfg2-reports [option] ...
-
-Options and arguments (and corresponding environment variables):
--a : shows all hosts, including expired hosts
--b NAME : single-host mode - shows bad entries from the
- current interaction of NAME
--c : shows only clean hosts
--d : shows only dirty hosts
--e NAME : single-host mode - shows extra entries from the
- current interaction of NAME
--h : shows help and usage info about bcfg2-reports
--s NAME : single-host mode - shows bad and extra entries from
- the current interaction of NAME
--x NAME : toggles expired/unexpired state of NAME
---badentry=KIND,NAME : shows only hosts whose current interaction has bad
- entries in of KIND kind and NAME name; if a single
- argument ARG1 is given, then KIND,NAME pairs will be
- read from a file of name ARG1
---extraentry=KIND,NAME : shows only hosts whose current interaction has extra
- entries in of KIND kind and NAME name; if a single
- argument ARG1 is given, then KIND,NAME pairs will be
- read from a file of name ARG1
---fields=ARG1,ARG2,... : only displays the fields ARG1,ARG2,...
- (name,time,state)
---sort=ARG1,ARG2,... : sorts output on ARG1,ARG2,... (name,time,state)
---stale : shows hosts which haven't run in the last 24 hours
-"""
-elif singlehost != "":
- for c_inst in c_list:
- if singlehost == c_inst.name:
- baditems = c_inst.current_interaction.bad()
- if len(baditems) > 0 and ('-b' in args or '-s' in args):
- print "Bad Entries:"
- max_name = -1
- for item in baditems:
- if len(item.entry.name) > max_name:
- max_name = len(item.entry.name)
- for item in baditems:
- print_entry(item, max_name)
- extraitems = c_inst.current_interaction.extra()
- if len(extraitems) > 0 and ('-e' in args or '-s' in args):
- print "Extra Entries:"
- max_name = -1
- for item in extraitems:
- if len(item.entry.name) > max_name:
- max_name = len(item.entry.name)
- for item in extraitems:
- print_entry(item, max_name)
-
-
-else:
- if fields == "":
- fields = ['name', 'time', 'state']
- else:
- fields = fields.split(',')
-
- if sort != "":
- sort = sort.split(',')
-
- if badentry != "":
- badentry = badentry.split(',')
-
- if extraentry != "":
- extraentry = extraentry.split(',')
-
- # stale hosts
- if '--stale' in args:
- for c_inst in c_list:
- if c_inst.current_interaction.isstale():
- result.append(c_inst)
- # clean hosts
- elif '-c' in args:
- for c_inst in c_list:
- if c_inst.current_interaction.isclean():
- result.append(c_inst)
- # dirty hosts
- elif '-d' in args:
- for c_inst in c_list:
- if not c_inst.current_interaction.isclean():
- result.append(c_inst)
-
- elif badentry != "":
- if len(badentry) == 1:
- fileread = fileinput.input(badentry[0])
- for line in fileread:
- badentry = line.strip().split(',')
- for c_inst in c_list:
- baditems = c_inst.current_interaction.bad()
- for item in baditems:
- if item.name == badentry[1] and item.kind == badentry[0]:
- result.append(c_inst)
- if c_inst in entrydict:
- entrydict.get(c_inst).append(badentry[1])
- else:
- entrydict[c_inst] = [badentry[1]]
- break
- else:
- for c_inst in c_list:
- baditems = c_inst.current_interaction.bad()
- for item in baditems:
- if item.name == badentry[1] and item.kind == badentry[0]:
- result.append(c_inst)
- break
- elif extraentry != "":
- if len(extraentry) == 1:
- fileread = fileinput.input(extraentry[0])
- for line in fileread:
- extraentry = line.strip().split(',')
- for c_inst in c_list:
- extraitems = c_inst.current_interaction.extra()
- for item in extraitems:
- if item.name == extraentry[1] and item.kind == extraentry[0]:
- result.append(c_inst)
- if c_inst in entrydict:
- entrydict.get(c_inst).append(extraentry[1])
- else:
- entrydict[c_inst] = [extraentry[1]]
- break
- else:
- for c_inst in c_list:
- extraitems = c_inst.current_interaction.extra()
- for item in extraitems:
- if item.name == extraentry[1] and item.kind == extraentry[0]:
- result.append(c_inst)
- break
-
- else:
- for c_inst in c_list:
- result.append(c_inst)
- max_name = -1
- if 'name' in fields:
- for c_inst in result:
- if len(c_inst.name) > max_name:
- max_name = len(c_inst.name)
-
- if sort != "":
- result.sort(lambda x, y: crit_compare(sort, x, y))
-
- if fields != "":
- for c_inst in result:
- if '-a' in args or c_inst.expiration == None:
- print_fields(fields, c_inst, max_name, entrydict)
diff --git a/build/scripts-2.7/bcfg2-server b/build/scripts-2.7/bcfg2-server
deleted file mode 100755
index 115708bf9..000000000
--- a/build/scripts-2.7/bcfg2-server
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/python
-
-"""The XML-RPC Bcfg2 server."""
-__revision__ = '$Revision$'
-
-import logging
-import os.path
-import sys
-
-import Bcfg2.Logger
-import Bcfg2.Options
-import Bcfg2.Component
-import Bcfg2.Server.Plugins.Metadata
-from Bcfg2.Server.Core import CoreInitError
-
-logger = logging.getLogger('bcfg2-server')
-
-if __name__ == '__main__':
-
- OPTINFO = {
- 'configfile': Bcfg2.Options.CFILE,
- 'daemon' : Bcfg2.Options.DAEMON,
- 'debug' : Bcfg2.Options.DEBUG,
- 'help' : Bcfg2.Options.HELP,
- 'verbose' : Bcfg2.Options.VERBOSE,
- 'to_file' : Bcfg2.Options.LOGGING_FILE_PATH,
- }
-
- OPTINFO.update({'repo' : Bcfg2.Options.SERVER_REPOSITORY,
- 'plugins' : Bcfg2.Options.SERVER_PLUGINS,
- 'password' : Bcfg2.Options.SERVER_PASSWORD,
- 'fm' : Bcfg2.Options.SERVER_FILEMONITOR,
- })
-
- OPTINFO.update({'key' : Bcfg2.Options.SERVER_KEY,
- 'cert' : Bcfg2.Options.SERVER_CERT,
- 'ca' : Bcfg2.Options.SERVER_CA,
- 'location' : Bcfg2.Options.SERVER_LOCATION,
- 'passwd' : Bcfg2.Options.SERVER_PASSWORD,
- 'static' : Bcfg2.Options.SERVER_STATIC,
- 'encoding' : Bcfg2.Options.ENCODING,
- 'filelog' : Bcfg2.Options.LOGGING_FILE_PATH,
- 'protocol' : Bcfg2.Options.SERVER_PROTOCOL,
- })
-
- setup = Bcfg2.Options.OptionParser(OPTINFO)
- setup.parse(sys.argv[1:])
- try:
- # check whether the specified bcfg2.conf exists
- if not os.path.exists(setup['configfile']):
- print("Could not read %s" % setup['configfile'])
- sys.exit(1)
- Bcfg2.Component.run_component(Bcfg2.Server.Core.Core,
- location=setup['location'],
- daemon = setup['daemon'],
- pidfile_name = setup['daemon'],
- protocol = setup['protocol'],
- to_file=setup['to_file'],
- cfile=setup['configfile'],
- register=False,
- cls_kwargs={'repo':setup['repo'],
- 'plugins':setup['plugins'],
- 'password':setup['password'],
- 'encoding':setup['encoding'],
- 'ca':setup['ca'],
- 'filemonitor':setup['fm'],
- 'start_fam_thread':True},
- keyfile=setup['key'],
- certfile=setup['cert'],
- ca=setup['ca'],
- )
- except CoreInitError, msg:
- logger.error(msg)
- logger.error("exiting")
- sys.exit(1)
- except KeyboardInterrupt:
- sys.exit(1)
- sys.exit(0)
-