From c4de45d84a95ec7e3b61780eae6a591885fc9bbf Mon Sep 17 00:00:00 2001 From: Andrew Brestick Date: Thu, 19 Jun 2008 15:11:06 +0000 Subject: Resolves ticket #541 and fixes client adding/deleting git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4701 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Server/Admin/Client.py | 55 +++++++++++++++++++++++++++----------- src/lib/Server/Admin/Query.py | 18 +++++++++++-- src/lib/Server/Plugins/Metadata.py | 19 ++++++++++--- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/lib/Server/Admin/Client.py b/src/lib/Server/Admin/Client.py index 9d75a6ab3..c4f931350 100644 --- a/src/lib/Server/Admin/Client.py +++ b/src/lib/Server/Admin/Client.py @@ -1,50 +1,75 @@ import lxml.etree - +import fcntl import Bcfg2.Server.Admin class Client(Bcfg2.Server.Admin.Mode): __shorthelp__ = 'bcfg2-admin client add attr1=val1 attr2=val2\nbcfg2-admin client del ' __longhelp__ = __shorthelp__ + '\n\tCreate or delete client entries' - def __init__(self): - Bcfg2.Server.Admin.Mode.__init__(self) + def __init__(self, configfile): + Bcfg2.Server.Admin.Mode.__init__(self, configfile) try: - self.bcore = Bcfg2.Server.Core.Core(self.repo, [], ['Metadata'], + self.bcore = Bcfg2.Server.Core.Core(self.get_repo_path(), [], ['Metadata'], 'foo', False) except Bcfg2.Server.Core.CoreInitError, msg: self.errExit("Core load failed because %s" % msg) - [bcore.fam.Service() for _ in range(5)] - while bcore.fam.Service(): + [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() def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) if args[0] == 'add': attr_d = {} - for i in args[1:]: + for i in args[2:]: attr, val = i.split('=', 1) if attr not in ['profile', 'uuid', 'password', 'address', 'secure', 'location']: print "Attribute %s unknown" % attr raise SystemExit(1) attr_d[attr] = val - self.AddClient(args[1], attr_d) + self.add_client(args[1], attr_d) elif args[0] in ['delete', 'remove', 'del', 'rm']: - self.DelClient(args[1]) + self.del_client(args[1]) else: print "No command specified" raise SystemExit(1) - self.tree.write(self.get_repo_path() + '/Metadata/clients.xml') + 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 AddClient(self, client, attrs): + def add_client(self, client, attrs): '''add a new client''' - # FIXME add a dup client check 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 DelClient(self, client): + def del_client(self, client): '''delete an existing client''' - # FIXME DelClient not implemented - pass + 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 + return None diff --git a/src/lib/Server/Admin/Query.py b/src/lib/Server/Admin/Query.py index 0c0659213..a5e2a977e 100644 --- a/src/lib/Server/Admin/Query.py +++ b/src/lib/Server/Admin/Query.py @@ -1,7 +1,7 @@ import Bcfg2.Server.Admin, Bcfg2.Logging, logging class Query(Bcfg2.Server.Admin.Mode): - __shorthelp__ = 'bcfg2-admin query [-n] [-c] g=group p=profile' + __shorthelp__ = 'bcfg2-admin query [-n] [-c] [-f filename] g=group p=profile' __longhelp__ = __shorthelp__ + '\n\tQuery clients' def __init__(self, cfile): logging.root.setLevel(100) @@ -22,9 +22,18 @@ class Query(Bcfg2.Server.Admin.Mode): 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: @@ -37,9 +46,14 @@ class Query(Bcfg2.Server.Admin.Mode): self.meta.groups[self.meta.clients[c]][1] or v in self.meta.cgroups.get(c, [])] 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/src/lib/Server/Plugins/Metadata.py b/src/lib/Server/Plugins/Metadata.py index f79aa4d03..67959c968 100644 --- a/src/lib/Server/Plugins/Metadata.py +++ b/src/lib/Server/Plugins/Metadata.py @@ -1,7 +1,7 @@ '''This file stores persistent metadata for the BCFG Configuration Repository''' __revision__ = '$Revision$' -import lxml.etree, re, socket, time +import lxml.etree, re, socket, time, fcntl, copy import Bcfg2.Server.Plugin class MetadataConsistencyError(Exception): @@ -267,9 +267,20 @@ class Metadata(Bcfg2.Server.Plugin.MetadataPlugin, except IOError: self.logger.error("Failed to write clients.xml") raise MetadataRuntimeError + fd = datafile.fileno() + while self.locked(fd) == True: + pass datafile.write(lxml.etree.tostring(self.clientdata.getroot())) + fcntl.lockf(fd, fcntl.LOCK_UN) datafile.close() - + + def locked(self, fd): + try: + fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError: + return True + return False + def write_probedata(self): '''write probe data out for use with bcfg2-info''' if self.pdirty: @@ -362,8 +373,10 @@ class Metadata(Bcfg2.Server.Plugin.MetadataPlugin, [newbundles.append(b) for b in nbundles if b not in newbundles] [newgroups.append(g) for g in ngroups if g not in newgroups] newcategories.update(ncategories) + groupscopy = copy.deepcopy(self.groups) + profilescopy = copy.deepcopy(self.profiles) return ClientMetadata(client, newgroups, newbundles, newcategories, - probed, uuid, password, self) + probed, uuid, password, (groupscopy, profilescopy)) def GetProbes(self, meta, force=False): '''Return a set of probes for execution on client''' -- cgit v1.2.3-1-g7c22