Current Path : /usr/lib/python2.7/dist-packages/landscape/monitor/ |
Current File : //usr/lib/python2.7/dist-packages/landscape/monitor/packagemonitor.py |
import logging import os from twisted.internet.utils import getProcessOutput from landscape.package.store import PackageStore from landscape.package.reporter import find_reporter_command from landscape.monitor.plugin import MonitorPlugin class PackageMonitor(MonitorPlugin): run_interval = 1800 scope = "package" def __init__(self, package_store_filename=None): super(PackageMonitor, self).__init__() if package_store_filename: self._package_store = PackageStore(package_store_filename) else: self._package_store = None self._reporter_command = find_reporter_command() def register(self, registry): self.config = registry.config self.run_interval = self.config.package_monitor_interval if self.config.clones and self.config.is_clone: # Run clones a bit more frequently in order to catch up self.run_interval = 60 # 300 super(PackageMonitor, self).register(registry) if not self._package_store: filename = os.path.join(registry.config.data_path, "package/database") self._package_store = PackageStore(filename) registry.register_message("package-ids", self._enqueue_message_as_reporter_task) registry.reactor.call_on("server-uuid-changed", self._server_uuid_changed) self.call_on_accepted("packages", self.spawn_reporter) self.run() def _enqueue_message_as_reporter_task(self, message): self._package_store.add_task("reporter", message) self.spawn_reporter() def run(self): result = self.registry.broker.get_accepted_message_types() result.addCallback(self._got_message_types) return result def _got_message_types(self, message_types): if "packages" in message_types: self.spawn_reporter() def _run_fake_reporter(self, args): """Run a fake-reporter in-process.""" class FakeFacade(object): """ A fake facade to workaround the issue that the AptFacade essentially allows only once instance per process. """ def get_arch(self): arch = os.uname()[-1] result = {"pentium": "i386", "i86pc": "i386", "x86_64": "amd64"}.get(arch) if result: arch = result elif (arch[0] == "i" and arch.endswith("86")): arch = "i386" return arch if getattr(self, "_fake_reporter", None) is None: from landscape.package.reporter import ( FakeReporter, PackageReporterConfiguration) from landscape.package.store import FakePackageStore package_facade = FakeFacade() package_config = PackageReporterConfiguration() package_config.load(args + ["-d", self.config.data_path, "-l", self.config.log_dir]) package_store = FakePackageStore(package_config.store_filename) self._fake_reporter = FakeReporter(package_store, package_facade, self.registry.broker, package_config) self._fake_reporter.global_store_filename = os.path.join( self.config.master_data_path, "package", "database") self._fake_reporter_running = False if self._fake_reporter_running: from twisted.internet.defer import succeed return succeed(None) self._fake_reporter_running = True result = self._fake_reporter.run() def done(passthrough): self._fake_reporter_running = False return passthrough return result.addBoth(done) def spawn_reporter(self): args = ["--quiet"] if self.config.config: args.extend(["-c", self.config.config]) env = os.environ.copy() if self.config.clones > 0: if self.config.is_clone: return self._run_fake_reporter(args) else: env["FAKE_GLOBAL_PACKAGE_STORE"] = "1" # path is set to None so that getProcessOutput does not # chdir to "." see bug #211373 result = getProcessOutput(self._reporter_command, args=args, env=env, errortoo=1, path=None) result.addCallback(self._got_reporter_output) return result def _got_reporter_output(self, output): if output: logging.warning("Package reporter output:\n%s" % output) def _reset(self): """ Remove all tasks *except* the resynchronize task. This is because if we clear all tasks, then add the resynchronize, it's possible that the reporter may be running a task at this time and when it finishes, it will unknowningly remove the resynchronize task because sqlite resets its serial primary keys when you delete an entire table. This problem is avoided by adding the task first and removing them all *except* the resynchronize task and not causing sqlite to reset the serial key. """ task = self._package_store.add_task("reporter", {"type": "resynchronize"}) self._package_store.clear_tasks(except_tasks=(task,)) def _server_uuid_changed(self, old_uuid, new_uuid): """Called when the broker sends a server-uuid-changed event. The package hash=>id map is server-specific, so when we change servers, we should reset this map. """ # If the old_uuid is None, it means we're just starting to # communicate with a server that knows how to report its UUID, # so we don't clear our knowledge. if old_uuid is not None: self._package_store.clear_hash_ids()