summaryrefslogtreecommitdiffstats
path: root/build/lib/Bcfg2/Server/Admin/Pull.py
diff options
context:
space:
mode:
Diffstat (limited to 'build/lib/Bcfg2/Server/Admin/Pull.py')
-rw-r--r--build/lib/Bcfg2/Server/Admin/Pull.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/build/lib/Bcfg2/Server/Admin/Pull.py b/build/lib/Bcfg2/Server/Admin/Pull.py
new file mode 100644
index 000000000..aa732c67f
--- /dev/null
+++ b/build/lib/Bcfg2/Server/Admin/Pull.py
@@ -0,0 +1,138 @@
+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