for creole's zephir2 branch
This commit is contained in:
454
bin/Maj-Auto
Executable file
454
bin/Maj-Auto
Executable file
@ -0,0 +1,454 @@
|
||||
#! /usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
##########################################################################
|
||||
# Maj-Auto - Manage automatique update of EOLE server
|
||||
# Copyright © 2013 Pôle de compétences EOLE <eole@ac-dijon.fr>
|
||||
#
|
||||
# License CeCILL:
|
||||
# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
|
||||
# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
|
||||
##########################################################################
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import atexit
|
||||
import time
|
||||
import locale
|
||||
|
||||
from os import unlink, environ, system
|
||||
from subprocess import Popen, PIPE
|
||||
from os.path import basename, isfile
|
||||
|
||||
from creole import reconfigure, fonctionseole
|
||||
from creole.client import CreoleClient, TimeoutCreoleClientError, NotFoundError, CreoleClientError
|
||||
from creole.error import UserExit, UserExitError
|
||||
|
||||
from creole.eoleversion import EOLE_RELEASE, LAST_RELEASE, EOLE_VERSION
|
||||
|
||||
from pyeole.lock import acquire, release, is_locked
|
||||
from pyeole.log import init_logging, set_formatter
|
||||
from pyeole.ihm import question_ouinon, only_root, catch_signal
|
||||
from pyeole.encode import normalize
|
||||
|
||||
from pyeole.pkg import EolePkg, _configure_sources_mirror, report
|
||||
|
||||
from pyeole.diagnose import test_tcp
|
||||
from pyeole import scriptargs
|
||||
|
||||
from pyeole.i18n import i18n
|
||||
|
||||
_ = i18n('creole')
|
||||
|
||||
#import logging
|
||||
|
||||
log = None
|
||||
|
||||
only_root()
|
||||
|
||||
try:
|
||||
# FIXME : refactorer le système de lock de zephir-client (ref #6660)
|
||||
from zephir.lib_zephir import lock, unlock
|
||||
zephir_libs = True
|
||||
except Exception:
|
||||
zephir_libs = False
|
||||
|
||||
def release_lock():
|
||||
if zephir_libs:
|
||||
unlock('maj')
|
||||
if is_locked('majauto', level='system'):
|
||||
release('majauto', level='system')
|
||||
|
||||
def user_exit(*args, **kwargs):
|
||||
"""
|
||||
sortie utilisateur "propre"
|
||||
"""
|
||||
log.warn(_(u'! Abandoning configuration !'))
|
||||
log.warn(_(u'System may be in an incoherent state.\n\n'))
|
||||
raise UserExitError()
|
||||
|
||||
|
||||
def parse_cmdline():
|
||||
"""Parse commande line.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog='Maj-Auto|Query-Auto',
|
||||
description=_(u"Manage EOLE server automatic update"),
|
||||
parents=[scriptargs.logging('info')],
|
||||
add_help=False)
|
||||
|
||||
parser.add_argument('-h', '--help',
|
||||
action='help',
|
||||
help=_(u"show this help message and exit"))
|
||||
parser.add_argument('-n', '--dry-run',
|
||||
action='store_true',
|
||||
help=_(u"run in dry-run mode (force to True when using Query-Auto)."))
|
||||
parser.add_argument('-f', '--force',
|
||||
action='store_true',
|
||||
help=_(u"bypass Zephir authorizations."))
|
||||
parser.add_argument('-F', '--force-update',
|
||||
action='store_true',
|
||||
help=_(u"update your server without any confirmation."))
|
||||
|
||||
parser.add_argument('-s', '--simulate',
|
||||
action='store_true',
|
||||
help=_(u"ask apt-get to simulate packages installation"))
|
||||
|
||||
# Level of upgrade
|
||||
maj_level = parser.add_mutually_exclusive_group()
|
||||
maj_level.add_argument('-C', '--candidat', default=False,
|
||||
action='store', nargs='*',
|
||||
choices=['eole', 'envole'],
|
||||
help=_(u"use testing packages."))
|
||||
maj_level.add_argument('-D', '--devel', default=False,
|
||||
action='store', nargs='*',
|
||||
choices=['eole', 'envole'],
|
||||
help=_(u"use development packages."))
|
||||
|
||||
parser.add_argument('--release',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
# Action when upgrade is OK
|
||||
parser.add_argument('-r', '--reconfigure',
|
||||
action='store_true',
|
||||
help=_(u"run reconfigure on successful upgrade."))
|
||||
|
||||
parser.add_argument('-R', '--reboot',
|
||||
action='store_true',
|
||||
help=_(u"run reconfigure on successful upgrade and reboot if necessary (implies -r)."))
|
||||
parser.add_argument('--download', action='store_true',
|
||||
help=_(u'only download packages in cache.'))
|
||||
# Mirror selection
|
||||
parser.add_argument('-S', '--eole-mirror',
|
||||
help=_(u"EOLE repository server."))
|
||||
parser.add_argument('-U', '--ubuntu-mirror',
|
||||
help=_(u"Ubuntu repository server."))
|
||||
parser.add_argument('-V', '--envole-mirror',
|
||||
help=_(u"Envole repository server."))
|
||||
parser.add_argument('-c', '--cdrom', action="store_true",
|
||||
help=_(u"use CDROM as source."))
|
||||
|
||||
# sortie EAD
|
||||
parser.add_argument('-W', action='store_true',
|
||||
help=_(u"specific output for EAD."))
|
||||
# mode sans creoled
|
||||
parser.add_argument('-i', '--ignore', action='store_true',
|
||||
help=_(u"ignore local configuration if creoled not responding."))
|
||||
|
||||
|
||||
opts = parser.parse_args()
|
||||
|
||||
if getattr(opts, 'level', None) is None:
|
||||
opts.level = u'updates'
|
||||
if opts.verbose:
|
||||
opts.log_level = 'info'
|
||||
if opts.debug:
|
||||
opts.log_level = 'debug'
|
||||
|
||||
if opts.reboot:
|
||||
opts.reconfigure = True
|
||||
|
||||
return opts
|
||||
|
||||
|
||||
def main():
|
||||
global log
|
||||
opts = parse_cmdline()
|
||||
if opts.W:
|
||||
# variable set for pyeole.ansiprint
|
||||
environ['ModeTxt'] = 'yes'
|
||||
reporting = not (opts.dry_run or opts.simulate or opts.download)
|
||||
if not reporting:
|
||||
z_proc = 'QUERY-MAJ'
|
||||
log = init_logging(name=basename(sys.argv[0]), level=opts.log_level)
|
||||
pkg_log = init_logging(name='pyeole.pkg', level=opts.log_level)
|
||||
diag_log = init_logging(name='pyeole.diagnose', level=opts.log_level)
|
||||
else:
|
||||
z_proc = 'MAJ'
|
||||
report_file = '/var/lib/eole/reports/rapport-maj.log'
|
||||
if isfile(report_file):
|
||||
unlink(report_file)
|
||||
log = init_logging(name=basename(sys.argv[0]), level=opts.log_level,
|
||||
filename=report_file)
|
||||
pkg_log = init_logging(name='pyeole.pkg', level=opts.log_level,
|
||||
filename=report_file)
|
||||
diag_log = init_logging(name='pyeole.diagnose', level=opts.log_level,
|
||||
filename=report_file)
|
||||
set_formatter(log, u'file', u'brief')
|
||||
set_formatter(log, u'file', u'with-levelname-date')
|
||||
set_formatter(pkg_log, u'file', u'with-levelname-date')
|
||||
set_formatter(diag_log, u'file', u'with-levelname-date')
|
||||
report(2)
|
||||
locale.setlocale(locale.LC_TIME, "fr_FR.utf8")
|
||||
log.info(_(u'Update at {0}').format(time.strftime("%A %d %B %Y %H:%M:%S")))
|
||||
raised_err = None
|
||||
error_msg = None
|
||||
try:
|
||||
# gestion du ctrl+c
|
||||
catch_signal(user_exit)
|
||||
acquire('majauto', level='system')
|
||||
atexit.register(release_lock)
|
||||
client = CreoleClient()
|
||||
eole_level = 'stable'
|
||||
envole_level = 'stable'
|
||||
try:
|
||||
version = client.get_creole('eole_release')
|
||||
except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err:
|
||||
if opts.ignore:
|
||||
version = EOLE_RELEASE
|
||||
else:
|
||||
raise err
|
||||
if opts.candidat is not False:
|
||||
z_level = " en candidate"
|
||||
# Gestion du niveau par dépôt (16110)
|
||||
if len(opts.candidat) == 0:
|
||||
# Si on ne précise aucun dépôt tout le monde va en candidat
|
||||
eole_level = 'proposed'
|
||||
envole_level = 'proposed'
|
||||
else:
|
||||
# Sinon on vérifie dépôt par dépôt, les dépôts non précisés restent en stable
|
||||
if 'eole' in opts.candidat:
|
||||
eole_level = 'proposed'
|
||||
if 'envole' in opts.candidat:
|
||||
envole_level = 'proposed'
|
||||
elif opts.devel is not False:
|
||||
z_level = " en devel"
|
||||
# Gestion du niveau par dépôt (16110)
|
||||
if len(opts.devel) == 0:
|
||||
# Si on ne précise aucun dépôt tout le monde vas en candidat
|
||||
eole_level = 'unstable'
|
||||
envole_level = 'unstable'
|
||||
else:
|
||||
# Sinon on vérifie dépôt par dépôt, les dépôts non précisés restent en stable
|
||||
if 'eole' in opts.devel:
|
||||
eole_level = 'unstable'
|
||||
if 'envole' in opts.devel:
|
||||
envole_level = 'unstable'
|
||||
else:
|
||||
z_level = ""
|
||||
if opts.release:
|
||||
current_release = int(EOLE_RELEASE.split('.')[-1])
|
||||
new_release = opts.release.split('.')
|
||||
if len(new_release) != 3 or \
|
||||
u'.'.join(new_release[0:2]) != EOLE_VERSION or \
|
||||
int(new_release[2]) not in range(current_release+1, int(LAST_RELEASE) + 1):
|
||||
raise Exception(_('Unknown release number'))
|
||||
z_level += " en {0}".format(opts.release)
|
||||
version = opts.release
|
||||
if opts.cdrom:
|
||||
z_level += " via le CDROM"
|
||||
#distro = 'stable'
|
||||
fonctionseole.zephir("INIT", "Début{0}".format(z_level), z_proc)
|
||||
if zephir_libs and not fonctionseole.init_proc('MAJ'):
|
||||
if opts.force:
|
||||
fonctionseole.zephir("MSG",
|
||||
"Mise à jour forcée par l'utilisateur",
|
||||
z_proc)
|
||||
else:
|
||||
log.warn(_(u"Update is locked, please contact Zéphir administrator"))
|
||||
log.warn(_(u"Use -f option if you want to force execution"))
|
||||
raise UserExitError()
|
||||
lock('maj')
|
||||
PKGMGR = EolePkg('apt', ignore=opts.ignore)
|
||||
if opts.dry_run:
|
||||
PKGMGR.set_option('APT::Get::Simulate', 'true')
|
||||
|
||||
try:
|
||||
module = client.get_creole('eole_module')
|
||||
except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err:
|
||||
if opts.ignore:
|
||||
module = 'module'
|
||||
else:
|
||||
raise err
|
||||
try:
|
||||
uai = client.get_creole('numero_etab')
|
||||
except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err:
|
||||
if opts.ignore:
|
||||
uai = None
|
||||
else:
|
||||
raise err
|
||||
|
||||
head = "*** {0} {1}"
|
||||
if uai:
|
||||
head += " ({2})"
|
||||
head += " ***\n"
|
||||
|
||||
log.info(head.format(module, version, uai))
|
||||
|
||||
if not opts.force_update:
|
||||
raising_level = u''
|
||||
if opts.release:
|
||||
raising_level = _(u"(CHANGE RELEASE LEVEL)")
|
||||
elif u'unstable' in [eole_level, envole_level]:
|
||||
raising_level = _(u"(UNSTABLE VERSION)")
|
||||
elif u'proposed' in [eole_level, envole_level]:
|
||||
raising_level = _(u"(TESTING VERSION)")
|
||||
|
||||
if raising_level != u'':
|
||||
log.warn(_(u"{0} - Raising update level may prevent "
|
||||
u"lowering back to stable version.").format(raising_level))
|
||||
try:
|
||||
assert question_ouinon(_(u"Do you wish to proceed?")) == 'oui'
|
||||
fonctionseole.zephir("MSG",
|
||||
"Mise à jour{0} forcée par l'utilisateur".format(z_level),
|
||||
z_proc)
|
||||
except (AssertionError, EOFError) as err:
|
||||
log.warn(_(u"Cancelling!"))
|
||||
raise UserExit()
|
||||
|
||||
PKGMGR.check()
|
||||
|
||||
#serveurs à utiliser pour les dépôts Ubuntu et EOLE
|
||||
_configure_sources_mirror(PKGMGR.pkgmgr, ubuntu=opts.ubuntu_mirror,
|
||||
eole=opts.eole_mirror, envole=opts.envole_mirror,
|
||||
ignore=opts.ignore, cdrom=opts.cdrom,
|
||||
release=version, eole_level=eole_level,
|
||||
envole_level=envole_level)
|
||||
|
||||
|
||||
PKGMGR.update(silent=True)
|
||||
upgrades = PKGMGR.get_upgradable_list()
|
||||
|
||||
install = 0
|
||||
upgrade = 0
|
||||
delete = 0
|
||||
for container, packages in upgrades.items():
|
||||
if not packages:
|
||||
continue
|
||||
for name, isInstalled, candidateVersion in packages:
|
||||
if isInstalled:
|
||||
if candidateVersion is None:
|
||||
delete += 1
|
||||
else:
|
||||
upgrade += 1
|
||||
else:
|
||||
install += 1
|
||||
|
||||
total_pkg = install+upgrade
|
||||
|
||||
headers = []
|
||||
if total_pkg == 0:
|
||||
log.info(_(u"Update successful."))
|
||||
log.info(_(u"Nothing to install."))
|
||||
fonctionseole.zephir("FIN",
|
||||
"Aucun paquet à installer{0}".format(z_level),
|
||||
z_proc)
|
||||
if reporting:
|
||||
report(3)
|
||||
sys.exit(0)
|
||||
|
||||
headers.append(_(u"{0} new,", u"{0} news,", install).format(install))
|
||||
headers.append(_(u"{0} upgrade,", u"{0} upgrades,", upgrade).format(upgrade))
|
||||
headers.append(_(u"{0} delete", u"{0} deletes", delete).format(delete))
|
||||
log.info(' '.join(headers))
|
||||
|
||||
for line in PKGMGR.list_upgrade(upgrades=upgrades):
|
||||
log.info(line)
|
||||
|
||||
if opts.dry_run:
|
||||
fonctionseole.zephir("FIN",
|
||||
"{0} paquets à mettre à jour{1}".format(total_pkg, z_level),
|
||||
z_proc)
|
||||
sys.exit(0)
|
||||
|
||||
if opts.download:
|
||||
for container, packages in upgrades.items():
|
||||
if not packages:
|
||||
continue
|
||||
pkgs = []
|
||||
for name, isInstalled, candidateVersion in packages:
|
||||
pkgs.append(name)
|
||||
PKGMGR.fetch_archives(container=container, packages=pkgs)
|
||||
fonctionseole.zephir("FIN",
|
||||
"{0} paquets téléchargés{1}".format(total_pkg, z_level),
|
||||
z_proc)
|
||||
|
||||
elif opts.simulate:
|
||||
PKGMGR.dist_upgrade(simulate=opts.simulate)
|
||||
fonctionseole.zephir("FIN",
|
||||
"{0} paquets mis à jour (simulation){1}".format(total_pkg, z_level),
|
||||
z_proc)
|
||||
|
||||
else:
|
||||
PKGMGR.download_upgrade()
|
||||
PKGMGR.dist_upgrade(simulate=opts.simulate)
|
||||
log.info(_(u"Update successful."))
|
||||
fonctionseole.zephir("FIN",
|
||||
"{0} paquets mis à jour{1}".format(total_pkg, z_level),
|
||||
z_proc)
|
||||
if opts.release:
|
||||
ret_code = system('/usr/share/zephir/scripts/upgrade_distrib.py --auto')
|
||||
if ret_code != 0:
|
||||
error_msg = str('erreur à la mise à jour vers la release {0}'.format(opts.release))
|
||||
else:
|
||||
log.info(_('Upgrade post Maj-Release, please wait'))
|
||||
release('majauto', level='system')
|
||||
cmd = ['/usr/bin/Maj-Auto', '-F']
|
||||
process = Popen(cmd, stdin=PIPE, stderr=PIPE, stdout=PIPE, shell=False)
|
||||
ret_code = process.wait()
|
||||
if ret_code != 0:
|
||||
error_msg = str(_('error in post maj release'))
|
||||
if opts.reconfigure:
|
||||
# rechargement des modules python (#7832)
|
||||
# cf. http://code.activestate.com/recipes/81731-reloading-all-modules/
|
||||
if globals().has_key('init_modules'):
|
||||
for m in [x for x in sys.modules.keys() if x not in init_modules]:
|
||||
del(sys.modules[m])
|
||||
else:
|
||||
init_modules = sys.modules.keys()
|
||||
fonctionseole.zephir("MSG",
|
||||
"Reconfiguration automatique",
|
||||
z_proc)
|
||||
elif not opts.release:
|
||||
log.warn(_(u"At least one packages has been updated,"
|
||||
u" use command [reconfigure] to apply modifications."))
|
||||
fonctionseole.zephir("MSG",
|
||||
"Reconfiguration du serveur à planifier",
|
||||
z_proc)
|
||||
|
||||
except (UserExit, UserExitError) as err:
|
||||
if reporting:
|
||||
report(1, 'Stopped by user')
|
||||
fonctionseole.zephir("FIN", "Abandon par l'utilisateur", z_proc)
|
||||
sys.exit(1)
|
||||
|
||||
except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err:
|
||||
clue = _(". If restarting creoled service does not help, try {} command with '-i' option.")
|
||||
error_msg = str(err) + clue.format('Query-Auto' if opts.dry_run else 'Maj-Auto')
|
||||
raised_err = err
|
||||
|
||||
except Exception as err:
|
||||
error_msg = str(err)
|
||||
raised_err = err
|
||||
else:
|
||||
if reporting:
|
||||
report(0, reconf=opts.reconfigure)
|
||||
|
||||
if error_msg is not None:
|
||||
fonctionseole.zephir("ERR", error_msg, z_proc, console=False)
|
||||
if reporting:
|
||||
if raised_err is not None:
|
||||
report(1, normalize(err))
|
||||
else:
|
||||
report(1, error_msg)
|
||||
if log is None:
|
||||
# No logger defined, error in argument parsing
|
||||
raise
|
||||
if opts.log_level == 'debug' and raised_err is not None:
|
||||
log.error(err, exc_info=True)
|
||||
else:
|
||||
log.error(error_msg)
|
||||
sys.exit(1)
|
||||
|
||||
if opts.reconfigure:
|
||||
try:
|
||||
reconfigure.main(force_options={'auto': opts.reboot, 'log_level': opts.log_level},
|
||||
force_args=[], need_lock=False)
|
||||
except Exception as err:
|
||||
fonctionseole.zephir("ERR", str(err), z_proc, console=False)
|
||||
if reporting:
|
||||
report(1, normalize(err))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user