initial commit of file from CVS for smeserver-yum on Thu 26 Oct 11:26:23 BST 2023
This commit is contained in:
14
root/usr/lib/systemd/system/yum.service
Normal file
14
root/usr/lib/systemd/system/yum.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Yum db updater for Koozali SME Server
|
||||
After=network-pre.target networking.service
|
||||
Conflicts=yum-cron.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStartPre=/sbin/e-smith/service-status yum
|
||||
ExecStart=/sbin/e-smith/yum_update_dbs
|
||||
TimeoutSec=0
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=sme-server.target
|
446
root/usr/lib/yum-plugins/smeserver.py
Normal file
446
root/usr/lib/yum-plugins/smeserver.py
Normal file
@@ -0,0 +1,446 @@
|
||||
# vim: noexpandtab tabstop=4
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import syslog
|
||||
from yum.constants import *
|
||||
from yum.plugins import PluginYumExit
|
||||
from yum.plugins import TYPE_CORE
|
||||
from yum.packages import parsePackages
|
||||
from yum.packages import RpmBase
|
||||
|
||||
requires_api_version = '2.1'
|
||||
plugin_type = (TYPE_CORE,)
|
||||
|
||||
events_path = '/etc/e-smith/events'
|
||||
initialize_database = events_path + '/actions/initialize-default-databases'
|
||||
navigation_conf = events_path + '/actions/navigation-conf'
|
||||
systemctl = "/usr/bin/systemctl"
|
||||
yum_update_dbs = events_path + '/actions/yum-update-dbs'
|
||||
signal_event = '/sbin/e-smith/signal-event'
|
||||
config_set = '/sbin/e-smith/config'
|
||||
status_file = '/var/run/yum.status'
|
||||
expand_template = '/sbin/e-smith/expand-template'
|
||||
service = '/sbin/e-smith/service'
|
||||
|
||||
eventlist = dict()
|
||||
actionlist = dict()
|
||||
templateslist = dict()
|
||||
serviceslist = dict()
|
||||
|
||||
|
||||
# list of packages that need a reboot
|
||||
# if a package name starts with one these names, a reboot is needed
|
||||
rebootpkgs = ['daemontools', 'dbus', 'glibc', 'gnutls', 'kernel', 'linux-firmware', 'lvm2', 'mdadm', 'openssl-libs', 'systemd']
|
||||
# exclusions :
|
||||
rebootpkgsexclude = dict()
|
||||
rebootpkgsexclude['dbus']='-python','-tests','-devel','-doc',
|
||||
rebootpkgsexclude['glibc']='-devel','-headers','-statics','-utils','-glib',
|
||||
rebootpkgsexclude['gnutls']='-devel',
|
||||
rebootpkgsexclude['kernel']='-doc','-debug','-devel','-abi-whitelists','tools',
|
||||
rebootpkgsexclude['lvm2']='-devel','-python',
|
||||
rebootpkgsexclude['systemd']='-devel','-python',
|
||||
|
||||
|
||||
# list of packages that need a service restart
|
||||
# if a package name starts with one of these values, a service restart is needed
|
||||
# since, for example, httpd means httpd-admin and httpd-e-smith, we won't use these names directly but via serviceslist (see below)
|
||||
restartpkgs = ['dovecot','bglibs','cvm','freeradius','httpd','iptables', 'mariadb' , 'nut', 'openldap', 'openssh', 'php', 'pptpd', 'proftp', 'samba', 'spamassassin', 'squid', 'qmail', 'qpsmtpd']
|
||||
servicenames = dict()
|
||||
servicenames['bglibs']='cvm-unix',
|
||||
servicenames['cvm']='cvm-unix',
|
||||
servicenames['dovecot']='dovecot',
|
||||
servicenames['freeradius']='radiusd',
|
||||
servicenames['httpd']='httpd-admin','httpd-e-smith',
|
||||
servicenames['iptables']='masq',
|
||||
servicenames['mariadb']='mariadb',
|
||||
servicenames['nut']='nut-server','nut-driver','nut-monitor',
|
||||
servicenames['openldap']='ldap',
|
||||
servicenames['openssh']='sshd',
|
||||
servicenames['php']='httpd-e-smith', 'php-fpm', 'php55-php-fpm', 'php56-php-fpm', 'php70-php-fpm', 'php71-php-fpm', 'php72-php-fpm', 'php73-php-fpm', 'php74-php-fpm', 'php80-php-fpm', 'php81-php-fpm',
|
||||
servicenames['proftp']='ftp',
|
||||
servicenames['samba']='smb',
|
||||
servicenames['spamassassin']='spamassassin',
|
||||
servicenames['squid']='squid',
|
||||
servicenames['qmail']='qmail',
|
||||
servicenames['qpsmtpd']='qpsmtpd',
|
||||
|
||||
smechange = False
|
||||
smechangelist = dict()
|
||||
ourfile = False
|
||||
erasing = False
|
||||
DEBUG = False
|
||||
smeEventPretrans = False
|
||||
removenorebootok = dict()
|
||||
|
||||
def log(s):
|
||||
if DEBUG :
|
||||
print s
|
||||
def createevent():
|
||||
if os.path.isdir('/etc/e-smith/events/temp'):
|
||||
shutil.rmtree('/etc/e-smith/events/temp')
|
||||
os.makedirs('/etc/e-smith/events/temp/services2adjust', 0o777)
|
||||
os.makedirs('/etc/e-smith/events/temp/templates2expand', 0o777)
|
||||
|
||||
def addtemplate2expand(template):
|
||||
#check filename
|
||||
head_tail = os.path.split(template)
|
||||
head = head_tail[0];
|
||||
filename = head_tail[1];
|
||||
# create dir
|
||||
if not os.path.isdir('/etc/e-smith/events/temp/templates2expand' + head):
|
||||
os.makedirs('/etc/e-smith/events/temp/templates2expand' + head, 0o777)
|
||||
#touch file
|
||||
fname= '/etc/e-smith/events/temp/templates2expand'+ template
|
||||
fhandle = open(fname, 'a')
|
||||
try:
|
||||
os.utime(fname, None)
|
||||
finally:
|
||||
fhandle.close()
|
||||
|
||||
def report_yum_status(status):
|
||||
fileHandle = open(status_file, 'w')
|
||||
fileHandle.write(status)
|
||||
fileHandle.close()
|
||||
|
||||
def predownload_hook(conduit):
|
||||
report_yum_status('predownload')
|
||||
|
||||
def postdownload_hook(conduit):
|
||||
report_yum_status('postdownload')
|
||||
|
||||
def prereposetup_hook(conduit):
|
||||
global ourfile
|
||||
|
||||
ourfile = True
|
||||
report_yum_status('prereposetup')
|
||||
|
||||
def postreposetup_hook(conduit):
|
||||
report_yum_status('postreposetup')
|
||||
|
||||
def exclude_hook(conduit):
|
||||
report_yum_status('exclude')
|
||||
|
||||
def preresolve_hook(conduit):
|
||||
report_yum_status('preresolve')
|
||||
|
||||
def postresolve_hook(conduit):
|
||||
report_yum_status('postresolve')
|
||||
|
||||
def pretrans_hook(conduit):
|
||||
# we might need to change the strategy here to make a difference between update and removal.
|
||||
#transaction set states
|
||||
#TS_UPDATE = 10
|
||||
#TS_INSTALL = 20
|
||||
#TS_TRUEINSTALL = 30
|
||||
#TS_ERASE = 40
|
||||
#TS_OBSOLETED = 50
|
||||
#TS_OBSOLETING = 60
|
||||
#TS_AVAILABLE = 70
|
||||
#TS_UPDATED = 90
|
||||
#TS_FAILED = 100
|
||||
#TS_INSTALL_STATES = [TS_INSTALL, TS_TRUEINSTALL, TS_UPDATE, TS_OBSOLETING]
|
||||
#TS_REMOVE_STATES = [TS_ERASE, TS_OBSOLETED, TS_UPDATED]
|
||||
|
||||
report_yum_status('pretrans')
|
||||
log("*******Pretrans********")
|
||||
# Prefetch filelist for packages to be removed,
|
||||
# otherwise for updated packages headers will not be available
|
||||
ts = conduit.getTsInfo()
|
||||
removes = ts.getMembersWithState(output_states=TS_REMOVE_STATES)
|
||||
rpmdb = conduit.getRpmDB()
|
||||
global smechange
|
||||
global eventlist
|
||||
global actionlist
|
||||
global templateslist
|
||||
global serviceslist
|
||||
global erasing
|
||||
global smeEventPretrans
|
||||
global removenorebootok
|
||||
|
||||
|
||||
# reinstall are not listed there so already skipped
|
||||
# downgrade are going there
|
||||
# update are going there, we filter them out
|
||||
# real removal are the real deal there ; downgrade are played like if they were removal
|
||||
for tsmem in removes:
|
||||
erasing = True
|
||||
(n, a, e, v, r) = tsmem.po.pkgtup
|
||||
if tsmem.output_state == TS_UPDATED :
|
||||
# if we are actually updating then we are not removing, and new package will do better... skipping
|
||||
log('skiping as updating ==> state ' + str(tsmem.po.state) + " RPM current state" + str(tsmem.current_state) + " RPM output state" + str(tsmem.output_state))
|
||||
continue
|
||||
log('**Package: ' + tsmem.name + ' to be removed')
|
||||
smeevent = tsmem.name + '-update'
|
||||
if os.path.isdir(events_path + os.sep + smeevent):
|
||||
tmppath = events_path + os.sep + smeevent + os.sep
|
||||
eventlist[tsmem.name] = smeevent
|
||||
|
||||
if os.path.isdir(tmppath + "templates2expand" + os.sep):
|
||||
tmppathtmpl = tmppath + "templates2expand" + os.sep
|
||||
for subdir, dirs, files in os.walk(tmppathtmpl):
|
||||
for file in files:
|
||||
mytmptemplate = os.path.join(subdir, file).replace(tmppathtmpl,os.sep)
|
||||
if not templateslist.has_key(mytmptemplate):
|
||||
templateslist[mytmptemplate]=mytmptemplate
|
||||
log(" template " + mytmptemplate)
|
||||
|
||||
# nothing for actions ???
|
||||
tmppathsrv = tmppath + os.sep
|
||||
files = [f for f in os.listdir(tmppathsrv)]
|
||||
for f in files:
|
||||
if os.path.islink(tmppathsrv + f):
|
||||
mytmpaction = os.path.realpath(os.readlink(tmppath + f).replace("..",events_path))
|
||||
log(" link " + f + ": " + mytmpaction)
|
||||
actionlist[f]=mytmpaction
|
||||
|
||||
# end debug print
|
||||
if os.path.isdir(tmppath + "services2adjust" + os.sep):
|
||||
tmppathsrv = tmppath + "services2adjust" + os.sep
|
||||
files = [f for f in os.listdir(tmppathsrv)]
|
||||
for f in files:
|
||||
if os.path.islink(tmppathsrv + f):
|
||||
log(" service link " + f + ": " + (os.readlink(tmppathsrv + f)))
|
||||
mytmpserv = os.readlink(tmppathsrv + f)
|
||||
if not serviceslist.has_key(f):
|
||||
serviceslist[f]=mytmpserv
|
||||
else:
|
||||
if mytmpserv == "restart":
|
||||
log("overriding all signals, forcing restart " + f )
|
||||
serviceslist[f]="restart"
|
||||
removenorebootok[n]=1;
|
||||
thispo = rpmdb.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)[0]
|
||||
# thispo.dirlist thispo.ghostlist thispo.filelist
|
||||
if "/etc/e-smith/web/panels/manager/cgi-bin" in thispo.dirlist:
|
||||
log(" ==> pannel detected : adding navigation-conf")
|
||||
actionlist['S80navigation-conf']="/etc/e-smith/events/actions/navigation-conf"
|
||||
|
||||
else:
|
||||
if (n.startswith('smeserver') or n.startswith('e-smith')) and not n.startswith('smeserver-locale'):
|
||||
smechange = True
|
||||
smechangelist[n]=str(tsmem.po.state) + " " + str(tsmem.current_state) + " " + str(tsmem.output_state)
|
||||
log("smechange set to True because of " + n + " with " + str(tsmem.po.state) + " " + str(tsmem.current_state) + " " + str(tsmem.output_state) )
|
||||
|
||||
#only for debug
|
||||
log('## smechange: '+str(smechange))
|
||||
log('## eventlist: '+ str(eventlist))
|
||||
log('## templateslist: '+str(templateslist.keys()))
|
||||
log('## serviceslist: '+str(serviceslist.items()))
|
||||
log('## actions ALL: ' + str(actionlist.keys()))
|
||||
log('## smechangelist: ' + str(smechangelist.keys()))
|
||||
|
||||
if len(serviceslist)>0:
|
||||
# would it be a good idea to do some action/event there to stop service being removed ?
|
||||
# for the moment we do not, logic : if template still there at posttrans, we expand it after removal
|
||||
# probably the actions in some situations could be done before...
|
||||
# create an empty temp event
|
||||
print "Creating temporary event 'temp' and populating it..."
|
||||
createevent()
|
||||
print " Adding services to adjust"
|
||||
for kservices in serviceslist:
|
||||
log(" " + kservices + ": " + serviceslist[kservices])
|
||||
os.symlink(serviceslist[kservices], '/etc/e-smith/events/temp/services2adjust/' + kservices)
|
||||
|
||||
# execute the event ; should we really wait ??
|
||||
print "Executing signal-event temp before uninstalling ..........."
|
||||
os.spawnl(os.P_WAIT,signal_event,signal_event, 'temp')
|
||||
smeEventPretrans = True;
|
||||
|
||||
def posttrans_hook(conduit):
|
||||
report_yum_status('posttrans')
|
||||
log("*******Postrans********")
|
||||
ts = conduit.getTsInfo()
|
||||
rpmdb = conduit.getRpmDB()
|
||||
|
||||
global smechange
|
||||
global eventlist
|
||||
global actionlist
|
||||
global templateslist
|
||||
global serviceslist
|
||||
global erasing
|
||||
global smeEventPretrans
|
||||
global removenorebootok
|
||||
|
||||
|
||||
for tsmem in ts.getMembers():
|
||||
(n, a, e, v, r) = tsmem.po.pkgtup
|
||||
# n: name ; a : arch; e: epoch ; v: version, r: release
|
||||
#if tsmem.output_state in TS_INSTALL_STATES:
|
||||
# thispo = rpmdb.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)[0]
|
||||
|
||||
# we're upgrading/installing/removing a rebootpkgs package.. a reboot is required
|
||||
for pkg in rebootpkgs:
|
||||
if n.startswith(pkg):
|
||||
log('**Package: ' + tsmem.name + ' triggers reboot')
|
||||
# we do some exclusions -devel -doc ...
|
||||
if pkg in rebootpkgsexclude:
|
||||
cont=False
|
||||
for name in rebootpkgsexclude[pkg]:
|
||||
if n.startswith(pkg + name):
|
||||
cont=True
|
||||
if cont:
|
||||
# this is an exception we do not need reboot : -devel, -doc ...
|
||||
continue
|
||||
# either no exception or does not fit exceptions: we need reboot
|
||||
smechange = True
|
||||
smechangelist[n]=str(tsmem.po.state) + " " + str(tsmem.current_state) + " " + str(tsmem.output_state)
|
||||
log("smechange set to True because of " + n + " with " + str(tsmem.po.state) + " " + str(tsmem.current_state) + " " + str(tsmem.output_state))
|
||||
#log("smechange set to True because of " + pkg)
|
||||
|
||||
# check if we're upgrading a restartpkgs rpm
|
||||
for pkg in restartpkgs:
|
||||
if n.startswith(pkg):
|
||||
if pkg in servicenames:
|
||||
for name in servicenames[pkg]:
|
||||
if not serviceslist.has_key(name):
|
||||
serviceslist[name] = 'restart'
|
||||
else:
|
||||
if not serviceslist.has_key(pkg):
|
||||
serviceslist[pkg] = 'restart'
|
||||
|
||||
|
||||
#if smechange is true we can ignore the following part
|
||||
# wondering if we reallly do want to ignore that : let's say we want to delay kernel reboot,
|
||||
# could we at least configure httpd cleanly until next week ?
|
||||
# also when updating a package the erasing flag was on and prevented to do this ....
|
||||
# if not smechange and not erasing:
|
||||
if True:
|
||||
|
||||
smeevent = tsmem.name + '-update'
|
||||
if os.path.isdir(events_path + os.sep + smeevent):
|
||||
tmppath = events_path + os.sep + smeevent + os.sep
|
||||
eventlist[tsmem.name] = smeevent
|
||||
|
||||
files = [f for f in os.listdir(tmppath)]
|
||||
for f in files:
|
||||
if os.path.islink(tmppath + f):
|
||||
|
||||
mytmpaction = os.path.realpath(os.readlink(tmppath + f).replace("..",events_path))
|
||||
#log(" link " + f + ": " + mytmpaction)
|
||||
actionlist[f]=mytmpaction
|
||||
|
||||
|
||||
if os.path.isdir(tmppath + "templates2expand" + os.sep):
|
||||
tmppathtmpl = tmppath + "templates2expand" + os.sep
|
||||
for subdir, dirs, files in os.walk(tmppathtmpl):
|
||||
for file in files:
|
||||
mytmptemplate = os.path.join(subdir, file).replace(tmppathtmpl,os.sep)
|
||||
if not templateslist.has_key(mytmptemplate):
|
||||
templateslist[mytmptemplate]=mytmptemplate
|
||||
log(" template " + mytmptemplate)
|
||||
|
||||
if os.path.isdir(tmppath + "services2adjust" + os.sep):
|
||||
tmppathsrv = tmppath + "services2adjust" + os.sep
|
||||
files = [f for f in os.listdir(tmppathsrv)]
|
||||
for f in files:
|
||||
if os.path.islink(tmppathsrv + f):
|
||||
log(" service link " + f + ": " + (os.readlink(tmppathsrv + f)))
|
||||
mytmpserv = os.readlink(tmppathsrv + f)
|
||||
if not serviceslist.has_key(f):
|
||||
serviceslist[f]=mytmpserv
|
||||
else:
|
||||
if mytmpserv == "restart":
|
||||
#only for debug
|
||||
log("overriding all signals, forcing restart " + f)
|
||||
serviceslist[f]="restart"
|
||||
if tsmem.output_state in TS_INSTALL_STATES:
|
||||
thispo = rpmdb.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)[0]
|
||||
# thispo.dirlist thispo.ghostlist thispo.filelist
|
||||
if "/etc/e-smith/web/panels/manager/cgi-bin" in thispo.dirlist:
|
||||
log(" ==> pannel detected : adding navigation-conf")
|
||||
actionlist['S80navigation-conf']="/etc/e-smith/events/actions/navigation-conf"
|
||||
|
||||
else:
|
||||
if (n.startswith('smeserver') or n.startswith('e-smith')) and not n.startswith('smeserver-locale') and not (n in removenorebootok):
|
||||
smechange = True
|
||||
smechangelist[n]=str(tsmem.po.state) + " " + str(tsmem.current_state) + " " + str(tsmem.output_state)
|
||||
log("smechange set to True because of " + n + " with " + str(tsmem.po.state) + " " + str(tsmem.current_state) + " " + str(tsmem.output_state) )
|
||||
|
||||
#only for debug
|
||||
log('## smechange: '+str(smechange))
|
||||
log('## eventlist: '+ str(eventlist))
|
||||
log('## templateslist: '+str(templateslist.keys()))
|
||||
log('## serviceslist: '+str(serviceslist.items()))
|
||||
log('## actions ALL: ' + str(actionlist.keys()))
|
||||
log('## smechangelist: ' + str(smechangelist.keys()))
|
||||
|
||||
# check if smechange is true or if eventlist has items.. in both cases we must initialize databases
|
||||
if smechange == True or len(eventlist)>0:
|
||||
print 'Initializing databases'
|
||||
os.spawnl(os.P_WAIT, initialize_database, initialize_database)
|
||||
|
||||
# just in case we add systemd-default and systemd-reload
|
||||
if not actionlist.has_key('S88systemd-default'):
|
||||
actionlist['S88systemd-default'] = '/etc/e-smith/events/actions/systemd-default'
|
||||
if not actionlist.has_key('S89systemd-reload'):
|
||||
actionlist['S89systemd-reload'] = '/etc/e-smith/events/actions/systemd-reload'
|
||||
|
||||
# here we would like to remove duplicates
|
||||
# those are potential : S??navigation-conf S??systemd-reload S??systemd-default
|
||||
for act in ('navigation-conf','systemd-reload','systemd-default'):
|
||||
global iter
|
||||
iter = 0
|
||||
for key in actionlist.keys():
|
||||
if key.endswith(act):
|
||||
iter += 1
|
||||
if iter>1:
|
||||
del actionlist[key]
|
||||
log("removing duplicate action " + key + " iter " + str(iter))
|
||||
|
||||
|
||||
# now, if smechange is false (no reboot needed), we can execute actions, expand templates and adjust services
|
||||
|
||||
# create an empty temp event
|
||||
print "Creating temporary event 'temp' and populating it..."
|
||||
createevent()
|
||||
|
||||
# fill it with our list of actions
|
||||
if len(actionlist)>0:
|
||||
print " Adding actions to execute"
|
||||
for kactions in actionlist:
|
||||
if os.path.isfile(actionlist[kactions]):
|
||||
log(" " + kactions)
|
||||
os.symlink(actionlist[kactions],'/etc/e-smith/events/temp/' + kactions)
|
||||
|
||||
# fill it with our list of templates to expand
|
||||
if len(templateslist)>0:
|
||||
print " Adding templates to expand"
|
||||
for ktemplates in templateslist:
|
||||
mytemplatedir = '/etc/e-smith/templates/' + ktemplates
|
||||
mytemplatemeta = '/etc/e-smith/templates.metadata/' + ktemplates
|
||||
if os.path.exists(mytemplatedir) or os.path.exists(mytemplatemeta):
|
||||
log(" " + ktemplates)
|
||||
addtemplate2expand(ktemplates)
|
||||
|
||||
if len(serviceslist)>0:
|
||||
print " Adding services to adjust"
|
||||
for kservices in serviceslist:
|
||||
log(" " + kservices + ": " + serviceslist[kservices])
|
||||
os.symlink(serviceslist[kservices], '/etc/e-smith/events/temp/services2adjust/' + kservices)
|
||||
|
||||
# execute the event ; should we really wait ??
|
||||
print "Executing signal-event temp ..........."
|
||||
os.spawnl(os.P_WAIT,signal_event,signal_event, 'temp')
|
||||
|
||||
if smechange:
|
||||
os.spawnl(os.P_WAIT, config_set, config_set, 'set', 'UnsavedChanges', 'yes')
|
||||
os.spawnl(os.P_WAIT, navigation_conf, navigation_conf)
|
||||
syslog.syslog('Needs signal-event post-upgrade; signal-event reboot because of: ' + str(smechangelist.keys()) )
|
||||
print "Reload yum db for server-manager"
|
||||
os.spawnl(os.P_WAIT, systemctl, systemctl, 'restart', 'yum')
|
||||
|
||||
def close_hook(conduit):
|
||||
if ourfile and os.path.isfile('/var/run/yum.status'):
|
||||
os.unlink('/var/run/yum.status')
|
||||
|
||||
if smechange:
|
||||
print "\nThe following updates require a server reboot:\n" + str(smechangelist.keys())
|
||||
print "\n=============================================================="
|
||||
print "WARNING: You now need to run BOTH of the following commands"
|
||||
print "to ensure consistent system state:\n"
|
||||
print "signal-event post-upgrade; signal-event reboot\n"
|
||||
print "You should run these commands unless you are certain that"
|
||||
print "yum made no changes to your system."
|
||||
print "=============================================================="
|
||||
|
Reference in New Issue
Block a user