OwlCyberSecurity - MANAGER
Edit File: cmdline.py
## # Copyright (c) 2005-2017 Apple Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ## """ Shared main-point between utilities. """ from calendarserver.tap.util import checkDirectories, getRootResource from calendarserver.tools.util import loadConfig, autoDisableMemcached from twext.enterprise.jobs.queue import NonPerformingQueuer from twext.python.log import Logger from twistedcaldav.config import ConfigurationError from twistedcaldav.timezones import TimezoneCache from twisted.application.service import Service from twisted.internet.defer import inlineCallbacks, succeed from twisted.logger import FileLogObserver, formatEventAsClassicLogText from twisted.python.logfile import LogFile import sys from errno import ENOENT, EACCES # TODO: direct unit tests for these functions. def utilityMain( configFileName, serviceClass, reactor=None, serviceMaker=None, patchConfig=None, onShutdown=None, verbose=False, loadTimezones=False ): """ Shared main-point for utilities. This function will: - Load the configuration file named by C{configFileName}, - launch a L{CalDAVServiceMaker}'s with the C{ProcessType} of C{"Utility"} - run the reactor, with start/stop events hooked up to the service's C{startService}/C{stopService} methods. It is C{serviceClass}'s responsibility to stop the reactor when it's complete. @param configFileName: the name of the configuration file to load. @type configuration: C{str} @param serviceClass: a 1-argument callable which takes an object that provides L{ICalendarStore} and/or L{IAddressbookStore} and returns an L{IService}. @param patchConfig: a 1-argument callable which takes a config object and makes and changes necessary for the tool. @param onShutdown: a 0-argument callable which will run on shutdown. @param reactor: if specified, the L{IReactorTime} / L{IReactorThreads} / L{IReactorTCP} (etc) provider to use. If C{None}, the default reactor will be imported and used. """ from calendarserver.tap.caldav import CalDAVServiceMaker, CalDAVOptions if serviceMaker is None: serviceMaker = CalDAVServiceMaker # We want to validate that the actual service is always an instance of WorkerService, so wrap the # service maker callback inside a function that does that check def _makeValidService(store): service = serviceClass(store) assert isinstance(service, WorkerService) return service # Install std i/o observer observers = [] if verbose: observers.append(FileLogObserver(sys.stdout, lambda event: formatEventAsClassicLogText(event))) if reactor is None: from twisted.internet import reactor try: config = loadConfig(configFileName) if patchConfig is not None: patchConfig(config) checkDirectories(config) utilityLogFile = LogFile.fromFullPath( config.UtilityLogFile, rotateLength=config.ErrorLogRotateMB * 1024 * 1024, maxRotatedFiles=config.ErrorLogMaxRotatedFiles ) utilityLogObserver = FileLogObserver(utilityLogFile, lambda event: formatEventAsClassicLogText(event)) utilityLogObserver._encoding = "utf-8" observers.append(utilityLogObserver) Logger.beginLoggingTo(observers, redirectStandardIO=False) config.ProcessType = "Utility" config.UtilityServiceClass = _makeValidService autoDisableMemcached(config) maker = serviceMaker() # Only perform post-import duties if someone has explicitly said to maker.doPostImport = getattr(maker, "doPostImport", False) options = CalDAVOptions service = maker.makeService(options) reactor.addSystemEventTrigger("during", "startup", service.startService) reactor.addSystemEventTrigger("before", "shutdown", service.stopService) if onShutdown is not None: reactor.addSystemEventTrigger("before", "shutdown", onShutdown) if loadTimezones: TimezoneCache.create() except (ConfigurationError, OSError), e: sys.stderr.write("Error: %s\n" % (e,)) return reactor.run() class WorkerService(Service): def __init__(self, store): self.store = store def rootResource(self): try: from twistedcaldav.config import config rootResource = getRootResource(config, self.store) except OSError, e: if e.errno == ENOENT: # Trying to re-write resources.xml but its parent directory does # not exist. The server's never been started, so we're missing # state required to do any work. raise ConfigurationError( "It appears that the server has never been started.\n" "Please start it at least once before running this tool.") elif e.errno == EACCES: # Trying to re-write resources.xml but it is not writable by the # current user. This most likely means we're in a system # configuration and the user doesn't have sufficient privileges # to do the other things the tool might need to do either. raise ConfigurationError("You must run this tool as root.") else: raise return rootResource @inlineCallbacks def startService(self): try: # Work can be queued but will not be performed by the command # line tool if self.store is not None: self.store.queuer = NonPerformingQueuer() yield self.doWork() else: yield self.doWorkWithoutStore() except ConfigurationError, ce: sys.stderr.write("Error: %s\n" % (str(ce),)) except Exception, e: sys.stderr.write("Error: %s\n" % (e,)) raise finally: self.postStartService() def doWorkWithoutStore(self): """ Subclasses can override doWorkWithoutStore if there is any work they can accomplish without access to the store, or if they want to emit their own error message. """ sys.stderr.write("Error: Data store is not available\n") return succeed(None) def postStartService(self): """ By default, stop the reactor after doWork( ) finishes. Subclasses can override this if they want different behavior. """ if hasattr(self, "reactor"): self.reactor.stop() else: from twisted.internet import reactor reactor.stop()