From 111193ef96adb711b1b1b4859291c77197eb8ea8 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 31 Jul 2012 09:12:01 -0400 Subject: unified Metadata/DBMetadata plugins made django optional --- src/lib/Bcfg2/Server/Plugin.py | 21 +++- src/lib/Bcfg2/Server/Plugins/DBMetadata.py | 128 --------------------- src/lib/Bcfg2/Server/Plugins/Metadata.py | 179 +++++++++++++++++++++++------ src/lib/Bcfg2/Server/Plugins/Probes.py | 34 +++--- 4 files changed, 183 insertions(+), 179 deletions(-) delete mode 100644 src/lib/Bcfg2/Server/Plugins/DBMetadata.py (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugin.py b/src/lib/Bcfg2/Server/Plugin.py index 696dacc06..2a68ea3b7 100644 --- a/src/lib/Bcfg2/Server/Plugin.py +++ b/src/lib/Bcfg2/Server/Plugin.py @@ -11,9 +11,14 @@ import sys import threading import Bcfg2.Server from Bcfg2.Bcfg2Py3k import ConfigParser - import Bcfg2.Options +try: + import django + has_django = True +except ImportError: + has_django = False + # py3k compatibility if sys.hexversion >= 0x03000000: from functools import reduce @@ -106,6 +111,20 @@ class DatabaseBacked(object): def __init__(self): pass + @property + def _use_db(self): + use_db = self.core.setup.cfp.getboolean(self.name.lower(), + "use_database", + default=False) + if use_db and has_django: + return True + elif not use_db: + return False + else: + self.logger.error("use_database is true but django not found") + return False + + class PluginDatabaseModel(object): class Meta: diff --git a/src/lib/Bcfg2/Server/Plugins/DBMetadata.py b/src/lib/Bcfg2/Server/Plugins/DBMetadata.py deleted file mode 100644 index 16a6e0dcc..000000000 --- a/src/lib/Bcfg2/Server/Plugins/DBMetadata.py +++ /dev/null @@ -1,128 +0,0 @@ -import os -import sys -from UserDict import DictMixin -from django.db import models -import Bcfg2.Server.Lint -import Bcfg2.Server.Plugin -from Bcfg2.Server.Plugins.Metadata import * - -class MetadataClientModel(models.Model, - Bcfg2.Server.Plugin.PluginDatabaseModel): - hostname = models.CharField(max_length=255, primary_key=True) - version = models.CharField(max_length=31, null=True) - - -class ClientVersions(DictMixin): - def __getitem__(self, key): - try: - return MetadataClientModel.objects.get(hostname=key).version - except MetadataClientModel.DoesNotExist: - raise KeyError(key) - - def __setitem__(self, key, value): - client = MetadataClientModel.objects.get_or_create(hostname=key)[0] - client.version = value - client.save() - - def keys(self): - return [c.hostname for c in MetadataClientModel.objects.all()] - - def __contains__(self, key): - try: - client = MetadataClientModel.objects.get(hostname=key) - return True - except MetadataClientModel.DoesNotExist: - return False - - -class DBMetadata(Metadata, Bcfg2.Server.Plugin.DatabaseBacked): - __files__ = ["groups.xml"] - experimental = True - conflicts = ['Metadata'] - - def __init__(self, core, datastore, watch_clients=True): - Metadata.__init__(self, core, datastore, watch_clients=watch_clients) - Bcfg2.Server.Plugin.DatabaseBacked.__init__(self) - if os.path.exists(os.path.join(self.data, "clients.xml")): - self.logger.warning("DBMetadata: clients.xml found, parsing in " - "compatibility mode") - self._handle_file("clients.xml") - self.versions = ClientVersions() - - def add_group(self, group_name, attribs): - msg = "DBMetadata does not support adding groups" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def add_bundle(self, bundle_name): - msg = "DBMetadata does not support adding bundles" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def add_client(self, client_name): - """Add client to clients database.""" - client = MetadataClientModel(hostname=client_name) - client.save() - self.clients = self.list_clients() - return client - - def update_group(self, group_name, attribs): - msg = "DBMetadata does not support updating groups" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def update_bundle(self, bundle_name): - msg = "DBMetadata does not support updating bundles" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def update_client(self, client_name, attribs): - msg = "DBMetadata does not support updating clients" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def list_clients(self): - """ List all clients in client database """ - return set([c.hostname for c in MetadataClientModel.objects.all()]) - - def remove_group(self, group_name, attribs): - msg = "DBMetadata does not support removing groups" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def remove_bundle(self, bundle_name): - msg = "DBMetadata does not support removing bundles" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def remove_client(self, client_name): - """Remove a client""" - try: - client = MetadataClientModel.objects.get(hostname=client_name) - except MetadataClientModel.DoesNotExist: - msg = "Client %s does not exist" % client_name - self.logger.warning(msg) - raise MetadataConsistencyError(msg) - client.delete() - self.clients = self.list_clients() - - def _set_profile(self, client, profile, addresspair): - if client not in self.clients: - # adding a new client - self.add_client(client) - if client not in self.clientgroups: - self.clientgroups[client] = [profile] - else: - msg = "DBMetadata does not support asserting client profiles" - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - - def _handle_clients_xml_event(self, event): - # clients.xml is parsed and the options specified in it are - # understood, but it does _not_ assert client existence. - Metadata._handle_clients_xml_event(self, event) - self.clients = self.list_clients() - - -class DBMetadataLint(MetadataLint): - pass diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index 5dcaa8bdb..07659b62a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -3,19 +3,27 @@ This file stores persistent metadata for the Bcfg2 Configuration Repository. """ import re -import copy -import fcntl -import lxml.etree import os -import socket import sys import time +import copy +import fcntl +import socket +import lxml.etree import Bcfg2.Server import Bcfg2.Server.Lint import Bcfg2.Server.Plugin import Bcfg2.Server.FileMonitor +from UserDict import DictMixin from Bcfg2.version import Bcfg2VersionInfo +try: + from django.db import models + has_django = True +except ImportError: + has_django = False + + def locked(fd): """Aquire a lock on a file""" try: @@ -25,6 +33,35 @@ def locked(fd): return False +if has_django: + class MetadataClientModel(models.Model, + Bcfg2.Server.Plugin.PluginDatabaseModel): + hostname = models.CharField(max_length=255, primary_key=True) + version = models.CharField(max_length=31, null=True) + + class ClientVersions(DictMixin): + def __getitem__(self, key): + try: + return MetadataClientModel.objects.get(hostname=key).version + except MetadataClientModel.DoesNotExist: + raise KeyError(key) + + def __setitem__(self, key, value): + client = MetadataClientModel.objects.get_or_create(hostname=key)[0] + client.version = value + client.save() + + def keys(self): + return [c.hostname for c in MetadataClientModel.objects.all()] + + def __contains__(self, key): + try: + client = MetadataClientModel.objects.get(hostname=key) + return True + except MetadataClientModel.DoesNotExist: + return False + + class MetadataConsistencyError(Exception): """This error gets raised when metadata is internally inconsistent.""" pass @@ -264,23 +301,30 @@ class MetadataGroup(tuple): class Metadata(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Metadata, - Bcfg2.Server.Plugin.Statistics): + Bcfg2.Server.Plugin.Statistics, + Bcfg2.Server.Plugin.DatabaseBacked): """This class contains data for bcfg2 server metadata.""" __author__ = 'bcfg-dev@mcs.anl.gov' name = "Metadata" sort_order = 500 - __files__ = ["groups.xml", "clients.xml"] 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) + Bcfg2.Server.Plugin.DatabaseBacked.__init__(self) self.watch_clients = watch_clients self.states = dict() self.extra = dict() self.handlers = [] - for fname in self.__files__: - self._handle_file(fname) + self._handle_file("groups.xml") + if (self._use_db and + os.path.exists(os.path.join(self.data, "clients.xml"))): + self.logger.warning("Metadata: database enabled but clients.xml" + "found, parsing in compatibility mode") + self._handle_file("clients.xml") + elif not self._use_db: + self._handle_file("clients.xml") # mapping of clientname -> authtype self.auth = dict() @@ -304,7 +348,10 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, self.group_membership = dict() self.negated_groups = dict() # mapping of hostname -> version string - self.versions = dict() + if self._use_db: + self.versions = ClientVersions() + else: + self.versions = dict() self.uuid = {} self.session_cache = {} self.default = None @@ -322,7 +369,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, # must use super here; inheritance works funny with class methods super(Metadata, cls).init_repo(repo) - for fname in cls.__files__: + for fname in ["clients.xml", "groups.xml"]: aname = re.sub(r'[^A-z0-9_]', '_', fname) if aname in kwargs: open(os.path.join(repo, cls.name, fname), @@ -380,17 +427,36 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, def add_group(self, group_name, attribs): """Add group to groups.xml.""" - return self._add_xdata(self.groups_xml, "Group", group_name, - attribs=attribs) + if self._use_db: + msg = "Metadata does not support adding groups with use_database enabled" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + else: + return self._add_xdata(self.groups_xml, "Group", group_name, + attribs=attribs) def add_bundle(self, bundle_name): """Add bundle to groups.xml.""" - return self._add_xdata(self.groups_xml, "Bundle", bundle_name) + if self._use_db: + msg = "Metadata does not support adding bundles with use_database enabled" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + else: + return self._add_xdata(self.groups_xml, "Bundle", bundle_name) - def add_client(self, client_name, attribs): + def add_client(self, client_name, attribs=None): """Add client to clients.xml.""" - return self._add_xdata(self.clients_xml, "Client", client_name, - attribs=attribs, alias=True) + print "add_client(%s, attribs=%s)" % (client_name, attribs) + if attribs is None: + attribs = dict() + if self._use_db: + client = MetadataClientModel(hostname=client_name) + client.save() + self.clients = self.list_clients() + return client + else: + return self._add_xdata(self.clients_xml, "Client", client_name, + attribs=attribs, alias=True) def _update_xdata(self, config, tag, name, attribs, alias=False): node = self._search_xdata(tag, name, config.xdata, alias=alias) @@ -409,12 +475,30 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, def update_group(self, group_name, attribs): """Update a groups attributes.""" - return self._update_xdata(self.groups_xml, "Group", group_name, attribs) + if self._use_db: + msg = "Metadata does not support updating groups with use_database enabled" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + else: + return self._update_xdata(self.groups_xml, "Group", group_name, + attribs) def update_client(self, client_name, attribs): """Update a clients attributes.""" - return self._update_xdata(self.clients_xml, "Client", client_name, - attribs, alias=True) + if self._use_db: + msg = "Metadata does not support updating clients with use_database enabled" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + else: + return self._update_xdata(self.clients_xml, "Client", client_name, + attribs, alias=True) + + def list_clients(self): + """ List all clients in client database """ + if self._use_db: + return set([c.hostname for c in MetadataClientModel.objects.all()]) + else: + return self.clients def _remove_xdata(self, config, tag, name, alias=False): node = self._search_xdata(tag, name, config.xdata) @@ -432,15 +516,35 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, def remove_group(self, group_name): """Remove a group.""" - return self._remove_xdata(self.groups_xml, "Group", group_name) + if self._use_db: + msg = "Metadata does not support removing groups with use_database enabled" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + else: + return self._remove_xdata(self.groups_xml, "Group", group_name) def remove_bundle(self, bundle_name): """Remove a bundle.""" - return self._remove_xdata(self.groups_xml, "Bundle", bundle_name) + if self._use_db: + msg = "Metadata does not support removing bundles with use_database enabled" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + else: + return self._remove_xdata(self.groups_xml, "Bundle", bundle_name) def remove_client(self, client_name): """Remove a bundle.""" - return self._remove_xdata(self.clients_xml, "Client", client_name) + if self._use_db: + try: + client = MetadataClientModel.objects.get(hostname=client_name) + except MetadataClientModel.DoesNotExist: + msg = "Client %s does not exist" % client_name + self.logger.warning(msg) + raise MetadataConsistencyError(msg) + client.delete() + self.clients = self.list_clients() + else: + return self._remove_xdata(self.clients_xml, "Client", client_name) def _handle_clients_xml_event(self, event): xdata = self.clients_xml.xdata @@ -497,6 +601,8 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, except KeyError: self.clientgroups[clname] = [client.get('profile')] self.states['clients.xml'] = True + if self._use_db: + self.clients = self.list_clients() def _handle_groups_xml_event(self, event): self.groups = {} @@ -627,10 +733,13 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, msg = "Cannot set client %s to private group %s" % (client, profile) self.logger.error(msg) raise MetadataConsistencyError(msg) - self._set_profile(client, profile, addresspair) - def _set_profile(self, client, profile, addresspair): if client in self.clients: + if self._use_db: + msg = "DBMetadata does not support asserting client profiles" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + profiles = [g for g in self.clientgroups[client] if g in self.groups and self.groups[g].is_profile] self.logger.info("Changing %s profile from %s to %s" % @@ -645,16 +754,20 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, 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 - self.add_client(self.session_cache[addresspair][1], - dict(uuid=client, profile=profile, - address=addresspair[0])) + if self._use_db: + self.add_client(client) else: - self.add_client(client, dict(profile=profile)) - self.clients.append(client) - self.clientgroups[client] = [profile] - self.clients_xml.write() + if addresspair in self.session_cache: + # we are working with a uuid'd client + self.add_client(self.session_cache[addresspair][1], + dict(uuid=client, profile=profile, + address=addresspair[0])) + else: + self.add_client(client, dict(profile=profile)) + self.clients.append(client) + self.clientgroups[client] = [profile] + if not self._use_db: + self.clients_xml.write() def set_version(self, client, version): """Set group parameter for provided client.""" diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py index 3932c44d1..114a9bbd8 100644 --- a/src/lib/Bcfg2/Server/Plugins/Probes.py +++ b/src/lib/Bcfg2/Server/Plugins/Probes.py @@ -5,9 +5,14 @@ import time import operator import lxml.etree import Bcfg2.Server -from django.db import models import Bcfg2.Server.Plugin +try: + from django.db import models + has_django = True +except ImportError: + has_django = False + try: import json has_json = True @@ -32,18 +37,18 @@ except ImportError: import Bcfg2.Server.Plugin -class ProbesDataModel(models.Model, - Bcfg2.Server.Plugin.PluginDatabaseModel): - hostname = models.CharField(max_length=255) - probe = models.CharField(max_length=255) - timestamp = models.DateTimeField(auto_now=True) - data = models.TextField(null=True) +if has_django: + class ProbesDataModel(models.Model, + Bcfg2.Server.Plugin.PluginDatabaseModel): + hostname = models.CharField(max_length=255) + probe = models.CharField(max_length=255) + timestamp = models.DateTimeField(auto_now=True) + data = models.TextField(null=True) - -class ProbesGroupsModel(models.Model, - Bcfg2.Server.Plugin.PluginDatabaseModel): - hostname = models.CharField(max_length=255) - group = models.CharField(max_length=255) + class ProbesGroupsModel(models.Model, + Bcfg2.Server.Plugin.PluginDatabaseModel): + hostname = models.CharField(max_length=255) + group = models.CharField(max_length=255) class ClientProbeDataSet(dict): @@ -172,11 +177,6 @@ class Probes(Bcfg2.Server.Plugin.Plugin, self.cgroups = dict() self.load_data() - @property - def _use_db(self): - return self.core.setup.cfp.getboolean("probes", "use_database", - default=False) - def write_data(self, client): """Write probe data out for use with bcfg2-info.""" if self._use_db: -- cgit v1.2.3-1-g7c22