Move moulinette initialization and other stuff to src/yunohost/__init__.py

This commit is contained in:
Alexandre Aubin 2020-04-22 18:41:54 +02:00
parent 233c962710
commit dee08a16fe
3 changed files with 216 additions and 191 deletions

View file

@ -4,34 +4,29 @@
import os import os
import sys import sys
import argparse import argparse
import glob
import moulinette sys.path.insert(0, "/usr/lib/moulinette/")
import yunohost
# Directory and file to be used by logging
LOG_DIR = '/var/log/yunohost'
LOG_FILE = 'yunohost-cli.log'
# Initialization & helpers functions -----------------------------------
def _parse_cli_args(): def _parse_cli_args():
"""Parse additional arguments for the cli""" """Parse additional arguments for the cli"""
parser = argparse.ArgumentParser(add_help=False) parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--output-as', parser.add_argument('--output-as',
choices=['json', 'plain', 'none'], default=None, choices=['json', 'plain', 'none'], default=None,
help="Output result in another format", help="Output result in another format"
) )
parser.add_argument('--debug', parser.add_argument('--debug',
action='store_true', default=False, action='store_true', default=False,
help="Log and print debug messages", help="Log and print debug messages"
) )
parser.add_argument('--quiet', parser.add_argument('--quiet',
action='store_true', default=False, action='store_true', default=False,
help="Don't produce any output", help="Don't produce any output"
) )
parser.add_argument('--timeout', parser.add_argument('--timeout',
type=int, default=None, type=int, default=None,
help="Number of seconds before this command will timeout because it can't acquire the lock (meaning that another command is currently running), by default there is no timeout and the command will wait until it can get the lock", help="Number of seconds before this command will timeout because it can't acquire the lock (meaning that another command is currently running), by default there is no timeout and the command will wait until it can get the lock"
) )
# deprecated arguments # deprecated arguments
parser.add_argument('--plain', parser.add_argument('--plain',
@ -52,72 +47,6 @@ def _parse_cli_args():
return (parser, opts, args) return (parser, opts, args)
def init(debug=False, quiet=False, logfile='%s/%s' % (LOG_DIR, LOG_FILE)):
logdir = os.path.dirname(logfile)
if not os.path.isdir(logdir):
os.makedirs(logdir, 0750)
moulinette.init(logging_config={
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'tty-debug': {
'format': '%(relativeCreated)-4d %(fmessage)s'
},
'precise': {
'format': '%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s'
},
},
'filters': {
'action': {
'()': 'moulinette.utils.log.ActionFilter',
},
},
'handlers': {
'tty': {
'level': 'DEBUG' if debug else 'INFO',
'class': 'moulinette.interfaces.cli.TTYHandler',
'formatter': 'tty-debug' if debug else '',
},
'file': {
'class': 'logging.FileHandler',
'formatter': 'precise',
'filename': logfile,
'filters': ['action'],
},
},
'loggers': {
'yunohost': {
'level': 'DEBUG',
'handlers': ['file', 'tty'] if not quiet else ['file'],
'propagate': False,
},
'moulinette': {
'level': 'DEBUG',
'handlers': [],
'propagate': True,
},
'moulinette.interface': {
'level': 'DEBUG',
'handlers': ['file', 'tty'] if not quiet else ['file'],
'propagate': False,
},
},
'root': {
'level': 'DEBUG',
'handlers': ['file', 'tty'] if debug else ['file'],
},
})
def _retrieve_namespaces():
"""Return the list of namespaces to load"""
extensions = [n for n in ActionsMap.get_namespaces() if n.startswith('ynh_')]
return ['yunohost'] + extensions
# Stupid PATH management because sometimes (e.g. some cron job) PATH is only /usr/bin:/bin ... # Stupid PATH management because sometimes (e.g. some cron job) PATH is only /usr/bin:/bin ...
default_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" default_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
if os.environ["PATH"] != default_path: if os.environ["PATH"] != default_path:
@ -127,38 +56,18 @@ if os.environ["PATH"] != default_path:
if __name__ == '__main__': if __name__ == '__main__':
if os.geteuid() != 0: if os.geteuid() != 0:
# since moulinette isn't initialized, we can't use m18n here
sys.stderr.write("\033[1;31mError:\033[0m yunohost command must be " sys.stderr.write("\033[1;31mError:\033[0m yunohost command must be "
"run as root or with sudo.\n") "run as root or with sudo.\n")
sys.exit(1) sys.exit(1)
parser, opts, args = _parse_cli_args() parser, opts, args = _parse_cli_args()
init(debug=opts.debug, quiet=opts.quiet)
# Check that YunoHost is installed
allowed_if_not_installed = ['tools postinstall', 'backup restore', 'log display']
if not os.path.isfile('/etc/yunohost/installed') and \
(len(args) < 2 or (args[0] + ' ' + args[1] not in allowed_if_not_installed)):
from moulinette import m18n
from moulinette.interfaces.cli import colorize, get_locale
# Init i18n
m18n.load_namespace('yunohost')
m18n.set_locale(get_locale())
# Print error and exit
print(colorize(m18n.g('error'), 'red') + " " + m18n.n('yunohost_not_installed'))
sys.exit(1)
extensions = [f.split('/')[-1][:-4] for f in glob.glob("/usr/share/moulinette/actionsmap/ynh_*.yml")]
# Execute the action # Execute the action
ret = moulinette.cli( yunohost.cli(
['yunohost'] + extensions, debug=opts.debug,
args, quiet=opts.quiet,
output_as=opts.output_as, output_as=opts.output_as,
timeout=opts.timeout, timeout=opts.timeout,
parser_kwargs={'top_parser': parser}, args=args,
parser=parser
) )
sys.exit(ret)

View file

@ -1,23 +1,16 @@
#! /usr/bin/python #! /usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import sys import sys
import argparse import argparse
import glob
import moulinette sys.path.insert(0, "/usr/lib/moulinette/")
import yunohost
# Default server configuration # Default server configuration
DEFAULT_HOST = 'localhost' DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 6787 DEFAULT_PORT = 6787
# Directory and file to be used by logging
LOG_DIR = '/var/log/yunohost'
LOG_FILE = 'yunohost-api.log'
# Initialization & helpers functions -----------------------------------
def _parse_api_args(): def _parse_api_args():
"""Parse main arguments for the api""" """Parse main arguments for the api"""
@ -45,86 +38,7 @@ def _parse_api_args():
return parser.parse_args() return parser.parse_args()
def init_api(debug=False, logfile='%s/%s' % (LOG_DIR, LOG_FILE)):
logdir = os.path.dirname(logfile)
if not os.path.isdir(logdir):
os.makedirs(logdir, 0750)
moulinette.init(logging_config={
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'console': {
'format': '%(relativeCreated)-5d %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s'
},
'precise': {
'format': '%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s'
},
},
'filters': {
'action': {
'()': 'moulinette.utils.log.ActionFilter',
},
},
'handlers': {
'api': {
'level': 'DEBUG' if debug else 'INFO',
'class': 'moulinette.interfaces.api.APIQueueHandler',
},
'file': {
'class': 'logging.handlers.WatchedFileHandler',
'formatter': 'precise',
'filename': logfile,
'filters': ['action'],
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'console',
'stream': 'ext://sys.stdout',
'filters': ['action'],
},
},
'loggers': {
'yunohost': {
'level': 'DEBUG',
'handlers': ['file', 'api'] + ['console'] if debug else [],
'propagate': False,
},
'moulinette': {
'level': 'DEBUG',
'handlers': [],
'propagate': True,
},
},
'root': {
'level': 'DEBUG',
'handlers': ['file'] + ['console'] if debug else [],
},
})
# Callbacks for additional routes --------------------------------------
def is_installed():
""" Check whether YunoHost is installed or not """
return {'installed': os.path.isfile('/etc/yunohost/installed')}
# Main action ----------------------------------------------------------
if __name__ == '__main__': if __name__ == '__main__':
opts = _parse_api_args() opts = _parse_api_args()
init_api(opts.debug)
extensions = [f.split('/')[-1][:-4] for f in glob.glob("/usr/share/moulinette/actionsmap/ynh_*.yml")]
# Run the server # Run the server
ret = moulinette.api( yunohost.api(debug=opts.debug, host=opts.host, port=opts.port)
['yunohost'] + extensions,
host=opts.host,
port=opts.port,
routes={('GET', '/installed'): is_installed},
use_websocket=True
)
sys.exit(ret)

View file

@ -0,0 +1,202 @@
#! /usr/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import glob
import moulinette
from moulinette.utils.log import configure_logging
def is_installed():
return os.path.isfile('/etc/yunohost/installed')
def cli(debug, quiet, output_as, timeout, args, parser):
init_logging(interface="cli", debug=debug, quiet=quiet)
# Check that YunoHost is installed
if not is_installed():
check_command_is_valid_before_postinstall(args)
ret = moulinette.cli(
['yunohost'] + extensions(),
args,
output_as=output_as,
timeout=timeout,
parser_kwargs={'top_parser': parser},
)
sys.exit(ret)
def api(debug, host, port):
init_logging(debug=debug)
def is_installed_api():
return {'installed': is_installed()}
# FIXME : someday, maybe find a way to disable route /postinstall if
# postinstall already done ...
ret = moulinette.api(
['yunohost'] + extensions(),
host=host,
port=port,
routes={('GET', '/installed'): is_installed_api},
use_websocket=True
)
sys.exit(ret)
def extensions():
# This is probably not used anywhere, but the actionsmap and code can be
# extended by creating such files that contain bits of actionmap...
return [f.split('/')[-1][:-4] for f in glob.glob("/usr/share/moulinette/actionsmap/ynh_*.yml")]
def check_command_is_valid_before_postinstall(args):
allowed_if_not_postinstalled = ['tools postinstall',
'tools versions',
'backup list',
'backup restore',
'log display']
if (len(args) < 2 or (args[0] + ' ' + args[1] not in allowed_if_not_postinstalled)):
# This function is called before m18n is initialized, so we only initialized
# the specific bit to be able to call m18n.n/g()...
from moulinette import m18n
from moulinette.interfaces.cli import colorize, get_locale
# Init i18n
m18n.load_namespace('yunohost')
m18n.set_locale(get_locale())
print(colorize(m18n.g('error'), 'red') + " " + m18n.n('yunohost_not_installed'))
sys.exit(1)
def init_logging(interface="cli",
debug=False,
quiet=False,
logdir="/var/log/yunohost"):
logfile = os.path.join(logdir, "yunohost-%s.log" % interface)
if not os.path.isdir(logdir):
os.makedirs(logdir, 0750)
# ####################################################################### #
# Logging configuration for CLI (or any other interface than api...) #
# ####################################################################### #
if interface != "api":
configure_logging({
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'tty-debug': {
'format': '%(relativeCreated)-4d %(fmessage)s'
},
'precise': {
'format': '%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s'
},
},
'filters': {
'action': {
'()': 'moulinette.utils.log.ActionFilter',
},
},
'handlers': {
'tty': {
'level': 'DEBUG' if debug else 'INFO',
'class': 'moulinette.interfaces.cli.TTYHandler',
'formatter': 'tty-debug' if debug else '',
},
'file': {
'class': 'logging.FileHandler',
'formatter': 'precise',
'filename': logfile,
'filters': ['action'],
},
},
'loggers': {
'yunohost': {
'level': 'DEBUG',
'handlers': ['file', 'tty'] if not quiet else ['file'],
'propagate': False,
},
'moulinette': {
'level': 'DEBUG',
'handlers': [],
'propagate': True,
},
'moulinette.interface': {
'level': 'DEBUG',
'handlers': ['file', 'tty'] if not quiet else ['file'],
'propagate': False,
},
},
'root': {
'level': 'DEBUG',
'handlers': ['file', 'tty'] if debug else ['file'],
},
})
# ####################################################################### #
# Logging configuration for API #
# ####################################################################### #
else:
configure_logging({
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'console': {
'format': '%(relativeCreated)-5d %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s'
},
'precise': {
'format': '%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s'
},
},
'filters': {
'action': {
'()': 'moulinette.utils.log.ActionFilter',
},
},
'handlers': {
'api': {
'level': 'DEBUG' if debug else 'INFO',
'class': 'moulinette.interfaces.api.APIQueueHandler',
},
'file': {
'class': 'logging.handlers.WatchedFileHandler',
'formatter': 'precise',
'filename': logfile,
'filters': ['action'],
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'console',
'stream': 'ext://sys.stdout',
'filters': ['action'],
},
},
'loggers': {
'yunohost': {
'level': 'DEBUG',
'handlers': ['file', 'api'] + ['console'] if debug else [],
'propagate': False,
},
'moulinette': {
'level': 'DEBUG',
'handlers': [],
'propagate': True,
},
},
'root': {
'level': 'DEBUG',
'handlers': ['file'] + ['console'] if debug else [],
},
})