Viewing file: yum-updatesd (10.52 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#!/usr/bin/python -tt
#
# Proof of concept yumd implementation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Copyright 2007 Red Hat, Inc.
# Jeremy Katz
#
# since it takes me time everytime to figure this out again, here's how to
# queue a check with dbus-send. adjust appropriately for other methods
# $ dbus-send --system --print-reply --type=method_call \
# --dest=edu.duke.linux.yum /Updatesd edu.duke.linux.yum.CheckNow
import os, sys
import string
import syslog
import string
import subprocess
import time # For updaterefresh
from optparse import OptionParser
import dbus
import dbus.service
import dbus.glib
import gobject
import gamin
from yum.config import BaseConfig, Option, IntOption, ListOption, BoolOption
try:
from yum.config import SecondsOption
except:
class SecondsOption(IntOption):
pass
from yum.parser import ConfigPreProcessor
from ConfigParser import ConfigParser, ParsingError
updateInfoDone = False
updateInfo = []
helperProcess = None
NM_ONLINE = 3
class UDConfig(BaseConfig):
"""Config format for the daemon"""
run_interval = SecondsOption(60 * 60) # 1h
nonroot_workdir = Option("/var/tmp/yum-updatesd")
emit_via = ListOption(['dbus', 'email', 'syslog'])
email_to = ListOption(["root"])
email_from = Option("root")
smtp_server = Option("localhost:25")
use_sendmail = BoolOption(True)
dbus_listener = BoolOption(True)
do_update = BoolOption(False)
do_download = BoolOption(False)
do_download_deps = BoolOption(False)
updaterefresh = SecondsOption(60 * 60) # 1h
syslog_facility = Option("DAEMON")
syslog_level = Option("WARN")
syslog_ident = Option("yum-updatesd")
yum_config = Option("/etc/yum/yum.conf")
# added debugging
debug = BoolOption(False)
def read_config():
confparser = ConfigParser()
opts = UDConfig()
config_file = '/etc/yum/yum-updatesd.conf'
if os.path.exists(config_file):
confpp_obj = ConfigPreProcessor(config_file)
try:
confparser.readfp(confpp_obj)
except ParsingError, e:
print >> sys.stderr, "Error reading config file: %s" % e
sys.exit(1)
opts.populate(confparser, 'main')
return opts
class YumDbusListener(dbus.service.Object):
def __init__(self, bus_name, object_path='/Updatesd',
allowshutdown = False, config = None):
dbus.service.Object.__init__(self, bus_name, object_path)
self.allowshutdown = allowshutdown
self.yumdconfig = config
def doCheck(self):
checkUpdates(self.yumdconfig, limited=True)
return False
@dbus.service.method("edu.duke.linux.yum", in_signature="")
def CheckNow(self):
# make updating checking asynchronous since we discover whether
# or not there are updates via a callback signal anyway
gobject.idle_add(self.doCheck)
return "check queued"
@dbus.service.method("edu.duke.linux.yum", in_signature="")
def ShutDown(self):
if not self.allowshutdown:
return False
# we have to do this in a callback so that it doesn't get
# sent back to the caller
gobject.idle_add(sys.exit, 0)
return True
@dbus.service.method("edu.duke.linux.yum", in_signature="", out_signature="a(a{ss}a{ss})")
def GetUpdateInfo(self):
# FIXME: this call is deprecated. things should watch for the update
# info signals
global updateInfoDone, updateInfo
if not updateInfoDone:
# FIXME: this isn't synchronous anymore. but it should be
# reasonable enough given the users
gobject.idle_add(self.doCheck)
return []
return updateInfo
def checkHelperStatus():
global helperProcess
if helperProcess.poll() is not None:
helperProcess = None
return False
return True
lastUpdate = None
def checkUpdates(opts, wait = False, limited=False):
""" Run yum-updatesd-helper to check for updates and report. Possibly
wait for the result, and/or limit the number of updates we try. """
global lastUpdate
global helperProcess
if helperProcess is not None:
print >> sys.stderr, "Helper process already running"
return True
now = time.time()
if limited and lastUpdate and (now - lastUpdate) < opts.updaterefresh:
print >> sys.stderr, "Update requested too quickly"
return True
if os.path.exists("./yum-updatesd-helper") and opts.debug:
args = ["./yum-updatesd-helper", "--check"]
else:
args = ["/usr/libexec/yum-updatesd-helper", "--check"]
bus = dbus.SystemBus()
try:
o = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager")
if o.state() != NM_ONLINE:
args.append("--network-fail")
except dbus.DBusException:
pass
# arguments for what to do
if opts.do_download:
args.append("--download")
if opts.do_download_deps:
args.append("--deps")
if opts.do_update:
args.append("--apply")
# how should we send notifications?
if "dbus" in opts.emit_via:
args.append("--dbus")
if "email" in opts.emit_via:
args.extend(["--email", "--email-from=%s" %(opts.email_from,),
"--email-to=%s" %(string.join(opts.email_to, ","),),
"--smtp-server=%s" %(opts.smtp_server)])
if opts.use_sendmail:
args.append("--sendmail")
if "syslog" in opts.emit_via:
args.extend(["--syslog", "--syslog-level=%s" %(opts.syslog_level,),
"--syslog-facility=%s" %(opts.syslog_facility,),
"--syslog-ident=%s" %(opts.syslog_ident,)])
if opts.debug:
args.append("--debug")
print >> sys.stderr, "Going to exec: %s" %(args,)
lastUpdate = now
helperProcess = subprocess.Popen(args, close_fds = True)
if not wait:
gobject.timeout_add(1 * 1000, checkHelperStatus)
return True
return helperProcess.wait()
def add_update(update):
global updateInfo, updateInfoDone
if updateInfoDone:
updateInfo = []
updateInfoDone = False
updateInfo.append(update)
def updates_done(num):
global updateInfoDone, updateInfo
# if we received all the updates, we're good. otherwise, we need to
# clear the info out
if int(num) != len(updateInfo):
updateInfo = []
else:
updateInfoDone = True
def updates_applied(*args):
global updateInfoDone, updateInfo
updateInfo = []
updateInfoDone = False
def invalidate_cache(*args):
global updateInfoDone, updateInfo, helperProcess
if helperProcess is not None:
return
updateInfo = []
updateInfoDone = False
def setup_watcher():
"""Sets up gamin-based file watches on things we care about and makes
it so they get checked every 15 seconds."""
# add some watches on directories.
mon = gamin.WatchMonitor()
mon.watch_directory("/var/lib/rpm", invalidate_cache)
mon.watch_directory("/var/cache/yum", invalidate_cache)
map(lambda x: os.path.isdir("/var/cache/yum/%s" %(x,)) and
mon.watch_directory("/var/cache/yum/%s" %(x,), invalidate_cache),
os.listdir("/var/cache/yum"))
mon.handle_events()
fd = mon.get_fd()
gobject.io_add_watch(fd, gobject.IO_IN bool(false)
|