diff --git a/trunk/daemon/sbin/core-manage b/trunk/daemon/sbin/core-manage new file mode 100755 index 00000000..522584a4 --- /dev/null +++ b/trunk/daemon/sbin/core-manage @@ -0,0 +1,210 @@ +#!/usr/bin/env python +# +# CORE +# Copyright (c)2014 the Boeing Company. +# See the LICENSE file included in this distribution. +# +# author: Jeff Ahrenholz +# +''' +core-manage: Helper tool to add, remove, or check for services and models in +a CORE installation. +''' + +import os +import sys +import ast +import optparse + +from core import pycore +from core.constants import CORE_CONF_DIR + +# core-manage add emane_model RfPipeNew +# core-manage add service MyService + +class FileUpdater(object): + ''' Helper class for changing configuration files. + ''' + actions = ("add", "remove", "check") + targets = ("service", "model") + + def __init__(self, action, target, data, verbose=False): + ''' + ''' + self.action = action + self.target = target + self.data = data + self.verbose = verbose + self.search, self.filename = self.get_filename(target) + + def process(self): + ''' Invoke update_file() using a helper method depending on target. + ''' + if self.verbose: + txt = "Updating" + if self.action == "check": + txt = "Checking" + sys.stdout.write("%s file: '%s'\n" % (txt, self.filename)) + + if self.target == "service": + r = self.update_file(fn=self.update_services) + elif self.target == "model": + r = self.update_file(fn=self.update_emane_models) + + if self.verbose: + txt = "" + if not r: + txt = "NOT " + if self.action == "check": + sys.stdout.write("String %sfound.\n" % txt) + else: + sys.stdout.write("File %supdated.\n" % txt) + + return r + + def update_services(self, line): + ''' Modify the __init__.py file having this format: + __all__ = ["quagga", "nrl", "xorp", "bird", ] + Returns True or False when "check" is the action, a modified line + otherwise. + ''' + line = line.strip('\n') + key, valstr = line.split('= ') + vals = ast.literal_eval(valstr) + r = self.update_keyvals(key, vals) + if self.action == "check": + return r + valstr = '%s' % r + return '= '.join([key, valstr]) + '\n' + + + def update_emane_models(self, line): + ''' Modify the core.conf file having this format: + emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass + Returns True or False when "check" is the action, a modified line + otherwise. + ''' + line = line.strip('\n') + key, valstr = line.split('= ') + vals = valstr.split(', ') + r = self.update_keyvals(key, vals) + if self.action == "check": + return r + valstr = ', '.join(r) + return '= '.join([key, valstr]) + '\n' + + def update_keyvals(self, key, vals): + ''' Perform self.action on (key, vals). + Returns True or False when "check" is the action, a modified line + otherwise. + ''' + if self.action == "check": + if self.data in vals: + return True + else: + return False + elif self.action == "add": + if self.data not in vals: + vals.append(self.data) + elif self.action == "remove": + try: + vals.remove(self.data) + except ValueError: + pass + return vals + + @staticmethod + def get_filename(target): + ''' Return search string and filename based on target. + ''' + if target == "service": + pypath = os.path.dirname(pycore.__file__) + filename = os.path.join(pypath, "services", "__init__.py") + search = "__all__ =" + elif target == "model": + filename = os.path.join(CORE_CONF_DIR, "core.conf") + search = "emane_models =" + else: + raise ValueError, "unknown target" + if not os.path.exists(filename): + raise ValueError, "file '%s' does not exist" % filename + return search, filename + + def update_file(self, fn=None): + ''' Open a file and search for self.search, invoking the supplied + function on the matching line. Write file changes if necessary. + Returns True if the file has changed (or action is "check" and the + search string is found), False otherwise. + ''' + changed = False + output = "" # this accumulates output, assumes input is small + with open(self.filename, "r") as f: + for line in f: + if line[:len(self.search)] == self.search: + r = fn(line) # line may be modified by fn() here + if self.action == "check": + return r + else: + if line != r: + changed = True + line = r + output += line + if changed: + with open(self.filename, "w") as f: + f.write(output) + + return changed + + +def main(): + usagestr = "usage: %prog [-h] [options] \n" + usagestr += "\nHelper tool to add, remove, or check for " + usagestr += "services and models in a CORE\ninstallation.\n" + usagestr += "\nExamples:\n %prog add service newrouting" + usagestr += "\n %prog -v check model RfPipe\n" + usagestr += "\nArguments:\n should be one of: %s" % \ + ', '.join(FileUpdater.actions) + usagestr += "\n should be one of: %s" % \ + ', '.join(FileUpdater.targets) + usagestr += "\n is the text to %s" % \ + ', '.join(FileUpdater.actions) + parser = optparse.OptionParser(usage = usagestr) + parser.set_defaults(verbose = False,) + + parser.add_option("-v", "--verbose", dest = "verbose", action="store_true", + help = "be verbose when performing action") + + def usage(msg = None, err = 0): + sys.stdout.write("\n") + if msg: + sys.stdout.write(msg + "\n\n") + parser.print_help() + sys.exit(err) + + (options, args) = parser.parse_args() + + if len(args) != 3: + usage("Missing required arguments!", 1) + + action = args[0] + if action not in FileUpdater.actions: + usage("invalid action '%s'" % action, 1) + + target = args[1] + if target not in FileUpdater.targets: + usage("invalid target '%s'" % target, 1) + + data = args[2] + + try: + up = FileUpdater(action, target, data, verbose=options.verbose) + r = up.process() + except Exception, e: + sys.stderr.write("Exception: %s\n" % e) + sys.exit(1) + if not r: + sys.exit(1) + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/trunk/doc/man/Makefile.am b/trunk/doc/man/Makefile.am index 30405928..d08c5445 100755 --- a/trunk/doc/man/Makefile.am +++ b/trunk/doc/man/Makefile.am @@ -12,7 +12,7 @@ if WANT_GUI endif if WANT_DAEMON DAEMON_MANS = vnoded.1 vcmd.1 netns.1 core-daemon.1 coresendmsg.1 \ - core-cleanup.1 core-xen-cleanup.1 + core-cleanup.1 core-xen-cleanup.1 core-manage.1 endif man_MANS = $(GUI_MANS) $(DAEMON_MANS) @@ -26,6 +26,7 @@ generate-mans: $(HELP2MAN) --version-string=$(CORE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/sbin/coresendmsg -o coresendmsg.1.new $(HELP2MAN) --version-string=$(CORE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/sbin/core-cleanup -o core-cleanup.1.new $(HELP2MAN) --version-string=$(CORE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/sbin/core-xen-cleanup -o core-xen-cleanup.1.new + $(HELP2MAN) --version-string=$(CORE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/sbin/core-manage -o core-manage.1.new .PHONY: diff diff: diff --git a/trunk/doc/man/core-manage.1 b/trunk/doc/man/core-manage.1 new file mode 100644 index 00000000..fd300bf7 --- /dev/null +++ b/trunk/doc/man/core-manage.1 @@ -0,0 +1,28 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4. +.TH CORE-MANAGE "1" "July 2014" "CORE" "User Commands" +.SH NAME +core-manage \- helper tool to add, remove, or check for services and models in a CORE installation. +.SH SYNOPSIS +.B core-manage +[\fI-h\fR] [\fIoptions\fR] \fI \fR +.SH DESCRIPTION +.TP + should be one of: add, remove, check +.TP + should be one of: service, model +.TP + is the text to add, remove, check +.SH OPTIONS +.TP +\fB\-h\fR, \fB\-\-help\fR +show this help message and exit +.TP +\fB\-v\fR, \fB\-\-verbose\fR +be verbose when performing action +.SH EXAMPLES +.TP +core\-manage add service newrouting +.TP +core\-manage \fB\-v\fR check model RfPipe +.SH "SEE ALSO" +.BR core-daemon(1) diff --git a/trunk/packaging/rpm/core.spec.in b/trunk/packaging/rpm/core.spec.in index 451019ac..3325c6c7 100644 --- a/trunk/packaging/rpm/core.spec.in +++ b/trunk/packaging/rpm/core.spec.in @@ -338,6 +338,7 @@ sed -i 's/emane_realtime = True/emane_realtime = False/' /etc/core/core.conf %{python_sitelib}/core/xen/xen.py* %{_sbindir}/core-cleanup %{_sbindir}/core-daemon +%{_sbindir}/core-manage %{_sbindir}/coresendmsg %{_sbindir}/core-xen-cleanup %{_sbindir}/netns