Manual merge with unstable

This commit is contained in:
Julien Malik 2016-03-31 17:20:11 +02:00
commit 3ef177ea3b
22 changed files with 387 additions and 1430 deletions

View file

@ -1,8 +1,13 @@
#!/usr/bin/env python
#! /usr/bin/python
# -*- coding: utf-8 -*-
import sys
import os
import sys
import argparse
import moulinette
from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import colorize, get_locale
# Either we are in a development environment or not
IN_DEVEL = False
@ -34,17 +39,11 @@ if IN_DEVEL:
def _die(message, title='Error:'):
"""Print error message and exit"""
try:
from moulinette.interfaces.cli import colorize
except ImportError:
colorize = lambda msg, c: msg
print('%s %s' % (colorize(title, 'red'), message))
sys.exit(1)
def _parse_cli_args():
"""Parse additional arguments for the cli"""
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--no-cache',
action='store_false', default=True, dest='use_cache',
@ -90,8 +89,6 @@ def _parse_cli_args():
def _init_moulinette(debug=False, verbose=False, quiet=False):
"""Configure logging and initialize the moulinette"""
from moulinette import init
# Define loggers handlers
handlers = set(LOGGERS_HANDLERS)
if quiet and 'tty' in handlers:
@ -100,7 +97,7 @@ def _init_moulinette(debug=False, verbose=False, quiet=False):
handlers.append('tty')
root_handlers = set(handlers)
if not debug:
if not debug and 'tty' in root_handlers:
root_handlers.remove('tty')
# Define loggers level
@ -167,11 +164,10 @@ def _init_moulinette(debug=False, verbose=False, quiet=False):
_die(str(e))
# Initialize moulinette
init(logging_config=logging, _from_source=IN_DEVEL)
moulinette.init(logging_config=logging, _from_source=IN_DEVEL)
def _retrieve_namespaces():
"""Return the list of namespaces to load"""
from moulinette.actionsmap import ActionsMap
ret = ['yunohost']
for n in ActionsMap.get_namespaces():
# Append YunoHost modules
@ -190,8 +186,6 @@ if __name__ == '__main__':
if not os.path.isfile('/etc/yunohost/installed') and \
(len(args) < 2 or (args[0] +' '+ args[1] != 'tools postinstall' and \
args[0] +' '+ args[1] != 'backup restore')):
from moulinette.interfaces.cli import get_locale
# Init i18n
m18n.load_namespace('yunohost')
m18n.set_locale(get_locale())
@ -200,9 +194,9 @@ if __name__ == '__main__':
_die(m18n.n('yunohost_not_installed'), m18n.g('error'))
# Execute the action
from moulinette import cli
ret = cli(_retrieve_namespaces(), args,
use_cache=opts.use_cache, output_as=opts.output_as,
password=opts.password, parser_kwargs={'top_parser': parser}
ret = moulinette.cli(
_retrieve_namespaces(), args,
use_cache=opts.use_cache, output_as=opts.output_as,
password=opts.password, parser_kwargs={'top_parser': parser}
)
sys.exit(ret)

View file

@ -1,8 +1,13 @@
#!/usr/bin/env python
#! /usr/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import os.path
import argparse
import moulinette
from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import colorize
# Either we are in a development environment or not
IN_DEVEL = False
@ -38,17 +43,11 @@ if IN_DEVEL:
def _die(message, title='Error:'):
"""Print error message and exit"""
try:
from moulinette.interfaces.cli import colorize
except ImportError:
colorize = lambda msg, c: msg
print('%s %s' % (colorize(title, 'red'), message))
sys.exit(1)
def _parse_api_args():
"""Parse main arguments for the api"""
import argparse
parser = argparse.ArgumentParser(add_help=False,
description="Run the YunoHost API to manage your server.",
)
@ -87,8 +86,6 @@ def _parse_api_args():
def _init_moulinette(use_websocket=True, debug=False, verbose=False):
"""Configure logging and initialize the moulinette"""
from moulinette import init
# Define loggers handlers
handlers = set(LOGGERS_HANDLERS)
if not use_websocket and 'api' in handlers:
@ -162,11 +159,10 @@ def _init_moulinette(use_websocket=True, debug=False, verbose=False):
_die(str(e))
# Initialize moulinette
init(logging_config=logging, _from_source=IN_DEVEL)
moulinette.init(logging_config=logging, _from_source=IN_DEVEL)
def _retrieve_namespaces():
"""Return the list of namespaces to load"""
from moulinette.actionsmap import ActionsMap
ret = ['yunohost']
for n in ActionsMap.get_namespaces():
# Append YunoHost modules
@ -195,14 +191,12 @@ if __name__ == '__main__':
_init_moulinette(opts.use_websocket, opts.debug, opts.verbose)
# Run the server
from moulinette import api, MoulinetteError
from yunohost.utils.packages import ynh_packages_version
ret = api(_retrieve_namespaces(),
host=opts.host, port=opts.port,
routes={
('GET', '/installed'): is_installed,
('GET', '/version'): ynh_packages_version,
},
use_cache=opts.use_cache, use_websocket=opts.use_websocket
ret = moulinette.api(
_retrieve_namespaces(),
host=opts.host, port=opts.port, routes={
('GET', '/installed'): is_installed,
('GET', '/version'): ynh_packages_version,
}, use_cache=opts.use_cache, use_websocket=opts.use_websocket
)
sys.exit(ret)

View file

@ -334,7 +334,7 @@ app:
arguments:
-u:
full: --url
help: URL of remote JSON list (default https://yunohost.org/official.json)
help: URL of remote JSON list (default https://app.yunohost.org/official.json)
-n:
full: --name
help: Name of the list (default yunohost)
@ -377,6 +377,14 @@ app:
full: --raw
help: Return the full app_dict
action: store_true
-i:
full: --installed
help: Return only installed apps
action: store_true
-b:
full: --with-backup
help: Return only apps with backup feature (force --installed filter)
action: store_true
### app_info()
info:
@ -428,7 +436,7 @@ app:
help: Custom name for the app
-a:
full: --args
help: Serialize arguments for app installation
help: Serialized arguments for app script (i.e. "domain=domain.tld&path=/path")
### app_remove() TODO: Write help
remove:
@ -639,6 +647,8 @@ backup:
action_help: Restore from a local backup archive
api: POST /backup/restore/<name>
configuration:
authenticate: all
authenticator: ldap-anonymous
lock: false
arguments:
name:
@ -969,7 +979,6 @@ service:
action_help: >
Check if the specific file has been modified and display differences.
Stores the file hash in the services.yml file
api: PUT /services/safecopy
arguments:
new_conf_file:
help: Path to the desired conf file
@ -990,7 +999,6 @@ service:
action_help: >
Check if the specific file has been modified before removing it.
Backup the file in /home/yunohost.backup
api: PUT /services/safecopy
arguments:
conf_file:
help: Path to the targeted conf file
@ -1159,10 +1167,10 @@ dyndns:
arguments:
--dyn-host:
help: Dynette DNS server to inform
default: "dynhost.yunohost.org"
default: "dyndns.yunohost.org"
-d:
full: --domain
help: Full domain to subscribe with
help: Full domain to update
extra:
pattern: *pattern_domain
-k:
@ -1314,7 +1322,6 @@ hook:
### hook_add()
add:
action_help: Store hook script to filesystem
api: PUT /hook
arguments:
app:
help: App to link with
@ -1324,7 +1331,6 @@ hook:
### hook_remove()
remove:
action_help: Remove hook scripts from filesystem
api: DELETE /hook
arguments:
app:
help: Scripts related to app will be removed
@ -1362,7 +1368,7 @@ hook:
### hook_callback()
callback:
action_help: Execute all scripts binded to an action
api: GET /hooks
api: POST /hooks/<action>
arguments:
action:
help: Action name
@ -1378,7 +1384,6 @@ hook:
### hook_exec()
exec:
action_help: Execute hook from a file with arguments
api: GET /hook
arguments:
path:
help: Path of the script to execute
@ -1392,3 +1397,6 @@ hook:
full: --no-trace
help: Do not print each command that will be executed
action: store_true
-d:
full: --chdir
help: The directory from where the script will be executed

View file

@ -4,7 +4,7 @@
# | arg: app - the application id
# | arg: key - the setting to get
ynh_app_setting_get() {
sudo yunohost app setting "$1" "$2" --output-as plain
sudo yunohost app setting "$1" "$2" --output-as plain --quiet
}
# Set an application setting
@ -14,7 +14,7 @@ ynh_app_setting_get() {
# | arg: key - the setting name to set
# | arg: value - the setting value to set
ynh_app_setting_set() {
sudo yunohost app setting "$1" "$2" -v "$3"
sudo yunohost app setting "$1" "$2" -v "$3" --quiet
}
# Delete an application setting
@ -23,5 +23,5 @@ ynh_app_setting_set() {
# | arg: app - the application id
# | arg: key - the setting to delete
ynh_app_setting_delete() {
sudo yunohost app setting -d "$1" "$2"
sudo yunohost app setting -d "$1" "$2" --quiet
}

View file

@ -14,8 +14,11 @@ function safe_copy () {
cd /usr/share/yunohost/templates/rspamd
# Copy Rspamd configuration
safe_copy metrics.conf /etc/rspamd/metrics.conf
# Create configuration directories
sudo mkdir -p /etc/rspamd/local.d /etc/rspamd/override.d
# Copy specific configuration to rewrite the defaults
safe_copy metrics.conf.local /etc/rspamd/local.d/metrics.conf
# Install Rspamd sieve script
safe_copy rspamd.sieve /etc/dovecot/global_script/rspamd.sieve

View file

@ -17,11 +17,11 @@ function safe_copy () {
cd /usr/share/yunohost/templates/dnsmasq
# Get IPv4 address
ip=$(curl -s -4 https://ip.yunohost.org 2>/dev/null)
ip=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true)
ynh_validate_ip4 $ip || ip='0.0.0.0'
# Get IPv6 IP address
ipv6=$(curl -s -6 http://ip6.yunohost.org 2>/dev/null)
ipv6=$(curl -s -6 http://ip6.yunohost.org 2>/dev/null || true)
ynh_validate_ip6 $ipv6 || ipv6=''
sudo mkdir -p /etc/dnsmasq.d

View file

@ -29,11 +29,14 @@ server {
return 302 https://$http_host/yunohost/admin;
}
# Block crawlers bot
location /yunohost {
if ($http_user_agent ~ (crawl|Googlebot|Slurp|spider|bingbot|tracker|click|parser|spider|facebookexternalhit) ) {
return 403;
}
# Block crawlers bot
if ($http_user_agent ~ (crawl|Googlebot|Slurp|spider|bingbot|tracker|click|parser|spider|facebookexternalhit) ) {
return 403;
}
# Redirect most of 404 to maindomain.tld/yunohost/sso
access_by_lua_file /usr/share/ssowat/access.lua;
}
include conf.d/yunohost_admin.conf.inc;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
# Metrics settings
# This define overridden options.
actions {
reject = 21;
add_header = 8;
greylist = 4;
}

69
debian/changelog vendored
View file

@ -1,3 +1,66 @@
moulinette-yunohost (2.2.4) stable; urgency=low
[ Jérôme Lebleu ]
* [fix] Update first registered domain with DynDNS instead of current_host
* [fix] Set found private key and don't validate it in dyndns_update
* [fix] Use dyndns.yunohost.org instead of dynhost.yunohost.org
[ opi ]
* [fix] Catch ConnectionError from requests package
-- Jérôme Lebleu <jerome@yunohost.org> Sun, 27 Mar 2016 16:30:42 +0200
yunohost (2.3.11.2) testing; urgency=low
* [fix] Don't fail dnsmasq regen if IPv4/6 cannot be retrieved
-- Jérôme Lebleu <jerome@yunohost.org> Wed, 23 Mar 2016 14:57:22 +0100
yunohost (2.3.11.1) testing; urgency=low
* [deb] Include sysvinit services and files in the package, thanks to
nthykier and pabs from #debian-mentor
-- Jérôme Lebleu <jerome@yunohost.org> Wed, 23 Mar 2016 12:38:56 +0100
yunohost (2.3.11) testing; urgency=low
[ Laurent Peuch ]
* [mod] Explain how to start yunohost-firewall service
[ Jérôme Lebleu ]
* [fix] Remove useless API routes for some actions
* [fix] Update API route for hook_callback action
* [deb] Attempt to improve services management in Debian packaging
* [deb] Add missing cron dependency
* [deb] Clean debian/control with cosmetic changes
* [deb] Fix helpers bash script installation
[ Julien Malik ]
* [enh] Add helper for IP address validation
* [enh] move /usr/share/yunohost/apps/helpers to
/usr/share/yunohost/helpers since it became of more general use
* [enh] Remove unused checkupdate and upgrade scripts
* [fix] Validate IP addresses returned by ipX.yunohost.org
* [fix] fix lintian script-not-executable
* [deb] dh_python2 replaces shebang during build. Using the correct one
in source directly
[ Moul ]
* [enh] Add '-a' argument's usage example for app_install
[ opi ]
* [enh] Add diagnosis function. #39
* [enh] Redirect most of 404 to maindomain.tld/yunohost/sso
* [enh] Add --installed and --with-backup to app_list action (wip #227)
* [enh] More explicit backup forbidden directory error message.
* [enh] Use dedicated app list domain.
* [fix] Use only dyndns.yunohost.org domain.
* [fix] Use plain text 502 error page.
* [fix] Cleaner Nginx redirection rules. Use permanent only when paths match.
-- Jérôme Lebleu <jerome@yunohost.org> Wed, 23 Mar 2016 10:39:34 +0100
yunohost (2.3.10.2) testing; urgency=low
* [fix] Workaround for the bad people who are not using IPv6 yet
@ -332,12 +395,6 @@ moulinette-yunohost (2.3.0) testing; urgency=low
-- Jérôme Lebleu <jerome.lebleu@mailoo.org> Tue, 08 Sep 2015 14:19:28 +0200
moulinette-yunohost (2.2.3-1) stable; urgency=low
* [fix] Catch ConnectionError from requests package
-- opi <opi@zeropi.net> Sun, 06 Mar 2016 21:51:06 +0100
moulinette-yunohost (2.2.3) stable; urgency=low
* [fix] Catch proper exception in backup_list (fix #65)

77
debian/control vendored
View file

@ -9,50 +9,41 @@ Homepage: https://yunohost.org/
Package: yunohost
Architecture: all
Depends: ${python:Depends}, ${misc:Depends},
moulinette (>= 2.3.4),
python-psutil,
python-requests,
glances,
python-pip,
python-miniupnpc | pyminiupnpc,
dnsutils,
bind9utils,
python-apt,
ca-certificates,
python-dnspython,
netcat-openbsd,
iproute,
unzip,
git-core,
curl,
mariadb-server | mysql-server, php5-mysql | php5-mysqlnd,
slapd, ldap-utils, sudo-ldap, libnss-ldapd,
postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail,
dovecot-ldap, dovecot-lmtpd, dovecot-managesieved,
dovecot-antispam, fail2ban,
nginx-extras (>=1.6.2), php5-fpm, php5-ldap, php5-intl,
dnsmasq, openssl, avahi-daemon,
ssowat, metronome,
rspamd, rmilter (>=1.7.0), redis-server, opendkim-tools
Recommends: yunohost-admin,
bash-completion, rsyslog, ntp, openssh-server,
inetutils-ping | iputils-ping,
php5-gd, php5-curl, php-gettext, php5-mcrypt,
unattended-upgrades,
libdbd-ldap-perl, libnet-dns-perl
Depends: ${python:Depends}, ${misc:Depends}
, moulinette (>= 2.3.4)
, python-psutil, python-requests, python-dnspython
, python-apt, python-miniupnpc
, glances
, dnsutils, bind9utils, unzip, git, curl, cron
, ca-certificates, netcat-openbsd, iproute
, mariadb-server | mysql-server, php5-mysql | php5-mysqlnd
, slapd, ldap-utils, sudo-ldap, libnss-ldapd
, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail
, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved
, dovecot-antispam, fail2ban
, nginx-extras (>=1.6.2), php5-fpm, php5-ldap, php5-intl
, dnsmasq, openssl, avahi-daemon
, ssowat, metronome
, rspamd (>= 1.2.0), rmilter (>=1.7.0), redis-server, opendkim-tools
Recommends: yunohost-admin
, openssh-server, ntp, inetutils-ping | iputils-ping
, bash-completion, rsyslog
, php5-gd, php5-curl, php-gettext, php5-mcrypt
, python-pip
, unattended-upgrades
, libdbd-ldap-perl, libnet-dns-perl
Suggests: htop, vim, rsync, acpi-support-base, udisks2
Conflicts: iptables-persistent,
moulinette-yunohost, yunohost-config,
yunohost-config-others, yunohost-config-postfix,
yunohost-config-dovecot, yunohost-config-slapd,
yunohost-config-nginx, yunohost-config-amavis,
yunohost-config-mysql, yunohost-predepends
Replaces: moulinette-yunohost, yunohost-config,
yunohost-config-others, yunohost-config-postfix,
yunohost-config-dovecot, yunohost-config-slapd,
yunohost-config-nginx, yunohost-config-amavis,
yunohost-config-mysql, yunohost-predepends
Conflicts: iptables-persistent
, moulinette-yunohost, yunohost-config
, yunohost-config-others, yunohost-config-postfix
, yunohost-config-dovecot, yunohost-config-slapd
, yunohost-config-nginx, yunohost-config-amavis
, yunohost-config-mysql, yunohost-predepends
Replaces: moulinette-yunohost, yunohost-config
, yunohost-config-others, yunohost-config-postfix
, yunohost-config-dovecot, yunohost-config-slapd
, yunohost-config-nginx, yunohost-config-amavis
, yunohost-config-mysql, yunohost-predepends
Description: manageable and configured self-hosting server
YunoHost aims to make self-hosting accessible to everyone. It configures
an email, Web and IM server alongside a LDAP base. It also provides

3
debian/rules vendored
View file

@ -8,7 +8,8 @@
dh ${@} --with=python2,systemd
override_dh_installinit:
dh_installinit --noscripts
dh_installinit -pyunohost --name=yunohost-api --noscripts
dh_installinit -pyunohost --name=yunohost-firewall --noscripts
override_dh_systemd_enable:
dh_systemd_enable --name=yunohost-api

View file

@ -5,7 +5,7 @@
"installation_complete" : "Installation complete",
"installation_failed" : "Installation failed",
"unexpected_error" : "An unexpected error occured",
"action_invalid" : "Invalid action '{:s}'",
"action_invalid" : "Invalid action '{action:s}'",
"not_enough_disk_space" : "Not enough free disk space on '{path:s}'",
"license_undefined" : "undefined",
@ -27,6 +27,7 @@
"app_upgrade_failed" : "Unable to upgrade {app:s}",
"app_id_invalid" : "Invalid app id",
"app_already_installed" : "{app:s} is already installed",
"app_not_properly_removed" : "{app:s} has not been properly removed",
"app_removed" : "{app:s} successfully removed",
"app_location_already_used" : "An app is already installed on this location",
"app_location_install_failed" : "Unable to install the app on this location",
@ -68,8 +69,10 @@
"no_ipv6_connectivity": "IPv6 connectivity is not available",
"dyndns_key_generating" : "DNS key is being generated, it may take a while...",
"dyndns_key_not_found" : "DNS key not found for the domain",
"dyndns_no_domain_registered": "No domain has been registered with DynDNS",
"dyndns_unavailable" : "Unavailable DynDNS subdomain",
"dyndns_registration_failed" : "Unable to register DynDNS domain: {:s}",
"dyndns_registration_failed" : "Unable to register DynDNS domain: {error:s}",
"dyndns_registered" : "DynDNS domain successfully registered",
"dyndns_ip_update_failed" : "Unable to update IP address on DynDNS",
"dyndns_ip_updated" : "IP address successfully updated on DynDNS",
@ -79,8 +82,8 @@
"port_available" : "Port {port:d} is available",
"port_unavailable" : "Port {port:d} is not available",
"port_already_opened" : "Port {} is already opened for {:s} connections",
"port_already_closed" : "Port {} is already closed for {:s} connections",
"port_already_opened" : "Port {port:d} is already opened for {ip_version:s} connections",
"port_already_closed" : "Port {port:d} is already closed for {ip_version:s} connections",
"iptables_unavailable" : "You cannot play with iptables here. You are either in a container or your kernel does not support it.",
"ip6tables_unavailable" : "You cannot play with ip6tables here. You are either in a container or your kernel does not support it.",
"upnp_dev_not_found" : "No UPnP device found",
@ -92,12 +95,12 @@
"firewall_reloaded" : "Firewall successfully reloaded",
"hook_list_by_invalid" : "Invalid property to list hook by",
"hook_name_unknown" : "Unknown hook name '{:s}'",
"hook_exec_failed" : "Script execution failed",
"hook_exec_not_terminated" : "Script execution hasnt terminated",
"hook_name_unknown" : "Unknown hook name '{name:s}'",
"hook_exec_failed" : "Script execution failed: {path:s}",
"hook_exec_not_terminated" : "Script execution hasnt terminated: {path:s}",
"mountpoint_unknown" : "Unknown mountpoint",
"unit_unknown" : "Unknown unit '{:s}'",
"unit_unknown" : "Unknown unit '{unit:s}'",
"monitor_period_invalid" : "Invalid time period",
"monitor_stats_no_update" : "No monitoring statistics to update",
"monitor_stats_file_not_found" : "Statistics file not found",
@ -107,25 +110,26 @@
"monitor_not_enabled" : "Server monitoring is not enabled",
"monitor_glances_con_failed" : "Unable to connect to Glances server",
"service_unknown" : "Unknown service '{:s}'",
"service_add_failed" : "Unable to add service '{:s}'",
"service_added" : "Service successfully added",
"service_remove_failed" : "Unable to remove service '{:s}'",
"service_removed" : "Service successfully removed",
"service_start_failed" : "Unable to start service '{:s}'",
"service_already_started" : "Service '{:s}' is already started",
"service_started" : "Service '{:s}' successfully started",
"service_stop_failed" : "Unable to stop service '{:s}'",
"service_already_stopped" : "Service '{:s}' is already stopped",
"service_stopped" : "Service '{:s}' successfully stopped",
"service_enable_failed" : "Unable to enable service '{:s}'",
"service_enabled" : "Service '{:s}' successfully enabled",
"service_disable_failed" : "Unable to disable service '{:s}'",
"service_disabled" : "Service '{:s}' successfully disabled",
"service_status_failed" : "Unable to determine status of service '{:s}'",
"service_no_log" : "No log to display for service '{:s}'",
"service_cmd_exec_failed" : "Unable to execute command '{:s}'",
"services_configured": "Configuration successfully generated",
"service_unknown" : "Unknown service '{service:s}'",
"service_add_failed" : "Unable to add service '{service:s}'",
"service_added" : "Service successfully added: '{service:s}'",
"service_remove_failed" : "Unable to remove service '{service:s}'",
"service_removed" : "Service successfully removed: '{service:s}'",
"service_start_failed" : "Unable to start service '{service:s}'",
"service_already_started" : "Service '{service:s}' is already started",
"service_started" : "Service '{service:s}' successfully started",
"service_stop_failed" : "Unable to stop service '{service:s}'",
"service_already_stopped" : "Service '{service:s}' is already stopped",
"service_stopped" : "Service '{service:s}' successfully stopped",
"service_enable_failed" : "Unable to enable service '{service:s}'",
"service_enabled" : "Service '{service:s}' successfully enabled",
"service_disable_failed" : "Unable to disable service '{service:s}'",
"service_disabled" : "Service '{service:s}' successfully disabled",
"service_status_failed" : "Unable to determine status of service '{service:s}'",
"service_no_log" : "No log to display for service '{service:s}'",
"service_cmd_exec_failed" : "Unable to execute command '{command:s}'",
"service_configured": "Configuration successfully generated for service '{service:s}'",
"service_configured_all": "Configuration successfully generated for every services",
"service_configuration_conflict": "The file {file:s} has been changed since its last generation. Please apply the modifications manually or use the option --force (it will erase all the modifications previously done to the file).",
"no_such_conf_file": "Unable to copy the file {file:s}: the file does not exist",
"service_add_configuration": "Adding the configuration file {file:s}",
@ -148,14 +152,14 @@
"updating_apt_cache" : "Updating the lists of available packages...",
"update_cache_failed" : "Unable to update APT cache",
"packages_no_upgrade" : "There is no package to upgrade",
"packages_upgrade_critical_later" : "Critical packages ({:s}) will be upgraded later",
"packages_upgrade_critical_later" : "Critical packages ({packages:s}) will be upgraded later",
"upgrading_packages" : "Upgrading packages...",
"packages_upgrade_failed" : "Unable to upgrade all packages",
"system_upgraded" : "System successfully upgraded",
"backup_action_required" : "You must specify something to save",
"backup_output_directory_required" : "You must provide an output directory for the backup",
"backup_output_directory_forbidden" : "Forbidden output directory",
"backup_output_directory_forbidden" : "Forbidden output directory. Backups can't be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders.",
"backup_output_directory_not_empty" : "Output directory is not empty",
"backup_hook_unknown" : "Backup hook '{hook:s}' unknown",
"backup_running_hooks" : "Running backup hooks...",
@ -190,10 +194,10 @@
"backup_deleted" : "Backup successfully deleted",
"field_invalid" : "Invalid field '{:s}'",
"mail_domain_unknown" : "Unknown mail address domain '{:s}'",
"mail_alias_remove_failed" : "Unable to remove mail alias '{:s}'",
"mail_forward_remove_failed" : "Unable to remove mail forward '{:s}'",
"user_unknown" : "Unknown user",
"mail_domain_unknown" : "Unknown mail address domain '{domain:s}'",
"mail_alias_remove_failed" : "Unable to remove mail alias '{mail:s}'",
"mail_forward_remove_failed" : "Unable to remove mail forward '{mail:s}'",
"user_unknown" : "Unknown user: {user:s}",
"system_username_exists" : "Username already exists in the system users",
"user_creation_failed" : "Unable to create user",
"user_created" : "User successfully created",

View file

@ -85,7 +85,7 @@ def app_fetchlist(url=None, name=None):
Keyword argument:
name -- Name of the list (default yunohost)
url -- URL of remote JSON list (default https://yunohost.org/official.json)
url -- URL of remote JSON list (default https://app.yunohost.org/official.json)
"""
# Create app path if not exists
@ -93,7 +93,7 @@ def app_fetchlist(url=None, name=None):
except OSError: os.makedirs(repo_path)
if url is None:
url = 'https://yunohost.org/official.json'
url = 'https://app.yunohost.org/official.json'
name = 'yunohost'
else:
if name is None:
@ -131,7 +131,7 @@ def app_removelist(name):
logger.success(m18n.n('appslist_removed'))
def app_list(offset=None, limit=None, filter=None, raw=False):
def app_list(offset=None, limit=None, filter=None, raw=False, installed=False, with_backup=False):
"""
List apps
@ -140,12 +140,15 @@ def app_list(offset=None, limit=None, filter=None, raw=False):
offset -- Starting number for app fetching
limit -- Maximum number of app fetched
raw -- Return the full app_dict
installed -- Return only installed apps
with_backup -- Return only apps with backup feature (force --installed filter)
"""
if offset: offset = int(offset)
else: offset = 0
if limit: limit = int(limit)
else: limit = 1000
installed = with_backup or installed
app_dict = {}
if raw:
@ -188,16 +191,27 @@ def app_list(offset=None, limit=None, filter=None, raw=False):
for app_id, app_info_dict in sorted_app_dict.items():
if i < limit:
if (filter and ((filter in app_id) or (filter in app_info_dict['manifest']['name']))) or not filter:
installed = _is_installed(app_id)
app_installed = _is_installed(app_id)
# Only installed apps filter
if installed and not app_installed:
continue
# Filter only apps with backup and restore scripts
if with_backup and (
not os.path.isfile(apps_setting_path + app_id + '/scripts/backup') or
not os.path.isfile(apps_setting_path + app_id + '/scripts/restore')
):
continue
if raw:
app_info_dict['installed'] = installed
if installed:
app_info_dict['installed'] = app_installed
if app_installed:
app_info_dict['status'] = _get_app_status(app_id)
list_dict[app_id] = app_info_dict
else:
label = None
if installed:
if app_installed:
app_info_dict_raw = app_info(app=app_id, raw=True)
label = app_info_dict_raw['settings']['label']
list_dict.append({
@ -209,7 +223,7 @@ def app_list(offset=None, limit=None, filter=None, raw=False):
# FIXME: Temporarly allow undefined license
'license': app_info_dict['manifest'].get('license',
m18n.n('license_undefined')),
'installed': installed
'installed': app_installed
})
i += 1
else:
@ -515,37 +529,53 @@ def app_install(auth, app, label=None, args=None):
# Move scripts and manifest to the right place
os.system('cp %s/manifest.json %s' % (app_tmp_folder, app_setting_path))
os.system('cp -R %s/scripts %s' % (app_tmp_folder, app_setting_path))
# Execute the app install script
install_retcode = 1
try:
if hook_exec(app_tmp_folder + '/scripts/install', args=args_list, env=env_dict) == 0:
# Store app status
with open(app_setting_path + '/status.json', 'w+') as f:
json.dump(status, f)
# Clean and set permissions
shutil.rmtree(app_tmp_folder)
os.system('chmod -R 400 %s' % app_setting_path)
os.system('chown -R root: %s' % app_setting_path)
os.system('chown -R admin: %s/scripts' % app_setting_path)
app_ssowatconf(auth)
logger.success(m18n.n('installation_complete'))
else:
raise MoulinetteError(errno.EIO, m18n.n('installation_failed'))
install_retcode = hook_exec(
os.path.join(app_tmp_folder, 'scripts/install'), args_list, env=env_dict)
except (KeyboardInterrupt, EOFError):
install_retcode = -1
except:
# Execute remove script and clean folders
hook_remove(app_instance_name)
shutil.rmtree(app_setting_path)
shutil.rmtree(app_tmp_folder)
logger.exception(m18n.n('unexpected_error'))
finally:
if install_retcode != 0:
# Setup environment for remove script
env_dict_remove = {}
env_dict_remove["YNH_APP_ID"] = app_id
env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
# Reraise proper exception
try:
raise
except MoulinetteError:
raise
except (KeyboardInterrupt, EOFError):
raise MoulinetteError(errno.EINTR, m18n.g('operation_interrupted'))
except Exception as e:
logger.debug('app installation failed', exc_info=1)
raise MoulinetteError(errno.EIO, m18n.n('unexpected_error'))
# Execute remove script
remove_retcode = hook_exec(
os.path.join(app_tmp_folder, 'scripts/remove'), args=[app_instance_name], env=env_dict_remove)
if remove_retcode != 0:
logger.warning(m18n.n('app_not_properly_removed', app=app_instance_name))
# Clean tmp folders
hook_remove(app_instance_name)
shutil.rmtree(app_setting_path)
shutil.rmtree(app_tmp_folder)
if install_retcode == -1:
raise MoulinetteError(errno.EINTR,
m18n.g('operation_interrupted'))
raise MoulinetteError(errno.EIO, m18n.n('installation_failed'))
# Store app status
with open(app_setting_path + '/status.json', 'w+') as f:
json.dump(status, f)
# Clean and set permissions
shutil.rmtree(app_tmp_folder)
os.system('chmod -R 400 %s' % app_setting_path)
os.system('chown -R root: %s' % app_setting_path)
os.system('chown -R admin: %s/scripts' % app_setting_path)
app_ssowatconf(auth)
logger.success(m18n.n('installation_complete'))
def app_remove(auth, app):
@ -624,10 +654,7 @@ def app_addaccess(auth, apps, users=[]):
try:
user_info(auth, allowed_user)
except MoulinetteError:
# FIXME: Add username keyword in user_unknown
logger.warning('{0}{1}'.format(
m18n.g('colon', m18n.n('user_unknown')),
allowed_user))
logger.warning(m18n.n('user_unknown', user=allowed_user))
continue
allowed_users.add(allowed_user)

View file

@ -39,6 +39,13 @@ from moulinette.core import MoulinetteError
from moulinette.utils import filesystem
from moulinette.utils.log import getActionLogger
from yunohost.app import app_info, app_ssowatconf, _is_installed, _parse_app_instance_name
from yunohost.hook import (
hook_info, hook_callback, hook_exec, custom_hook_folder
)
from yunohost.monitor import binary_to_human
from yunohost.tools import tools_postinstall
backup_path = '/home/yunohost.backup'
archives_path = '%s/archives' % backup_path
@ -63,8 +70,6 @@ def backup_create(name=None, description=None, output_directory=None,
"""
# TODO: Add a 'clean' argument to clean output directory
from yunohost.hook import hook_info, hook_callback, hook_exec
tmp_dir = None
# Validate what to backup
@ -167,9 +172,6 @@ def backup_create(name=None, description=None, output_directory=None,
# Backup apps
if not ignore_apps:
from yunohost.app import app_info
from yunohost.app import _parse_app_instance_name
# Filter applications to backup
apps_list = set(os.listdir('/etc/yunohost/apps'))
apps_filtered = set()
@ -215,7 +217,8 @@ def backup_create(name=None, description=None, output_directory=None,
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
hook_exec(tmp_script, args=[tmp_app_bkp_dir, app_instance_name],
raise_on_error=True, env=env_dict)
raise_on_error=True, chdir=tmp_app_bkp_dir, env=env_dict)
except:
logger.exception(m18n.n('backup_app_failed', app=app_instance_name))
# Cleaning app backup directory
@ -288,21 +291,20 @@ def backup_create(name=None, description=None, output_directory=None,
return { 'archive': info }
def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=False, force=False):
def backup_restore(auth, name, hooks=[], ignore_hooks=False,
apps=[], ignore_apps=False, force=False):
"""
Restore from a local backup archive
Keyword argument:
name -- Name of the local backup archive
hooks -- List of restoration hooks names to execute
ignore_hooks -- Do not execute backup hooks
apps -- List of application names to restore
ignore_apps -- Do not restore apps
force -- Force restauration on an already installed system
"""
from yunohost.hook import hook_info, hook_callback, hook_exec
from yunohost.hook import custom_hook_folder
# Validate what to restore
if ignore_hooks and ignore_apps:
raise MoulinetteError(errno.EINVAL,
@ -380,8 +382,6 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals
_clean_tmp_dir()
raise MoulinetteError(errno.EEXIST, m18n.n('restore_failed'))
else:
from yunohost.tools import tools_postinstall
# Retrieve the domain from the backup
try:
with open("%s/yunohost/current_host" % tmp_dir, 'r') as f:
@ -437,9 +437,6 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals
# Add apps restore hook
if not ignore_apps:
from yunohost.app import _is_installed
from yunohost.app import _parse_app_instance_name
# Filter applications to restore
apps_list = set(info['apps'].keys())
apps_filtered = set()
@ -454,6 +451,7 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals
for app_instance_name in apps_filtered:
tmp_app_dir = '{:s}/apps/{:s}'.format(tmp_dir, app_instance_name)
tmp_app_bkp_dir = tmp_app_dir + '/backup'
# Check if the app is not already installed
if _is_installed(app_instance_name):
@ -487,7 +485,7 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
hook_exec(tmp_script, args=[tmp_app_dir + '/backup', app_instance_name],
raise_on_error=True, env=env_dict)
raise_on_error=True, chdir=tmp_app_bkp_dir, env=env_dict)
except:
logger.exception(m18n.n('restore_app_failed', app=app_instance_name))
# Cleaning app directory
@ -501,6 +499,8 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals
if not result['hooks'] and not result['apps']:
_clean_tmp_dir(1)
raise MoulinetteError(errno.EINVAL, m18n.n('restore_nothings_done'))
if result['apps']:
app_ssowatconf(auth)
_clean_tmp_dir()
logger.success(m18n.n('restore_complete'))
@ -553,8 +553,6 @@ def backup_info(name, with_details=False, human_readable=False):
human_readable -- Print sizes in human readable format
"""
from yunohost.monitor import binary_to_human
archive_file = '%s/%s.tar.gz' % (archives_path, name)
if not os.path.isfile(archive_file):
raise MoulinetteError(errno.EIO,
@ -602,7 +600,6 @@ def backup_delete(name):
name -- Name of the local backup archive
"""
from yunohost.hook import hook_callback
hook_callback('pre_backup_delete', args=[name])
archive_file = '%s/%s.tar.gz' % (archives_path, name)

View file

@ -24,12 +24,12 @@
Subscribe and Update DynDNS Hosts
"""
import os
import requests
import re
import json
import glob
import base64
import errno
import requests
import subprocess
from moulinette.core import MoulinetteError
@ -62,6 +62,10 @@ class IPRouteLine(object):
for k, v in self.m.groupdict().items():
setattr(self, k, v)
re_dyndns_private_key = re.compile(
r'.*/K(?P<domain>[^\s\+]+)\.\+157.+\.private$'
)
def dyndns_subscribe(subscribe_host="dyndns.yunohost.org", domain=None, key=None):
"""
@ -107,30 +111,26 @@ def dyndns_subscribe(subscribe_host="dyndns.yunohost.org", domain=None, key=None
try: error = json.loads(r.text)['error']
except: error = "Server error"
raise MoulinetteError(errno.EPERM,
m18n.n('dyndns_registration_failed', error))
m18n.n('dyndns_registration_failed', error=error))
logger.success(m18n.n('dyndns_registered'))
dyndns_installcron()
def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None,
def dyndns_update(dyn_host="dyndns.yunohost.org", domain=None, key=None,
ipv4=None, ipv6=None):
"""
Update IP on DynDNS platform
Keyword argument:
domain -- Full domain to subscribe with
domain -- Full domain to update
dyn_host -- Dynette DNS server to inform
key -- Public DNS key
ipv4 -- IP address to send
ipv6 -- IPv6 address to send
"""
if domain is None:
with open('/etc/yunohost/current_host', 'r') as f:
domain = f.readline().rstrip()
# IPv4
if ipv4 is None:
ipv4 = get_public_ip()
@ -168,6 +168,37 @@ def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None,
old_ipv6 = '0000:0000:0000:0000:0000:0000:0000:0000'
if old_ip != ipv4 or old_ipv6 != ipv6:
if domain is None:
# Retrieve the first registered domain
for path in glob.iglob('/etc/yunohost/dyndns/K*.private'):
match = re_dyndns_private_key.match(path)
if not match:
continue
_domain = match.group('domain')
try:
# Check if domain is registered
if requests.get('https://{0}/test/{1}'.format(
dyn_host, _domain)).status_code == 200:
continue
except requests.ConnectionError:
raise MoulinetteError(errno.ENETUNREACH,
m18n.n('no_internet_connection'))
domain = _domain
key = path
break
if not domain:
raise MoulinetteError(errno.EINVAL,
m18n.n('dyndns_no_domain_registered'))
if key is None:
keys = glob.glob(
'/etc/yunohost/dyndns/K{0}.+*.private'.format(domain))
if len(keys) > 0:
key = keys[0]
if not key:
raise MoulinetteError(errno.EIO,
m18n.n('dyndns_key_not_found'))
host = domain.split('.')[1:]
host = '.'.join(host)
lines = [
@ -209,11 +240,7 @@ def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None,
for line in lines:
zone.write(line + '\n')
if key is None:
private_key_file = glob.glob('/etc/yunohost/dyndns/*.private')[0]
else:
private_key_file = key
if os.system('/usr/bin/nsupdate -k %s /etc/yunohost/dyndns/zone' % private_key_file) == 0:
if os.system('/usr/bin/nsupdate -k %s /etc/yunohost/dyndns/zone' % key) == 0:
logger.success(m18n.n('dyndns_ip_updated'))
with open('/etc/yunohost/dyndns/old_ip', 'w') as f:
f.write(ipv4)

View file

@ -83,7 +83,7 @@ def firewall_allow(protocol, port, ipv4_only=False, ipv6_only=False,
firewall[i][p].append(port)
else:
ipv = "IPv%s" % i[3]
logger.warning(m18n.n('port_already_opened', port, ipv))
logger.warning(m18n.n('port_already_opened', port=port, ip_version=ipv))
# Add port forwarding with UPnP
if not no_upnp and port not in firewall['uPnP'][p]:
firewall['uPnP'][p].append(port)
@ -140,7 +140,7 @@ def firewall_disallow(protocol, port, ipv4_only=False, ipv6_only=False,
firewall[i][p].remove(port)
else:
ipv = "IPv%s" % i[3]
logger.warning(m18n.n('port_already_closed', port, ipv))
logger.warning(m18n.n('port_already_closed', port=port, ip_version=ipv))
# Remove port forwarding with UPnP
if upnp and port in firewall['uPnP'][p]:
firewall['uPnP'][p].remove(port)
@ -335,7 +335,7 @@ def firewall_upnp(action='status', no_refresh=False):
if action == 'status':
no_refresh = True
else:
raise MoulinetteError(errno.EINVAL, m18n.n('action_invalid', action))
raise MoulinetteError(errno.EINVAL, m18n.n('action_invalid', action=action))
# Refresh port mapping using UPnP
if not no_refresh:

View file

@ -110,7 +110,7 @@ def hook_info(action, name):
})
if not hooks:
raise MoulinetteError(errno.EINVAL, m18n.n('hook_name_unknown', name))
raise MoulinetteError(errno.EINVAL, m18n.n('hook_name_unknown', name=name))
return {
'action': action,
'name': name,
@ -275,7 +275,8 @@ def hook_callback(action, hooks=[], args=None):
return result
def hook_exec(path, args=None, raise_on_error=False, no_trace=False, env=None):
def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
chdir=None, env=None):
"""
Execute hook from a file with arguments
@ -284,6 +285,7 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False, env=None):
args -- A list of arguments to pass to the script
raise_on_error -- Raise if the script returns a non-zero exit code
no_trace -- Do not print each command that will be executed
chdir -- The directory from where the script will be executed
env -- Dictionnary of environment variables to export
"""
@ -297,50 +299,54 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False, env=None):
raise MoulinetteError(errno.EIO, m18n.g('file_not_exist'))
# Construct command variables
cmd_fdir, cmd_fname = os.path.split(path)
cmd_fname = './{0}'.format(cmd_fname)
cmd_args = ''
if args and isinstance(args, list):
# Concatenate arguments and escape them with double quotes to prevent
# bash related issue if an argument is empty and is not the last
cmd_args = '"{:s}"'.format('" "'.join(str(s) for s in args))
if not chdir:
# use the script directory as current one
chdir, cmd_script = os.path.split(path)
cmd_script = './{0}'.format(cmd_script)
else:
cmd_script = path
envcli = ''
if env is not None:
envcli = ' '.join([ '{key}="{val}"'.format(key=key, val=val) for key,val in env.items()])
# Construct command to execute
command = ['sudo', '-u', 'admin', '-H', 'sh', '-c']
command = ['sudo', '-n', '-u', 'admin', '-H', 'sh', '-c']
if no_trace:
cmd = 'cd "{0:s}" && {1:s} /bin/bash "{2:s}" {3:s}'
cmd = '{envcli} /bin/bash "{script}" {args}'
else:
# use xtrace on fd 7 which is redirected to stdout
cmd = 'cd "{0:s}" && {1:s} BASH_XTRACEFD=7 /bin/bash -x "{2:s}" {3:s} 7>&1'
command.append(cmd.format(cmd_fdir, envcli, cmd_fname, cmd_args))
cmd = '{envcli} BASH_XTRACEFD=7 /bin/bash -x "{script}" {args} 7>&1'
command.append(cmd.format(envcli=envcli, script=cmd_script, args=cmd_args))
if logger.isEnabledFor(log.DEBUG):
logger.info(m18n.n('executing_command', command=' '.join(command)))
else:
logger.info(m18n.n('executing_script', script='{0}/{1}'.format(
cmd_fdir, cmd_fname)))
logger.info(m18n.n('executing_script', script=path))
# Define output callbacks and call command
callbacks = (
lambda l: logger.info(l.rstrip()),
lambda l: logger.warning(l.rstrip()),
)
returncode = call_async_output(command, callbacks, shell=False)
returncode = call_async_output(
command, callbacks, shell=False, cwd=chdir
)
# Check and return process' return code
if returncode is None:
if raise_on_error:
raise MoulinetteError(m18n.n('hook_exec_not_terminated'))
raise MoulinetteError(m18n.n('hook_exec_not_terminated', path=path))
else:
logger.error(m18n.n('hook_exec_not_terminated'))
logger.error(m18n.n('hook_exec_not_terminated', path=path))
return 1
elif raise_on_error and returncode != 0:
raise MoulinetteError(m18n.n('hook_exec_failed'))
raise MoulinetteError(m18n.n('hook_exec_failed', path=path))
return returncode

View file

@ -139,7 +139,7 @@ def monitor_disk(units=None, mountpoint=None, human_readable=False):
for dname in devices_names:
_set(dname, 'not-available')
else:
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', u))
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', unit=u))
if result_dname is not None:
return result[result_dname]
@ -237,7 +237,7 @@ def monitor_network(units=None, human_readable=False):
'gateway': gateway,
}
else:
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', u))
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', unit=u))
if len(units) == 1:
return result[units[0]]
@ -287,7 +287,7 @@ def monitor_system(units=None, human_readable=False):
elif u == 'infos':
result[u] = json.loads(glances.getSystem())
else:
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', u))
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', unit=u))
if len(units) == 1 and type(result[units[0]]) is not str:
return result[units[0]]

View file

@ -75,9 +75,9 @@ def service_add(name, status=None, log=None, runlevel=None):
try:
_save_services(services)
except:
raise MoulinetteError(errno.EIO, m18n.n('service_add_failed', name))
raise MoulinetteError(errno.EIO, m18n.n('service_add_failed', service=name))
logger.success(m18n.n('service_added'))
logger.success(m18n.n('service_added', service=name))
def service_remove(name):
@ -93,14 +93,14 @@ def service_remove(name):
try:
del services[name]
except KeyError:
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', name))
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service=name))
try:
_save_services(services)
except:
raise MoulinetteError(errno.EIO, m18n.n('service_remove_failed', name))
raise MoulinetteError(errno.EIO, m18n.n('service_remove_failed', service=name))
logger.success(m18n.n('service_removed'))
logger.success(m18n.n('service_removed', service=name))
def service_start(names):
@ -115,12 +115,12 @@ def service_start(names):
names = [names]
for name in names:
if _run_service_command('start', name):
logger.success(m18n.n('service_started', name))
logger.success(m18n.n('service_started', service=name))
else:
if service_status(name)['status'] != 'running':
raise MoulinetteError(errno.EPERM,
m18n.n('service_start_failed', name))
logger.info(m18n.n('service_already_started', name))
m18n.n('service_start_failed', service=name))
logger.info(m18n.n('service_already_started', service=name))
def service_stop(names):
@ -135,12 +135,12 @@ def service_stop(names):
names = [names]
for name in names:
if _run_service_command('stop', name):
logger.success(m18n.n('service_stopped', name))
logger.success(m18n.n('service_stopped', service=name))
else:
if service_status(name)['status'] != 'inactive':
raise MoulinetteError(errno.EPERM,
m18n.n('service_stop_failed', name))
logger.info(m18n.n('service_already_stopped', name))
m18n.n('service_stop_failed', service=name))
logger.info(m18n.n('service_already_stopped', service=name))
def service_enable(names):
@ -155,10 +155,10 @@ def service_enable(names):
names = [names]
for name in names:
if _run_service_command('enable', name):
logger.success(m18n.n('service_enabled', name))
logger.success(m18n.n('service_enabled', service=name))
else:
raise MoulinetteError(errno.EPERM,
m18n.n('service_enable_failed', name))
m18n.n('service_enable_failed', service=name))
def service_disable(names):
@ -173,10 +173,10 @@ def service_disable(names):
names = [names]
for name in names:
if _run_service_command('disable', name):
logger.success(m18n.n('service_disabled', name))
logger.success(m18n.n('service_disabled', service=name))
else:
raise MoulinetteError(errno.EPERM,
m18n.n('service_disable_failed', name))
m18n.n('service_disable_failed', service=name))
def service_status(names=[]):
@ -200,7 +200,7 @@ def service_status(names=[]):
for name in names:
if check_names and name not in services.keys():
raise MoulinetteError(errno.EINVAL,
m18n.n('service_unknown', name))
m18n.n('service_unknown', service=name))
status = None
if 'status' not in services[name] or \
@ -221,7 +221,7 @@ def service_status(names=[]):
shell=True)
except subprocess.CalledProcessError as e:
if 'usage:' in e.output.lower():
logger.warning(m18n.n('service_status_failed', name))
logger.warning(m18n.n('service_status_failed', service=name))
else:
result[name]['status'] = 'inactive'
else:
@ -253,7 +253,7 @@ def service_log(name, number=50):
services = _get_services()
if name not in services.keys():
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', name))
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service=name))
if 'log' in services[name]:
log_list = services[name]['log']
@ -268,7 +268,7 @@ def service_log(name, number=50):
else:
result[log_path] = _tail(log_path, int(number))
else:
raise MoulinetteError(errno.EPERM, m18n.n('service_no_log', name))
raise MoulinetteError(errno.EPERM, m18n.n('service_no_log', service=name))
return result
@ -289,9 +289,10 @@ def service_regenconf(service=None, force=False):
if service is not None:
hook_callback('conf_regen', [service], args=[force])
logger.success(m18n.n('service_configured', service=service))
else:
hook_callback('conf_regen', args=[force])
logger.success(m18n.n('services_configured'))
logger.success(m18n.n('service_configured_all'))
def _run_service_command(action, service):
@ -304,8 +305,7 @@ def _run_service_command(action, service):
"""
if service not in _get_services().keys():
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown',
service))
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service=service))
cmd = None
if action in ['start', 'stop', 'restart', 'reload']:
@ -320,7 +320,7 @@ def _run_service_command(action, service):
ret = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
# TODO: Log output?
logger.warning(m18n.n('service_cmd_exec_failed', ' '.join(e.cmd)))
logger.warning(m18n.n('service_cmd_exec_failed', command=' '.join(e.cmd)))
return False
return True

View file

@ -380,7 +380,7 @@ def tools_upgrade(auth, ignore_apps=False, ignore_packages=False):
# ... and set a hourly cron up to upgrade critical packages
if critical_upgrades:
logger.info(m18n.n('packages_upgrade_critical_later',
', '.join(critical_upgrades)))
packages=', '.join(critical_upgrades)))
with open('/etc/cron.d/yunohost-upgrade', 'w+') as f:
f.write('00 * * * * root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin apt-get install %s -y && rm -f /etc/cron.d/yunohost-upgrade\n' % ' '.join(critical_upgrades))

View file

@ -128,7 +128,7 @@ def user_create(auth, username, firstname, lastname, mail, password,
if mail[mail.find('@')+1:] not in domain_list(auth)['domains']:
raise MoulinetteError(errno.EINVAL,
m18n.n('mail_domain_unknown',
mail[mail.find('@')+1:]))
domain=mail[mail.find('@')+1:]))
# Get random UID/GID
uid_check = gid_check = 0
@ -275,7 +275,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
# Populate user informations
result = auth.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch)
if not result:
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown'))
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown', user=username))
user = result[0]
# Get modifications from arguments
@ -301,7 +301,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
if mail[mail.find('@')+1:] not in domains:
raise MoulinetteError(errno.EINVAL,
m18n.n('mail_domain_unknown',
mail[mail.find('@')+1:]))
domain=mail[mail.find('@')+1:]))
del user['mail'][0]
new_attr_dict['mail'] = [mail] + user['mail']
@ -313,7 +313,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
if mail[mail.find('@')+1:] not in domains:
raise MoulinetteError(errno.EINVAL,
m18n.n('mail_domain_unknown',
mail[mail.find('@')+1:]))
domain=mail[mail.find('@')+1:]))
user['mail'].append(mail)
new_attr_dict['mail'] = user['mail']
@ -325,7 +325,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
user['mail'].remove(mail)
else:
raise MoulinetteError(errno.EINVAL,
m18n.n('mail_alias_remove_failed', mail))
m18n.n('mail_alias_remove_failed', mail=mail))
new_attr_dict['mail'] = user['mail']
if add_mailforward:
@ -345,7 +345,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
user['maildrop'].remove(mail)
else:
raise MoulinetteError(errno.EINVAL,
m18n.n('mail_forward_remove_failed', mail))
m18n.n('mail_forward_remove_failed', mail=mail))
new_attr_dict['maildrop'] = user['maildrop']
if mailbox_quota is not None:
@ -381,7 +381,7 @@ def user_info(auth, username):
if result:
user = result[0]
else:
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown'))
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown', user=username))
result_dict = {
'username': user['uid'][0],