summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorAndrew Brestick <brestick@mcs.anl.gov>2008-07-31 20:50:44 +0000
committerAndrew Brestick <brestick@mcs.anl.gov>2008-07-31 20:50:44 +0000
commite9e94e78bb52ca2ec36e3f3402dbde3f8289cdf3 (patch)
tree5f8c573da32e0f3dba86555a3534909abd2bb2d2 /src/lib
parent7c6c1636a0841ea9c5b28a4223c0cd3677eede53 (diff)
downloadbcfg2-e9e94e78bb52ca2ec36e3f3402dbde3f8289cdf3.tar.gz
bcfg2-e9e94e78bb52ca2ec36e3f3402dbde3f8289cdf3.tar.bz2
bcfg2-e9e94e78bb52ca2ec36e3f3402dbde3f8289cdf3.zip
added support for alternate metadata plugins in bcfg2-admin
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4845 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Server/Admin/Client.py76
-rw-r--r--src/lib/Server/Admin/Viz.py21
-rw-r--r--src/lib/Server/Admin/__init__.py31
-rw-r--r--src/lib/Server/Plugin.py10
-rw-r--r--src/lib/Server/Plugins/BB.py58
-rw-r--r--src/lib/Server/Plugins/Metadata.py65
6 files changed, 183 insertions, 78 deletions
diff --git a/src/lib/Server/Admin/Client.py b/src/lib/Server/Admin/Client.py
index c51ac1598..1f784a4f2 100644
--- a/src/lib/Server/Admin/Client.py
+++ b/src/lib/Server/Admin/Client.py
@@ -1,25 +1,14 @@
-import lxml.etree
-import fcntl
import Bcfg2.Server.Admin
+from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError
-class Client(Bcfg2.Server.Admin.Mode):
+class Client(Bcfg2.Server.Admin.MetadataCore):
__shorthelp__ = 'bcfg2-admin client add <client> attr1=val1 attr2=val2\nbcfg2-admin client del <client>'
__longhelp__ = __shorthelp__ + '\n\tCreate or delete client entries'
def __init__(self, configfile):
- Bcfg2.Server.Admin.Mode.__init__(self, configfile)
- try:
- self.bcore = Bcfg2.Server.Core.Core(self.get_repo_path(), [],
- [], [], 'foo', False, 'UTF-8')
- except Bcfg2.Server.Core.CoreInitError, msg:
- self.errExit("Core load failed because %s" % msg)
- [self.bcore.fam.Service() for _ in range(5)]
- while self.bcore.fam.Service():
- pass
- self.tree = lxml.etree.parse(self.get_repo_path() + "/Metadata/clients.xml")
- self.root = self.tree.getroot()
+ Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile)
def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
+ Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
if len(args) == 0:
self.errExit("Client mode requires at least one argument: <add> or <delete>")
if "-h" in args:
@@ -30,55 +19,22 @@ class Client(Bcfg2.Server.Admin.Mode):
attr_d = {}
for i in args[2:]:
attr, val = i.split('=', 1)
- if attr not in ['profile', 'uuid', 'password', 'address',
- 'secure', 'location']:
+ if attr not in ['profile', 'user', 'state', 'image',
+ 'action']:
print "Attribute %s unknown" % attr
raise SystemExit(1)
attr_d[attr] = val
- self.add_client(args[1], attr_d)
+ try:
+ self.metadata.add_client(args[1], attr_d)
+ except MetadataConsistencyError:
+ print "Error in adding client"
+ raise SystemExit(1)
elif args[0] in ['delete', 'remove', 'del', 'rm']:
- self.del_client(args[1])
+ try:
+ self.metadata.remove_client(args[1])
+ except MetadataConsistencyError:
+ print "Error in deleting client"
+ raise SystemExit(1)
else:
print "No command specified"
raise SystemExit(1)
- client_tree = open(self.get_repo_path() + "/Metadata/clients.xml","w")
- fd = client_tree.fileno()
- while True:
- try:
- fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- continue
- else:
- break
- self.tree.write(client_tree)
- fcntl.lockf(fd, fcntl.LOCK_UN)
- client_tree.close()
-
- def add_client(self, client, attrs):
- '''add a new client'''
- element = lxml.etree.Element("Client", name=client)
- for key, val in attrs.iteritems():
- element.set(key, val)
- node = self.search_client(client)
- if node != None:
- print "Client \"%s\" already exists" % (client)
- raise SystemExit(1)
- self.root.append(element)
-
- def del_client(self, client):
- '''delete an existing client'''
- node = self.search_client(client)
- if node == None:
- print "Client \"%s\" not found" % (client)
- raise SystemExit(1)
- self.root.remove(node)
-
- def search_client(self, client):
- '''find a client'''
- for node in self.root:
- if node.attrib["name"] == client:
- return node
- for child in node:
- if child.tag == "Alias" and child.attrib["name"] == client:
- return node
- return None
diff --git a/src/lib/Server/Admin/Viz.py b/src/lib/Server/Admin/Viz.py
index dfc8b3392..d2eeb3370 100644
--- a/src/lib/Server/Admin/Viz.py
+++ b/src/lib/Server/Admin/Viz.py
@@ -2,7 +2,7 @@
import getopt, popen2, lxml.etree
import Bcfg2.Server.Admin
-class Viz(Bcfg2.Server.Admin.Mode):
+class Viz(Bcfg2.Server.Admin.MetadataCore):
__shorthelp__ = '''bcfg2-admin viz [--includehosts] [--includebundles] [--includekey] [-o output.png] [--raw]'''
__longhelp__ = __shorthelp__ + '\n\tProduce graphviz diagrams of metadata structures'
@@ -11,10 +11,10 @@ class Viz(Bcfg2.Server.Admin.Mode):
'green1', 'blue1', 'yellow1', 'darkturquoise', 'gray66']
def __init__(self, cfile):
- Bcfg2.Server.Admin.Mode.__init__(self, cfile)
+ Bcfg2.Server.Admin.MetadataCore.__init__(self, cfile)
def __call__(self, args):
- Bcfg2.Server.Admin.Mode.__call__(self, args)
+ Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
# First get options to the 'viz' subcommand
try:
opts, args = getopt.getopt(args, 'rhbko:',
@@ -48,9 +48,7 @@ class Viz(Bcfg2.Server.Admin.Mode):
def Visualize(self, repopath, raw=False, hosts=False,
bundles=False, key=False, output=False):
'''Build visualization of groups file'''
- groupdata = lxml.etree.parse(repopath + '/Metadata/groups.xml')
- groupdata.xinclude()
- groups = groupdata.getroot()
+ groups = self.metadata.get_groups()
if raw:
cmd = "dd bs=4M"
if output:
@@ -78,13 +76,12 @@ class Viz(Bcfg2.Server.Admin.Mode):
dotpipe.tochild.write('\trankdir="LR";\n')
if hosts:
- clients = lxml.etree.parse(repopath + \
- '/Metadata/clients.xml').getroot()
- for client in clients.findall('Client'):
- if instances.has_key(client.get('profile')):
- instances[client.get('profile')].append(client.get('name'))
+ clients = self.metadata.clients
+ for client, profile in clients.iteritems():
+ if instances.has_key(profile):
+ instances[profile].append(client)
else:
- instances[client.get('profile')] = [client.get('name')]
+ instances[profile] = [client]
for profile, clist in instances.iteritems():
clist.sort()
dotpipe.tochild.write(
diff --git a/src/lib/Server/Admin/__init__.py b/src/lib/Server/Admin/__init__.py
index cff9eec6a..a650f64e6 100644
--- a/src/lib/Server/Admin/__init__.py
+++ b/src/lib/Server/Admin/__init__.py
@@ -3,8 +3,8 @@ __revision__ = '$Revision$'
__all__ = ['Mode', 'Client', 'Compare', 'Fingerprint', 'Init', 'Minestruct',
'Pull', 'Query', 'Tidy', 'Viz']
-import ConfigParser, lxml.etree, logging
-
+import ConfigParser, lxml.etree, logging, sys
+import Bcfg2.Server.Core
class ModeOperationError(Exception):
pass
@@ -46,3 +46,30 @@ class Mode(object):
self.errExit("Could not find stats for client %s" % (client))
return hostent[0]
+class MetadataCore(Mode):
+ '''Base class for admin-modes that handle metadata'''
+ def __init__(self, configfile):
+ Mode.__init__(self, configfile)
+ options = {'plugins': Bcfg2.Options.SERVER_PLUGINS,
+ 'structures': Bcfg2.Options.SERVER_STRUCTURES,
+ 'generators': Bcfg2.Options.SERVER_GENERATORS}
+ setup = Bcfg2.Options.OptionParser(options)
+ setup.parse(sys.argv[1:])
+ plugins = [plugin for plugin in setup['plugins']
+ if plugin in ('BB', 'Metadata')]
+ structures = [structure for structure in setup['structures']
+ if structure in ('BB', 'Metadata')]
+ generators = [generator for generator in setup['generators']
+ if generator in ('BB', 'Metadata')]
+ try:
+ self.bcore = Bcfg2.Server.Core.Core(self.get_repo_path(), plugins,
+ structures, generators, 'foo', False, 'UTF-8')
+ except Bcfg2.Server.Core.CoreInitError, msg:
+ self.errExit("Core load failed because %s" % msg)
+ [self.bcore.fam.Service() for _ in range(5)]
+ while self.bcore.fam.Service():
+ pass
+ self.metadata = self.bcore.metadata
+
+ def __call__(self, args):
+ Bcfg2.Server.Admin.Mode.__call__(self, args)
diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py
index 0f9464a47..114e0b039 100644
--- a/src/lib/Server/Plugin.py
+++ b/src/lib/Server/Plugin.py
@@ -79,7 +79,15 @@ class StructurePlugin(Plugin):
class MetadataPlugin(Plugin):
'''Signal metadata capabilities for this plugin'''
- pass
+ def add_client(self, client_name, attribs):
+ '''add client'''
+ pass
+ def remove_client(self, client_name):
+ '''remove client'''
+ pass
+ def get_groups(self):
+ '''get groups xml tree'''
+ pass
class ProbingPlugin(Plugin):
'''Signal probe capability for this plugin'''
diff --git a/src/lib/Server/Plugins/BB.py b/src/lib/Server/Plugins/BB.py
index af3f3d379..50badb7a3 100644
--- a/src/lib/Server/Plugins/BB.py
+++ b/src/lib/Server/Plugins/BB.py
@@ -2,8 +2,9 @@
import Bcfg2.Server.Plugin
import lxml.etree
-import sys, os
+import os, fcntl
from socket import gethostbyname
+from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError
# map of keywords to profiles
# probably need a better way to do this
@@ -44,6 +45,56 @@ class BB(Bcfg2.Server.Plugin.GeneratorPlugin,
self.nodes = {}
self.dhcpd_loaded = False
self.need_update = False
+
+ def get_groups(self):
+ '''get groups xml tree'''
+ groups_tree = lxml.etree.parse(self.data + "/groups.xml")
+ root = groups_tree.getroot()
+ return root
+
+ def remove_client(self, client_name):
+ '''Remove client from bb.xml'''
+ bb_tree = lxml.etree.parse(self.data + "/bb.xml")
+ root = bb_tree.getroot()
+ if DOMAIN_SUFFIX in client_name:
+ client_name = client_name.split('.')[0]
+ if len(root.xpath(".//Node[@name='%s']" % client_name)) != 1:
+ self.logger.error("Client \"%s\" does not exist" % client_name)
+ raise MetadataConsistencyError
+ else:
+ root.remove(root.xpath(".//Node[@name='%s']" % client_name)[0])
+ self.write_metadata(bb_tree)
+
+ def add_client(self, client_name, attribs):
+ '''Add a client to bb.xml'''
+ bb_tree = lxml.etree.parse(self.data + "/bb.xml")
+ root = bb_tree.getroot()
+ if DOMAIN_SUFFIX in client_name:
+ client_name = client_name.split('.')[0]
+ if len(root.xpath(".//Node[@name='%s']" % client_name)) != 0:
+ self.logger.error("Client \"%s\" already exists" % client_name)
+ raise MetadataConsistencyError
+ else:
+ element = lxml.etree.Element("Client", name=client_name)
+ for key, val in attribs.iteritems():
+ element.set(key, val)
+ root.append(element)
+ self.write_metadata(bb_tree)
+
+ def write_metadata(self, tree):
+ '''write metadata back to bb.xml'''
+ data_file = open(self.data + "/bb.xml","w")
+ fd = data_file.fileno()
+ while True:
+ try:
+ fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ except IOError:
+ continue
+ else:
+ break
+ tree.write(data_file)
+ fcntl.lockf(fd, fcntl.LOCK_UN)
+ data_file.close()
def gen_dhcpd(self, entry, metadata):
'''Generate dhcpd.conf to serve to dhcp server'''
@@ -149,7 +200,7 @@ class BB(Bcfg2.Server.Plugin.GeneratorPlugin,
if node.attrib['name'] == metadata.hostname.split('.')[0]:
node.attrib['action'] = action
break
- bb_tree.write("%s/%s" % (self.data, 'bb.xml'))
+ self.write_metadata(bb_tree)
return bundles
def HandleEvent(self, event=None):
@@ -209,6 +260,9 @@ class BB(Bcfg2.Server.Plugin.GeneratorPlugin,
self.nodes[host] = node_dict
# update symlinks and /etc/dhcp3/dhcpd.conf
if self.write_to_disk:
+ if not node_dict.has_key('mac'):
+ self.logger.error("no mac address for %s" % host)
+ continue
mac = node_dict['mac'].replace(':','-').lower()
linkname = "/tftpboot/pxelinux.cfg/01-%s" % (mac)
try:
diff --git a/src/lib/Server/Plugins/Metadata.py b/src/lib/Server/Plugins/Metadata.py
index 345f14b54..d28d75530 100644
--- a/src/lib/Server/Plugins/Metadata.py
+++ b/src/lib/Server/Plugins/Metadata.py
@@ -121,7 +121,70 @@ class Metadata(Bcfg2.Server.Plugin.MetadataPlugin,
self.extra = {'groups.xml':[], 'clients.xml':[]}
self.password = core.password
self.load_probedata()
-
+
+ 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_client(self, client_name, tree):
+ '''find a client'''
+ for node in tree:
+ if node.attrib["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, root)
+ 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 remove_client(self, client_name):
+ '''Remove a client'''
+ tree = lxml.etree.parse(self.data + "/clients.xml")
+ root = tree.getroot()
+ node = self.search_client(client_name, root)
+ if node == None:
+ self.logger.error("Client \"%s\" not found" % (client_name))
+ raise MetadataConsistencyError
+ root.remove(node)
+ 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]