281 lines
8.9 KiB
Python
281 lines
8.9 KiB
Python
|
# -*- coding: utf-8 -*-
|
|||
|
"""
|
|||
|
fonctions communes Creole
|
|||
|
"""
|
|||
|
import os, time, re
|
|||
|
from os.path import join, isfile
|
|||
|
from pyeole.process import system_out, system_code
|
|||
|
from pyeole.ansiprint import print_orange
|
|||
|
from pyeole.log import init_logging
|
|||
|
from pyeole.pkg import EolePkg
|
|||
|
from pyeole.encode import normalize
|
|||
|
from .config import LOCALKERNEL_FILE, REBOOT_FILE
|
|||
|
|
|||
|
from .i18n import _
|
|||
|
|
|||
|
#si creole client n'est pas démarré
|
|||
|
global PkgManager
|
|||
|
PkgManager = None
|
|||
|
|
|||
|
######################
|
|||
|
# Gestion des noyaux #
|
|||
|
######################
|
|||
|
|
|||
|
def split_version(version):
|
|||
|
"""
|
|||
|
return version as list splitting subnumbers
|
|||
|
:param version: version number string
|
|||
|
:type version: string
|
|||
|
"""
|
|||
|
version_splitted = re.split('[-\.]', version)
|
|||
|
version_splitted = map(int, version_splitted)
|
|||
|
return version_splitted
|
|||
|
|
|||
|
def get_version_filtered_pkgs(prefix='linux-image'):
|
|||
|
"""
|
|||
|
return installed packages list ordered by version number
|
|||
|
"""
|
|||
|
vers_pkg_re = r"{0}-(?P<vers>[0-9]+(?P<upstr_vers>\.[0-9]+)*(-(?P<pkg_vers>[0-9]+))?)".format(prefix)
|
|||
|
vers_pkg_re = re.compile(vers_pkg_re)
|
|||
|
installed_pkgs = get_installed_kernel(prefix)
|
|||
|
vers_pkgs = [(pkg, split_version(vers_pkg_re.search(pkg).group('vers')))
|
|||
|
for pkg in installed_pkgs
|
|||
|
if vers_pkg_re.search(pkg)]
|
|||
|
vers_pkgs = [pkg[0] for pkg in sorted(vers_pkgs, key=lambda p: p[1])]
|
|||
|
return vers_pkgs
|
|||
|
|
|||
|
def get_custom_kernel():
|
|||
|
"""
|
|||
|
renvoie le nom du noyau personnalisé
|
|||
|
ou None
|
|||
|
"""
|
|||
|
if isfile(LOCALKERNEL_FILE):
|
|||
|
# noyau personnalisé détecté
|
|||
|
kernel_file = LOCALKERNEL_FILE
|
|||
|
return file(kernel_file).read().strip()
|
|||
|
|
|||
|
def get_wanted_kernel():
|
|||
|
"""
|
|||
|
renvoie le nom du noyau sur lequel on veut tourner
|
|||
|
"""
|
|||
|
custom_kernel = get_custom_kernel()
|
|||
|
if custom_kernel:
|
|||
|
ret = custom_kernel
|
|||
|
else:
|
|||
|
kernel_images = get_version_filtered_pkgs()
|
|||
|
# Get last kernel version
|
|||
|
last_ver = kernel_images[-1].split('-')
|
|||
|
if len(last_ver) >= 4:
|
|||
|
last_ver = "{0}-{1}-{2}".format(*last_ver[2:5])
|
|||
|
elif len(last_ver) == 3:
|
|||
|
last_ver = "{0}".format(last_ver[-1])
|
|||
|
ret = last_ver
|
|||
|
return ret
|
|||
|
|
|||
|
def get_current_kernel():
|
|||
|
"""
|
|||
|
renvoie le nom du noyau sur lequel on tourne
|
|||
|
"""
|
|||
|
version = system_out(['uname', '-r'])[1].strip()
|
|||
|
return version
|
|||
|
|
|||
|
def get_installed_kernel(kernel):
|
|||
|
"""
|
|||
|
renvoie la liste des noyaux installés
|
|||
|
correspondant à celui demandé
|
|||
|
"""
|
|||
|
cmd = """COLUMNS=180 dpkg -l 2>/dev/null | awk -F " " '/^(i|h)i.*%s/ {print $2}'""" % kernel
|
|||
|
return os.popen(cmd).read().splitlines()
|
|||
|
|
|||
|
def get_package_depends(pkg):
|
|||
|
"""
|
|||
|
Renvois les dépendances d'un paquet
|
|||
|
"""
|
|||
|
try:
|
|||
|
global PkgManager
|
|||
|
if PkgManager is None:
|
|||
|
PkgManager = EolePkg('apt')
|
|||
|
res = PkgManager.get_depends(pkg)
|
|||
|
return res
|
|||
|
except:
|
|||
|
return []
|
|||
|
|
|||
|
def controle_kernel(force_grub=True):
|
|||
|
"""
|
|||
|
Vérifie si on est sur le noyau désiré
|
|||
|
Renvoie True si un reboot est nécessaire
|
|||
|
"""
|
|||
|
need_boot = False
|
|||
|
if isfile(REBOOT_FILE):
|
|||
|
# i.e. /var/run/reboot-required
|
|||
|
need_boot = True
|
|||
|
|
|||
|
wanted_kernel = get_wanted_kernel()
|
|||
|
# on utilise le noyau spécifié
|
|||
|
if wanted_kernel != get_current_kernel():
|
|||
|
need_boot = True
|
|||
|
if force_grub:
|
|||
|
# Update grub does the job since eole-kernel-version 2.3-eole37~2
|
|||
|
print _(u"Updating Grub configuration")
|
|||
|
# ajout de LVM_SUPPRESS_FD_WARNINGS pour #10761
|
|||
|
system_code("/usr/sbin/update-grub2", env={'LVM_SUPPRESS_FD_WARNINGS': '1', "LC_ALL": 'fr_FR.UTF-8'})
|
|||
|
# reboot nécessaire ?
|
|||
|
return need_boot
|
|||
|
|
|||
|
def regen_initrd():
|
|||
|
"""
|
|||
|
vérifie la présence de l'initrd
|
|||
|
"""
|
|||
|
noyau = get_wanted_kernel()
|
|||
|
if not isfile("/boot/initrd.img-%s" % noyau):
|
|||
|
print _(u"Initramfs missing, generating :")
|
|||
|
cmd = ["/usr/sbin/update-initramfs", '-c', '-k', noyau]
|
|||
|
system_code(cmd)
|
|||
|
|
|||
|
def get_kernel_to_remove():
|
|||
|
"""
|
|||
|
Obtenir la liste des noyaux a supprimer. Tous les noyaux sauf :
|
|||
|
- le noyau courant
|
|||
|
- les deux noyaux les plus récents
|
|||
|
- l'éventuel noyau personnalisé
|
|||
|
"""
|
|||
|
# tous les noyaux installés
|
|||
|
installed_kernels = get_version_filtered_pkgs()
|
|||
|
# les deux noyaux les plus récents
|
|||
|
to_keep = installed_kernels[-2:]
|
|||
|
# tous les headers installés
|
|||
|
installed_kernels.extend(get_version_filtered_pkgs(prefix='linux-headers'))
|
|||
|
# le noyau courant
|
|||
|
to_keep.append('linux-image-{0}'.format(get_current_kernel()))
|
|||
|
# l'éventuel noyau personnalisé
|
|||
|
custom_kernel = get_custom_kernel()
|
|||
|
if custom_kernel:
|
|||
|
to_keep.append('linux-image-{0}'.format(custom_kernel))
|
|||
|
# les headers correspondants aux noyaux à conserver
|
|||
|
headers_to_keep = [k.replace('image', 'headers') for k in to_keep]
|
|||
|
headers_to_keep.extend([h.replace('-generic', '') for h in headers_to_keep])
|
|||
|
to_keep.extend(headers_to_keep)
|
|||
|
# on fait la différence
|
|||
|
to_remove = list(set(installed_kernels) - set(to_keep))
|
|||
|
return to_remove
|
|||
|
|
|||
|
def purge_rc():
|
|||
|
"""
|
|||
|
Purge des paquets "rc"
|
|||
|
"""
|
|||
|
cmd = """COLUMNS=180 dpkg -l|grep "^rc"|awk -F " " '{print $2}'"""
|
|||
|
rcs = os.popen(cmd).read().splitlines()
|
|||
|
for pak in rcs:
|
|||
|
os.system("dpkg -P %s >/dev/null" % pak)
|
|||
|
|
|||
|
def log(etat, msg, type_proc, console=True):
|
|||
|
"""
|
|||
|
effectue un log local et éventuellement sur zephir
|
|||
|
"""
|
|||
|
msg = normalize(msg)
|
|||
|
type_proc = normalize(type_proc)
|
|||
|
display = False
|
|||
|
log_func = 'info'
|
|||
|
if etat == "ERR":
|
|||
|
if console:
|
|||
|
# affichage sur la console
|
|||
|
display = True
|
|||
|
log_func = 'error'
|
|||
|
|
|||
|
try:
|
|||
|
z_logger = init_logging(name=u'zephir', syslog=True, level=u'info', console=display)
|
|||
|
except ValueError, err:
|
|||
|
z_logger = init_logging(name=u'zephir', level=u'info', console=True)
|
|||
|
z_logger.warn(_(u"Syslog logging is not working properly: {0}".format(err)))
|
|||
|
z_logger.warn(_(u"You may need to start/restart systemd-journald"))
|
|||
|
|
|||
|
getattr(z_logger, log_func)("%s => %s : %s " % (type_proc, etat, msg))
|
|||
|
|
|||
|
def zephir(etat, msg, type_proc, console=True):
|
|||
|
""" gestion des messages Zephir """
|
|||
|
etat_zeph = None
|
|||
|
if etat.upper().startswith("INIT"):
|
|||
|
etat_zeph = -1
|
|||
|
elif etat.upper().startswith("FIN"):
|
|||
|
etat_zeph = 0
|
|||
|
elif etat.upper().startswith('ERR'):
|
|||
|
etat_zeph = 1
|
|||
|
elif etat.upper().startswith('MSG'):
|
|||
|
etat_zeph = -2
|
|||
|
# log local si msg ou erreur
|
|||
|
if (len(msg) > 0) or (etat.upper() == "ERR"):
|
|||
|
log(etat, msg, type_proc, console)
|
|||
|
# log sur zephir si disponible
|
|||
|
if etat_zeph is not None:
|
|||
|
try:
|
|||
|
# si serveur enregistré, on envoie un log à Zéphir
|
|||
|
from zephir.zephir_conf.zephir_conf import id_serveur
|
|||
|
except:
|
|||
|
pass
|
|||
|
else:
|
|||
|
from zephir.lib_zephir import log as zlog
|
|||
|
zlog(type_proc, etat_zeph, msg, str(time.ctime()))
|
|||
|
|
|||
|
def init_proc(type_proc):
|
|||
|
"""
|
|||
|
initialisation d'une procédure (log démarrage + bcage éventuel)
|
|||
|
"""
|
|||
|
if verify_lock(type_proc):
|
|||
|
return True
|
|||
|
else:
|
|||
|
return False
|
|||
|
|
|||
|
#def end_proc(etat,msg,type_proc):
|
|||
|
# """
|
|||
|
# loggue la fin d'une procédure
|
|||
|
# """
|
|||
|
# log(etat,msg,type_proc )
|
|||
|
|
|||
|
def verify_lock(name):
|
|||
|
"""
|
|||
|
vérifie le bloquage ou non d'une procédure
|
|||
|
"""
|
|||
|
LOCK_FILE = "/usr/share/zephir/zephir_locks"
|
|||
|
if name == "":
|
|||
|
return True
|
|||
|
from zephir.lib_zephir import zephir_path
|
|||
|
try:
|
|||
|
from zephir.lib_zephir import config, zephir, convert
|
|||
|
locks = convert(zephir.serveurs.get_locks(config.id_serveur))
|
|||
|
if locks[0] == 0:
|
|||
|
# erreur sur zephir, on ignore cette phase
|
|||
|
raise Exception
|
|||
|
locks = [lock[0] for lock in locks[1]]
|
|||
|
except Exception, mess:
|
|||
|
# pas de message d'erreur si le serveur n'est pas enregistré
|
|||
|
zephir_error = False
|
|||
|
if isfile(join(zephir_path, "zephir_conf", "zephir_conf.py")):
|
|||
|
# on ne bloque pas si l'appel à zephir échoue
|
|||
|
print ""
|
|||
|
print_orange(_(u"Checking permissions on Zéphir for {0} impossible.").format(name))
|
|||
|
print_orange(_(u"Error message: {0}").format(mess))
|
|||
|
zephir_error = True
|
|||
|
# on regarde le denier état
|
|||
|
if os.path.exists(LOCK_FILE):
|
|||
|
if zephir_error:
|
|||
|
print_orange(_(u"Using stored parameters"))
|
|||
|
file_lock = file(LOCK_FILE)
|
|||
|
locks = file_lock.read().split('\n')
|
|||
|
file_lock.close()
|
|||
|
# on bloque si interdit
|
|||
|
if name in locks:
|
|||
|
return False
|
|||
|
else:
|
|||
|
# mise en place du fichier de droits
|
|||
|
content = "\n".join(locks)
|
|||
|
try:
|
|||
|
file_lock = file(LOCK_FILE, "w")
|
|||
|
file_lock.write(content)
|
|||
|
file_lock.close()
|
|||
|
except:
|
|||
|
print _(u"Updating {0} impossible (insufficient rights).").format(LOCK_FILE)
|
|||
|
# retour du code
|
|||
|
if name in locks:
|
|||
|
return False
|
|||
|
return True
|