[CalendarServer-changes] [15034] CalendarServer/trunk/calendarserver/tools

source_changes at macosforge.org source_changes at macosforge.org
Thu Aug 6 14:04:52 PDT 2015


Revision: 15034
          http://trac.calendarserver.org//changeset/15034
Author:   sagen at apple.com
Date:     2015-08-06 14:04:52 -0700 (Thu, 06 Aug 2015)
Log Message:
-----------
calendarserver_config now has --logging and --accounting options

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/config.py
    CalendarServer/trunk/calendarserver/tools/test/test_config.py
    CalendarServer/trunk/calendarserver/tools/test/test_gateway.py

Modified: CalendarServer/trunk/calendarserver/tools/config.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/config.py	2015-08-05 22:37:53 UTC (rev 15033)
+++ CalendarServer/trunk/calendarserver/tools/config.py	2015-08-06 21:04:52 UTC (rev 15034)
@@ -43,6 +43,7 @@
 
 
 WRITABLE_CONFIG_KEYS = [
+    "AccountingCategories",
     "Authentication.Basic.AllowedOverWireUnencrypted",
     "Authentication.Basic.Enabled",
     "Authentication.Digest.AllowedOverWireUnencrypted",
@@ -83,8 +84,21 @@
     "ServerRoot",
 ]
 
+ACCOUNTING_CATEGORIES = {
+    "http": ("HTTP",),
+    "itip": ("iTIP", "iTIP-VFREEBUSY",),
+    "implicit": ("Implicit Errors",),
+    "autoscheduling": ("AutoScheduling",),
+    "ischedule": ("iSchedule",),
+    "migration": ("migration",),
+}
 
+LOGGING_CATEGORIES = {
+    "directory": ("twext^who", "txdav^who",),
+    "imip": ("txdav^caldav^datastore^scheduling^imip",),
+}
 
+
 def usage(e=None):
     if e:
         print(e)
@@ -95,8 +109,10 @@
     print("")
     print("Print the value of the given config key.")
     print("options:")
+    print("  -a --accounting: Specify accounting categories (combinations of http, itip, implicit, autoscheduling, ischedule, migration, or off)")
     print("  -h --help: print this help and exit")
     print("  -f --config: Specify caldavd.plist configuration path")
+    print("  -l --logging: Specify logging categories (combinations of directory, imip, or default)")
     print("  -r --restart: Restart the calendar service")
     print("  --start: Start the calendar service and agent")
     print("  --stop: Stop the calendar service and agent")
@@ -125,13 +141,15 @@
 
     try:
         (optargs, args) = getopt(
-            sys.argv[1:], "hf:rw:", [
+            sys.argv[1:], "hf:rw:a:l:", [
                 "help",
                 "config=",
                 "writeconfig=",
                 "restart",
                 "start",
                 "stop",
+                "accounting=",
+                "logging=",
             ],
         )
     except GetoptError, e:
@@ -139,6 +157,8 @@
 
     configFileName = DEFAULT_CONFIG_FILE
     writeConfigFileName = ""
+    accountingCategories = None
+    loggingCategories = None
     doStop = False
     doStart = False
     doRestart = False
@@ -153,6 +173,12 @@
         elif opt in ("-w", "--writeconfig"):
             writeConfigFileName = arg
 
+        elif opt in ("-a", "--accounting"):
+            accountingCategories = arg.split(",")
+
+        elif opt in ("-l", "--logging"):
+            loggingCategories = arg.split(",")
+
         if opt == "--stop":
             doStop = True
 
@@ -198,6 +224,24 @@
     writable = WritableConfig(config, writeConfigFileName)
     writable.read()
 
+    # Convert logging categories to actual config key changes
+    if loggingCategories is not None:
+        args = ["LogLevels="]
+        if loggingCategories != ["default"]:
+            for cat in loggingCategories:
+                if cat in LOGGING_CATEGORIES:
+                    for moduleName in LOGGING_CATEGORIES[cat]:
+                        args.append("LogLevels.{}=debug".format(moduleName))
+
+    # Convert accounting categories to actual config key changes
+    if accountingCategories is not None:
+        args = ["AccountingCategories="]
+        if accountingCategories != ["off"]:
+            for cat in accountingCategories:
+                if cat in ACCOUNTING_CATEGORIES:
+                    for key in ACCOUNTING_CATEGORIES[cat]:
+                        args.append("AccountingCategories.{}=True".format(key))
+
     processArgs(writable, args)
 
 
@@ -265,8 +309,12 @@
             if "=" in configKey:
                 # This is an assignment
                 configKey, stringValue = configKey.split("=")
-                value = writable.convertToValue(stringValue)
-                writable.set({configKey: value})
+                if stringValue:
+                    value = writable.convertToValue(stringValue)
+                    valueDict = setKeyPath({}, configKey, value)
+                    writable.set(valueDict)
+                else:
+                    writable.delete(configKey)
             else:
                 # This is a read
                 c = config
@@ -416,7 +464,14 @@
     @return: parent
     """
     original = parent
-    parts = keyPath.split(".")
+
+    # Embedded ^ should be replaced by .
+    # That way, we can still use . as key path separator even though sometimes
+    # a key part wants to have a . in it (such as a LogLevels module).
+    # For example:  LogLevels.twext^who, will get converted to a "LogLevels"
+    # dict containing a the key "twext.who"
+    parts = [p.replace("^", ".") for p in keyPath.split(".")]
+
     for part in parts[:-1]:
         child = parent.get(part, None)
         if child is None:
@@ -531,6 +586,20 @@
         self.dirty = True
 
 
+    def delete(self, key):
+        """
+        Deletes the specified key
+
+        @param key: the key to delete
+        @type key: C{str}
+        """
+        try:
+            del self.currentConfigSubset[key]
+            self.dirty = True
+        except:
+            pass
+
+
     def read(self):
         """
         Reads in the data contained in the writable plist file.
@@ -568,7 +637,7 @@
     def convertToValue(cls, string):
         """
         Inspect string and convert the value into an appropriate Python data type
-        TODO: change this to look at actual types definied within stdconfig
+        TODO: change this to look at actual types defined within stdconfig
         """
         if "." in string:
             try:

Modified: CalendarServer/trunk/calendarserver/tools/test/test_config.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_config.py	2015-08-05 22:37:53 UTC (rev 15033)
+++ CalendarServer/trunk/calendarserver/tools/test/test_config.py	2015-08-06 21:04:52 UTC (rev 15034)
@@ -171,6 +171,247 @@
         self.assertEquals(results["error"], "Unknown command 'bogus'")
 
 
+    @inlineCallbacks
+    def test_commandLineArgs(self):
+        """
+        Verify commandline assignments works
+        """
+
+        # Check current values
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(results["result"]["DefaultLogLevel"], "warn")
+        self.assertEquals(results["result"]["Scheduling"]["iMIP"]["Enabled"], False)
+
+        # Set a single-level key and a multi-level key
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["DefaultLogLevel=debug", "Scheduling.iMIP.Enabled=True"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(results["result"]["DefaultLogLevel"], "debug")
+        self.assertEquals(results["result"]["Scheduling"]["iMIP"]["Enabled"], True)
+        self.assertEquals(results["result"]["LogLevels"], {})
+
+        # Directly set some LogLevels sub-keys
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["LogLevels.testing=debug", "LogLevels.testing2=warn"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["LogLevels"],
+            {"testing": "debug", "testing2" : "warn"}
+        )
+
+        # Test that setting additional sub-keys retains previous sub-keys
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["LogLevels.testing3=info", "LogLevels.testing4=warn"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["LogLevels"],
+            {"testing": "debug", "testing2" : "warn", "testing3": "info", "testing4" : "warn"}
+        )
+
+        # Test that an empty value deletes the key
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["LogLevels="],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["LogLevels"], # now an empty dict
+            {}
+        )
+
+
+    @inlineCallbacks
+    def test_loggingCategories(self):
+        """
+        Verify logging categories get mapped to the correct python module names
+        """
+
+
+        # Check existing values
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(results["result"]["LogLevels"], {})
+
+        # Set to directory and imip
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["--logging=directory,imip"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["LogLevels"],
+            {
+                "twext.who": "debug",
+                "txdav.who": "debug",
+                "txdav.caldav.datastore.scheduling.imip": "debug",
+            }
+        )
+
+        # Set up to imip, and the directory modules should go away
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["--logging=imip"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["LogLevels"],
+            {
+                "txdav.caldav.datastore.scheduling.imip": "debug",
+            }
+        )
+
+        # Set to default, and all modules should go away
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["--logging=default"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["LogLevels"], {}
+        )
+
+
+    @inlineCallbacks
+    def test_accountingCategories(self):
+        """
+        Verify accounting categories get mapped to the correct keys
+        """
+        # Check existing values
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["AccountingCategories"],
+            {
+                'AutoScheduling': False,
+                'HTTP': False,
+                'Implicit Errors': False,
+                'iSchedule': False,
+                'iTIP': False,
+                'iTIP-VFREEBUSY': False,
+                'migration': False,
+            }
+        )
+
+        # Set to http and itip
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["--accounting=http,itip"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["AccountingCategories"],
+            {
+                'AutoScheduling': False,
+                'HTTP': True,
+                'Implicit Errors': False,
+                'iSchedule': False,
+                'iTIP': True,
+                'iTIP-VFREEBUSY': True,
+                'migration': False,
+            }
+        )
+
+        # Set to off, so all are off
+
+        results = yield self.runCommand(
+            None,
+            script="calendarserver_config",
+            additionalArgs=["--accounting=off"],
+            parseOutput=False
+        )
+
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config")
+
+        self.assertEquals(
+            results["result"]["AccountingCategories"],
+            {
+                'AutoScheduling': False,
+                'HTTP': False,
+                'Implicit Errors': False,
+                'iSchedule': False,
+                'iTIP': False,
+                'iTIP-VFREEBUSY': False,
+                'migration': False,
+            }
+        )
+
+
+
+
     def test_keyPath(self):
         d = ConfigDict()
         setKeyPath(d, "one", "A")

Modified: CalendarServer/trunk/calendarserver/tools/test/test_gateway.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_gateway.py	2015-08-05 22:37:53 UTC (rev 15033)
+++ CalendarServer/trunk/calendarserver/tools/test/test_gateway.py	2015-08-06 21:04:52 UTC (rev 15034)
@@ -144,7 +144,8 @@
 
     @inlineCallbacks
     def runCommand(
-        self, command, error=False, script="calendarserver_command_gateway"
+        self, command, error=False, script="calendarserver_command_gateway",
+        additionalArgs=None, parseOutput=True
     ):
         """
         Run the given command by feeding it as standard input to
@@ -163,18 +164,24 @@
         if error:
             args.append("--error")
 
+        if additionalArgs:
+            args.extend(additionalArgs)
+
         cwd = sourceRoot
 
         deferred = Deferred()
         reactor.spawnProcess(CapturingProcessProtocol(deferred, command), cmd, args, env=os.environ, path=cwd)
         output = yield deferred
-        try:
-            plist = readPlistFromString(output)
-        except xml.parsers.expat.ExpatError, e:
-            print("Error (%s) parsing (%s)" % (e, output))
-            raise
+        if parseOutput:
+            try:
+                plist = readPlistFromString(output)
+                returnValue(plist)
+            except xml.parsers.expat.ExpatError, e:
+                print("Error (%s) parsing (%s)" % (e, output))
+                raise
+        else:
+            returnValue(output)
 
-        returnValue(plist)
 
 
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150806/d3a0c001/attachment-0001.html>


More information about the calendarserver-changes mailing list