mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Manual merge with unstable
This commit is contained in:
commit
3ef177ea3b
22 changed files with 387 additions and 1430 deletions
28
bin/yunohost
28
bin/yunohost
|
@ -1,8 +1,13 @@
|
||||||
#!/usr/bin/env python
|
#! /usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
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
|
# Either we are in a development environment or not
|
||||||
IN_DEVEL = False
|
IN_DEVEL = False
|
||||||
|
@ -34,17 +39,11 @@ if IN_DEVEL:
|
||||||
|
|
||||||
def _die(message, title='Error:'):
|
def _die(message, title='Error:'):
|
||||||
"""Print error message and exit"""
|
"""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))
|
print('%s %s' % (colorize(title, 'red'), message))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def _parse_cli_args():
|
def _parse_cli_args():
|
||||||
"""Parse additional arguments for the cli"""
|
"""Parse additional arguments for the cli"""
|
||||||
import argparse
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(add_help=False)
|
parser = argparse.ArgumentParser(add_help=False)
|
||||||
parser.add_argument('--no-cache',
|
parser.add_argument('--no-cache',
|
||||||
action='store_false', default=True, dest='use_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):
|
def _init_moulinette(debug=False, verbose=False, quiet=False):
|
||||||
"""Configure logging and initialize the moulinette"""
|
"""Configure logging and initialize the moulinette"""
|
||||||
from moulinette import init
|
|
||||||
|
|
||||||
# Define loggers handlers
|
# Define loggers handlers
|
||||||
handlers = set(LOGGERS_HANDLERS)
|
handlers = set(LOGGERS_HANDLERS)
|
||||||
if quiet and 'tty' in handlers:
|
if quiet and 'tty' in handlers:
|
||||||
|
@ -100,7 +97,7 @@ def _init_moulinette(debug=False, verbose=False, quiet=False):
|
||||||
handlers.append('tty')
|
handlers.append('tty')
|
||||||
|
|
||||||
root_handlers = set(handlers)
|
root_handlers = set(handlers)
|
||||||
if not debug:
|
if not debug and 'tty' in root_handlers:
|
||||||
root_handlers.remove('tty')
|
root_handlers.remove('tty')
|
||||||
|
|
||||||
# Define loggers level
|
# Define loggers level
|
||||||
|
@ -167,11 +164,10 @@ def _init_moulinette(debug=False, verbose=False, quiet=False):
|
||||||
_die(str(e))
|
_die(str(e))
|
||||||
|
|
||||||
# Initialize moulinette
|
# Initialize moulinette
|
||||||
init(logging_config=logging, _from_source=IN_DEVEL)
|
moulinette.init(logging_config=logging, _from_source=IN_DEVEL)
|
||||||
|
|
||||||
def _retrieve_namespaces():
|
def _retrieve_namespaces():
|
||||||
"""Return the list of namespaces to load"""
|
"""Return the list of namespaces to load"""
|
||||||
from moulinette.actionsmap import ActionsMap
|
|
||||||
ret = ['yunohost']
|
ret = ['yunohost']
|
||||||
for n in ActionsMap.get_namespaces():
|
for n in ActionsMap.get_namespaces():
|
||||||
# Append YunoHost modules
|
# Append YunoHost modules
|
||||||
|
@ -190,8 +186,6 @@ if __name__ == '__main__':
|
||||||
if not os.path.isfile('/etc/yunohost/installed') and \
|
if not os.path.isfile('/etc/yunohost/installed') and \
|
||||||
(len(args) < 2 or (args[0] +' '+ args[1] != 'tools postinstall' and \
|
(len(args) < 2 or (args[0] +' '+ args[1] != 'tools postinstall' and \
|
||||||
args[0] +' '+ args[1] != 'backup restore')):
|
args[0] +' '+ args[1] != 'backup restore')):
|
||||||
from moulinette.interfaces.cli import get_locale
|
|
||||||
|
|
||||||
# Init i18n
|
# Init i18n
|
||||||
m18n.load_namespace('yunohost')
|
m18n.load_namespace('yunohost')
|
||||||
m18n.set_locale(get_locale())
|
m18n.set_locale(get_locale())
|
||||||
|
@ -200,8 +194,8 @@ if __name__ == '__main__':
|
||||||
_die(m18n.n('yunohost_not_installed'), m18n.g('error'))
|
_die(m18n.n('yunohost_not_installed'), m18n.g('error'))
|
||||||
|
|
||||||
# Execute the action
|
# Execute the action
|
||||||
from moulinette import cli
|
ret = moulinette.cli(
|
||||||
ret = cli(_retrieve_namespaces(), args,
|
_retrieve_namespaces(), args,
|
||||||
use_cache=opts.use_cache, output_as=opts.output_as,
|
use_cache=opts.use_cache, output_as=opts.output_as,
|
||||||
password=opts.password, parser_kwargs={'top_parser': parser}
|
password=opts.password, parser_kwargs={'top_parser': parser}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#!/usr/bin/env python
|
#! /usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
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
|
# Either we are in a development environment or not
|
||||||
IN_DEVEL = False
|
IN_DEVEL = False
|
||||||
|
@ -38,17 +43,11 @@ if IN_DEVEL:
|
||||||
|
|
||||||
def _die(message, title='Error:'):
|
def _die(message, title='Error:'):
|
||||||
"""Print error message and exit"""
|
"""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))
|
print('%s %s' % (colorize(title, 'red'), message))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def _parse_api_args():
|
def _parse_api_args():
|
||||||
"""Parse main arguments for the api"""
|
"""Parse main arguments for the api"""
|
||||||
import argparse
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(add_help=False,
|
parser = argparse.ArgumentParser(add_help=False,
|
||||||
description="Run the YunoHost API to manage your server.",
|
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):
|
def _init_moulinette(use_websocket=True, debug=False, verbose=False):
|
||||||
"""Configure logging and initialize the moulinette"""
|
"""Configure logging and initialize the moulinette"""
|
||||||
from moulinette import init
|
|
||||||
|
|
||||||
# Define loggers handlers
|
# Define loggers handlers
|
||||||
handlers = set(LOGGERS_HANDLERS)
|
handlers = set(LOGGERS_HANDLERS)
|
||||||
if not use_websocket and 'api' in 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))
|
_die(str(e))
|
||||||
|
|
||||||
# Initialize moulinette
|
# Initialize moulinette
|
||||||
init(logging_config=logging, _from_source=IN_DEVEL)
|
moulinette.init(logging_config=logging, _from_source=IN_DEVEL)
|
||||||
|
|
||||||
def _retrieve_namespaces():
|
def _retrieve_namespaces():
|
||||||
"""Return the list of namespaces to load"""
|
"""Return the list of namespaces to load"""
|
||||||
from moulinette.actionsmap import ActionsMap
|
|
||||||
ret = ['yunohost']
|
ret = ['yunohost']
|
||||||
for n in ActionsMap.get_namespaces():
|
for n in ActionsMap.get_namespaces():
|
||||||
# Append YunoHost modules
|
# Append YunoHost modules
|
||||||
|
@ -195,14 +191,12 @@ if __name__ == '__main__':
|
||||||
_init_moulinette(opts.use_websocket, opts.debug, opts.verbose)
|
_init_moulinette(opts.use_websocket, opts.debug, opts.verbose)
|
||||||
|
|
||||||
# Run the server
|
# Run the server
|
||||||
from moulinette import api, MoulinetteError
|
|
||||||
from yunohost.utils.packages import ynh_packages_version
|
from yunohost.utils.packages import ynh_packages_version
|
||||||
ret = api(_retrieve_namespaces(),
|
ret = moulinette.api(
|
||||||
host=opts.host, port=opts.port,
|
_retrieve_namespaces(),
|
||||||
routes={
|
host=opts.host, port=opts.port, routes={
|
||||||
('GET', '/installed'): is_installed,
|
('GET', '/installed'): is_installed,
|
||||||
('GET', '/version'): ynh_packages_version,
|
('GET', '/version'): ynh_packages_version,
|
||||||
},
|
}, use_cache=opts.use_cache, use_websocket=opts.use_websocket
|
||||||
use_cache=opts.use_cache, use_websocket=opts.use_websocket
|
|
||||||
)
|
)
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
|
|
@ -334,7 +334,7 @@ app:
|
||||||
arguments:
|
arguments:
|
||||||
-u:
|
-u:
|
||||||
full: --url
|
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:
|
-n:
|
||||||
full: --name
|
full: --name
|
||||||
help: Name of the list (default yunohost)
|
help: Name of the list (default yunohost)
|
||||||
|
@ -377,6 +377,14 @@ app:
|
||||||
full: --raw
|
full: --raw
|
||||||
help: Return the full app_dict
|
help: Return the full app_dict
|
||||||
action: store_true
|
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()
|
### app_info()
|
||||||
info:
|
info:
|
||||||
|
@ -428,7 +436,7 @@ app:
|
||||||
help: Custom name for the app
|
help: Custom name for the app
|
||||||
-a:
|
-a:
|
||||||
full: --args
|
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
|
### app_remove() TODO: Write help
|
||||||
remove:
|
remove:
|
||||||
|
@ -639,6 +647,8 @@ backup:
|
||||||
action_help: Restore from a local backup archive
|
action_help: Restore from a local backup archive
|
||||||
api: POST /backup/restore/<name>
|
api: POST /backup/restore/<name>
|
||||||
configuration:
|
configuration:
|
||||||
|
authenticate: all
|
||||||
|
authenticator: ldap-anonymous
|
||||||
lock: false
|
lock: false
|
||||||
arguments:
|
arguments:
|
||||||
name:
|
name:
|
||||||
|
@ -969,7 +979,6 @@ service:
|
||||||
action_help: >
|
action_help: >
|
||||||
Check if the specific file has been modified and display differences.
|
Check if the specific file has been modified and display differences.
|
||||||
Stores the file hash in the services.yml file
|
Stores the file hash in the services.yml file
|
||||||
api: PUT /services/safecopy
|
|
||||||
arguments:
|
arguments:
|
||||||
new_conf_file:
|
new_conf_file:
|
||||||
help: Path to the desired conf file
|
help: Path to the desired conf file
|
||||||
|
@ -990,7 +999,6 @@ service:
|
||||||
action_help: >
|
action_help: >
|
||||||
Check if the specific file has been modified before removing it.
|
Check if the specific file has been modified before removing it.
|
||||||
Backup the file in /home/yunohost.backup
|
Backup the file in /home/yunohost.backup
|
||||||
api: PUT /services/safecopy
|
|
||||||
arguments:
|
arguments:
|
||||||
conf_file:
|
conf_file:
|
||||||
help: Path to the targeted conf file
|
help: Path to the targeted conf file
|
||||||
|
@ -1159,10 +1167,10 @@ dyndns:
|
||||||
arguments:
|
arguments:
|
||||||
--dyn-host:
|
--dyn-host:
|
||||||
help: Dynette DNS server to inform
|
help: Dynette DNS server to inform
|
||||||
default: "dynhost.yunohost.org"
|
default: "dyndns.yunohost.org"
|
||||||
-d:
|
-d:
|
||||||
full: --domain
|
full: --domain
|
||||||
help: Full domain to subscribe with
|
help: Full domain to update
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_domain
|
pattern: *pattern_domain
|
||||||
-k:
|
-k:
|
||||||
|
@ -1314,7 +1322,6 @@ hook:
|
||||||
### hook_add()
|
### hook_add()
|
||||||
add:
|
add:
|
||||||
action_help: Store hook script to filesystem
|
action_help: Store hook script to filesystem
|
||||||
api: PUT /hook
|
|
||||||
arguments:
|
arguments:
|
||||||
app:
|
app:
|
||||||
help: App to link with
|
help: App to link with
|
||||||
|
@ -1324,7 +1331,6 @@ hook:
|
||||||
### hook_remove()
|
### hook_remove()
|
||||||
remove:
|
remove:
|
||||||
action_help: Remove hook scripts from filesystem
|
action_help: Remove hook scripts from filesystem
|
||||||
api: DELETE /hook
|
|
||||||
arguments:
|
arguments:
|
||||||
app:
|
app:
|
||||||
help: Scripts related to app will be removed
|
help: Scripts related to app will be removed
|
||||||
|
@ -1362,7 +1368,7 @@ hook:
|
||||||
### hook_callback()
|
### hook_callback()
|
||||||
callback:
|
callback:
|
||||||
action_help: Execute all scripts binded to an action
|
action_help: Execute all scripts binded to an action
|
||||||
api: GET /hooks
|
api: POST /hooks/<action>
|
||||||
arguments:
|
arguments:
|
||||||
action:
|
action:
|
||||||
help: Action name
|
help: Action name
|
||||||
|
@ -1378,7 +1384,6 @@ hook:
|
||||||
### hook_exec()
|
### hook_exec()
|
||||||
exec:
|
exec:
|
||||||
action_help: Execute hook from a file with arguments
|
action_help: Execute hook from a file with arguments
|
||||||
api: GET /hook
|
|
||||||
arguments:
|
arguments:
|
||||||
path:
|
path:
|
||||||
help: Path of the script to execute
|
help: Path of the script to execute
|
||||||
|
@ -1392,3 +1397,6 @@ hook:
|
||||||
full: --no-trace
|
full: --no-trace
|
||||||
help: Do not print each command that will be executed
|
help: Do not print each command that will be executed
|
||||||
action: store_true
|
action: store_true
|
||||||
|
-d:
|
||||||
|
full: --chdir
|
||||||
|
help: The directory from where the script will be executed
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# | arg: app - the application id
|
# | arg: app - the application id
|
||||||
# | arg: key - the setting to get
|
# | arg: key - the setting to get
|
||||||
ynh_app_setting_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
|
# Set an application setting
|
||||||
|
@ -14,7 +14,7 @@ ynh_app_setting_get() {
|
||||||
# | arg: key - the setting name to set
|
# | arg: key - the setting name to set
|
||||||
# | arg: value - the setting value to set
|
# | arg: value - the setting value to set
|
||||||
ynh_app_setting_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
|
# Delete an application setting
|
||||||
|
@ -23,5 +23,5 @@ ynh_app_setting_set() {
|
||||||
# | arg: app - the application id
|
# | arg: app - the application id
|
||||||
# | arg: key - the setting to delete
|
# | arg: key - the setting to delete
|
||||||
ynh_app_setting_delete() {
|
ynh_app_setting_delete() {
|
||||||
sudo yunohost app setting -d "$1" "$2"
|
sudo yunohost app setting -d "$1" "$2" --quiet
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,11 @@ function safe_copy () {
|
||||||
|
|
||||||
cd /usr/share/yunohost/templates/rspamd
|
cd /usr/share/yunohost/templates/rspamd
|
||||||
|
|
||||||
# Copy Rspamd configuration
|
# Create configuration directories
|
||||||
safe_copy metrics.conf /etc/rspamd/metrics.conf
|
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
|
# Install Rspamd sieve script
|
||||||
safe_copy rspamd.sieve /etc/dovecot/global_script/rspamd.sieve
|
safe_copy rspamd.sieve /etc/dovecot/global_script/rspamd.sieve
|
||||||
|
|
|
@ -17,11 +17,11 @@ function safe_copy () {
|
||||||
cd /usr/share/yunohost/templates/dnsmasq
|
cd /usr/share/yunohost/templates/dnsmasq
|
||||||
|
|
||||||
# Get IPv4 address
|
# 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'
|
ynh_validate_ip4 $ip || ip='0.0.0.0'
|
||||||
|
|
||||||
# Get IPv6 IP address
|
# 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=''
|
ynh_validate_ip6 $ipv6 || ipv6=''
|
||||||
|
|
||||||
sudo mkdir -p /etc/dnsmasq.d
|
sudo mkdir -p /etc/dnsmasq.d
|
||||||
|
|
|
@ -29,11 +29,14 @@ server {
|
||||||
return 302 https://$http_host/yunohost/admin;
|
return 302 https://$http_host/yunohost/admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Block crawlers bot
|
|
||||||
location /yunohost {
|
location /yunohost {
|
||||||
|
# Block crawlers bot
|
||||||
if ($http_user_agent ~ (crawl|Googlebot|Slurp|spider|bingbot|tracker|click|parser|spider|facebookexternalhit) ) {
|
if ($http_user_agent ~ (crawl|Googlebot|Slurp|spider|bingbot|tracker|click|parser|spider|facebookexternalhit) ) {
|
||||||
return 403;
|
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;
|
include conf.d/yunohost_admin.conf.inc;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
8
data/templates/rspamd/metrics.conf.local
Normal file
8
data/templates/rspamd/metrics.conf.local
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Metrics settings
|
||||||
|
# This define overridden options.
|
||||||
|
|
||||||
|
actions {
|
||||||
|
reject = 21;
|
||||||
|
add_header = 8;
|
||||||
|
greylist = 4;
|
||||||
|
}
|
69
debian/changelog
vendored
69
debian/changelog
vendored
|
@ -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
|
yunohost (2.3.10.2) testing; urgency=low
|
||||||
|
|
||||||
* [fix] Workaround for the bad people who are not using IPv6 yet
|
* [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
|
-- 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
|
moulinette-yunohost (2.2.3) stable; urgency=low
|
||||||
|
|
||||||
* [fix] Catch proper exception in backup_list (fix #65)
|
* [fix] Catch proper exception in backup_list (fix #65)
|
||||||
|
|
77
debian/control
vendored
77
debian/control
vendored
|
@ -9,50 +9,41 @@ Homepage: https://yunohost.org/
|
||||||
|
|
||||||
Package: yunohost
|
Package: yunohost
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Depends: ${python:Depends}, ${misc:Depends},
|
Depends: ${python:Depends}, ${misc:Depends}
|
||||||
moulinette (>= 2.3.4),
|
, moulinette (>= 2.3.4)
|
||||||
python-psutil,
|
, python-psutil, python-requests, python-dnspython
|
||||||
python-requests,
|
, python-apt, python-miniupnpc
|
||||||
glances,
|
, glances
|
||||||
python-pip,
|
, dnsutils, bind9utils, unzip, git, curl, cron
|
||||||
python-miniupnpc | pyminiupnpc,
|
, ca-certificates, netcat-openbsd, iproute
|
||||||
dnsutils,
|
, mariadb-server | mysql-server, php5-mysql | php5-mysqlnd
|
||||||
bind9utils,
|
, slapd, ldap-utils, sudo-ldap, libnss-ldapd
|
||||||
python-apt,
|
, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail
|
||||||
ca-certificates,
|
, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved
|
||||||
python-dnspython,
|
, dovecot-antispam, fail2ban
|
||||||
netcat-openbsd,
|
, nginx-extras (>=1.6.2), php5-fpm, php5-ldap, php5-intl
|
||||||
iproute,
|
, dnsmasq, openssl, avahi-daemon
|
||||||
unzip,
|
, ssowat, metronome
|
||||||
git-core,
|
, rspamd (>= 1.2.0), rmilter (>=1.7.0), redis-server, opendkim-tools
|
||||||
curl,
|
Recommends: yunohost-admin
|
||||||
mariadb-server | mysql-server, php5-mysql | php5-mysqlnd,
|
, openssh-server, ntp, inetutils-ping | iputils-ping
|
||||||
slapd, ldap-utils, sudo-ldap, libnss-ldapd,
|
, bash-completion, rsyslog
|
||||||
postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail,
|
, php5-gd, php5-curl, php-gettext, php5-mcrypt
|
||||||
dovecot-ldap, dovecot-lmtpd, dovecot-managesieved,
|
, python-pip
|
||||||
dovecot-antispam, fail2ban,
|
, unattended-upgrades
|
||||||
nginx-extras (>=1.6.2), php5-fpm, php5-ldap, php5-intl,
|
, libdbd-ldap-perl, libnet-dns-perl
|
||||||
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
|
|
||||||
Suggests: htop, vim, rsync, acpi-support-base, udisks2
|
Suggests: htop, vim, rsync, acpi-support-base, udisks2
|
||||||
Conflicts: iptables-persistent,
|
Conflicts: iptables-persistent
|
||||||
moulinette-yunohost, yunohost-config,
|
, moulinette-yunohost, yunohost-config
|
||||||
yunohost-config-others, yunohost-config-postfix,
|
, yunohost-config-others, yunohost-config-postfix
|
||||||
yunohost-config-dovecot, yunohost-config-slapd,
|
, yunohost-config-dovecot, yunohost-config-slapd
|
||||||
yunohost-config-nginx, yunohost-config-amavis,
|
, yunohost-config-nginx, yunohost-config-amavis
|
||||||
yunohost-config-mysql, yunohost-predepends
|
, yunohost-config-mysql, yunohost-predepends
|
||||||
Replaces: moulinette-yunohost, yunohost-config,
|
Replaces: moulinette-yunohost, yunohost-config
|
||||||
yunohost-config-others, yunohost-config-postfix,
|
, yunohost-config-others, yunohost-config-postfix
|
||||||
yunohost-config-dovecot, yunohost-config-slapd,
|
, yunohost-config-dovecot, yunohost-config-slapd
|
||||||
yunohost-config-nginx, yunohost-config-amavis,
|
, yunohost-config-nginx, yunohost-config-amavis
|
||||||
yunohost-config-mysql, yunohost-predepends
|
, yunohost-config-mysql, yunohost-predepends
|
||||||
Description: manageable and configured self-hosting server
|
Description: manageable and configured self-hosting server
|
||||||
YunoHost aims to make self-hosting accessible to everyone. It configures
|
YunoHost aims to make self-hosting accessible to everyone. It configures
|
||||||
an email, Web and IM server alongside a LDAP base. It also provides
|
an email, Web and IM server alongside a LDAP base. It also provides
|
||||||
|
|
3
debian/rules
vendored
3
debian/rules
vendored
|
@ -8,7 +8,8 @@
|
||||||
dh ${@} --with=python2,systemd
|
dh ${@} --with=python2,systemd
|
||||||
|
|
||||||
override_dh_installinit:
|
override_dh_installinit:
|
||||||
dh_installinit --noscripts
|
dh_installinit -pyunohost --name=yunohost-api --noscripts
|
||||||
|
dh_installinit -pyunohost --name=yunohost-firewall --noscripts
|
||||||
|
|
||||||
override_dh_systemd_enable:
|
override_dh_systemd_enable:
|
||||||
dh_systemd_enable --name=yunohost-api
|
dh_systemd_enable --name=yunohost-api
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"installation_complete" : "Installation complete",
|
"installation_complete" : "Installation complete",
|
||||||
"installation_failed" : "Installation failed",
|
"installation_failed" : "Installation failed",
|
||||||
"unexpected_error" : "An unexpected error occured",
|
"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}'",
|
"not_enough_disk_space" : "Not enough free disk space on '{path:s}'",
|
||||||
|
|
||||||
"license_undefined" : "undefined",
|
"license_undefined" : "undefined",
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
"app_upgrade_failed" : "Unable to upgrade {app:s}",
|
"app_upgrade_failed" : "Unable to upgrade {app:s}",
|
||||||
"app_id_invalid" : "Invalid app id",
|
"app_id_invalid" : "Invalid app id",
|
||||||
"app_already_installed" : "{app:s} is already installed",
|
"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_removed" : "{app:s} successfully removed",
|
||||||
"app_location_already_used" : "An app is already installed on this location",
|
"app_location_already_used" : "An app is already installed on this location",
|
||||||
"app_location_install_failed" : "Unable to install the app 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",
|
"no_ipv6_connectivity": "IPv6 connectivity is not available",
|
||||||
|
|
||||||
"dyndns_key_generating" : "DNS key is being generated, it may take a while...",
|
"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_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_registered" : "DynDNS domain successfully registered",
|
||||||
"dyndns_ip_update_failed" : "Unable to update IP address on DynDNS",
|
"dyndns_ip_update_failed" : "Unable to update IP address on DynDNS",
|
||||||
"dyndns_ip_updated" : "IP address successfully updated on DynDNS",
|
"dyndns_ip_updated" : "IP address successfully updated on DynDNS",
|
||||||
|
@ -79,8 +82,8 @@
|
||||||
|
|
||||||
"port_available" : "Port {port:d} is available",
|
"port_available" : "Port {port:d} is available",
|
||||||
"port_unavailable" : "Port {port:d} is not available",
|
"port_unavailable" : "Port {port:d} is not available",
|
||||||
"port_already_opened" : "Port {} is already opened for {:s} connections",
|
"port_already_opened" : "Port {port:d} is already opened for {ip_version:s} connections",
|
||||||
"port_already_closed" : "Port {} is already closed for {: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.",
|
"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.",
|
"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",
|
"upnp_dev_not_found" : "No UPnP device found",
|
||||||
|
@ -92,12 +95,12 @@
|
||||||
"firewall_reloaded" : "Firewall successfully reloaded",
|
"firewall_reloaded" : "Firewall successfully reloaded",
|
||||||
|
|
||||||
"hook_list_by_invalid" : "Invalid property to list hook by",
|
"hook_list_by_invalid" : "Invalid property to list hook by",
|
||||||
"hook_name_unknown" : "Unknown hook name '{:s}'",
|
"hook_name_unknown" : "Unknown hook name '{name:s}'",
|
||||||
"hook_exec_failed" : "Script execution failed",
|
"hook_exec_failed" : "Script execution failed: {path:s}",
|
||||||
"hook_exec_not_terminated" : "Script execution hasn’t terminated",
|
"hook_exec_not_terminated" : "Script execution hasn’t terminated: {path:s}",
|
||||||
|
|
||||||
"mountpoint_unknown" : "Unknown mountpoint",
|
"mountpoint_unknown" : "Unknown mountpoint",
|
||||||
"unit_unknown" : "Unknown unit '{:s}'",
|
"unit_unknown" : "Unknown unit '{unit:s}'",
|
||||||
"monitor_period_invalid" : "Invalid time period",
|
"monitor_period_invalid" : "Invalid time period",
|
||||||
"monitor_stats_no_update" : "No monitoring statistics to update",
|
"monitor_stats_no_update" : "No monitoring statistics to update",
|
||||||
"monitor_stats_file_not_found" : "Statistics file not found",
|
"monitor_stats_file_not_found" : "Statistics file not found",
|
||||||
|
@ -107,25 +110,26 @@
|
||||||
"monitor_not_enabled" : "Server monitoring is not enabled",
|
"monitor_not_enabled" : "Server monitoring is not enabled",
|
||||||
"monitor_glances_con_failed" : "Unable to connect to Glances server",
|
"monitor_glances_con_failed" : "Unable to connect to Glances server",
|
||||||
|
|
||||||
"service_unknown" : "Unknown service '{:s}'",
|
"service_unknown" : "Unknown service '{service:s}'",
|
||||||
"service_add_failed" : "Unable to add service '{:s}'",
|
"service_add_failed" : "Unable to add service '{service:s}'",
|
||||||
"service_added" : "Service successfully added",
|
"service_added" : "Service successfully added: '{service:s}'",
|
||||||
"service_remove_failed" : "Unable to remove service '{:s}'",
|
"service_remove_failed" : "Unable to remove service '{service:s}'",
|
||||||
"service_removed" : "Service successfully removed",
|
"service_removed" : "Service successfully removed: '{service:s}'",
|
||||||
"service_start_failed" : "Unable to start service '{:s}'",
|
"service_start_failed" : "Unable to start service '{service:s}'",
|
||||||
"service_already_started" : "Service '{:s}' is already started",
|
"service_already_started" : "Service '{service:s}' is already started",
|
||||||
"service_started" : "Service '{:s}' successfully started",
|
"service_started" : "Service '{service:s}' successfully started",
|
||||||
"service_stop_failed" : "Unable to stop service '{:s}'",
|
"service_stop_failed" : "Unable to stop service '{service:s}'",
|
||||||
"service_already_stopped" : "Service '{:s}' is already stopped",
|
"service_already_stopped" : "Service '{service:s}' is already stopped",
|
||||||
"service_stopped" : "Service '{:s}' successfully stopped",
|
"service_stopped" : "Service '{service:s}' successfully stopped",
|
||||||
"service_enable_failed" : "Unable to enable service '{:s}'",
|
"service_enable_failed" : "Unable to enable service '{service:s}'",
|
||||||
"service_enabled" : "Service '{:s}' successfully enabled",
|
"service_enabled" : "Service '{service:s}' successfully enabled",
|
||||||
"service_disable_failed" : "Unable to disable service '{:s}'",
|
"service_disable_failed" : "Unable to disable service '{service:s}'",
|
||||||
"service_disabled" : "Service '{:s}' successfully disabled",
|
"service_disabled" : "Service '{service:s}' successfully disabled",
|
||||||
"service_status_failed" : "Unable to determine status of service '{:s}'",
|
"service_status_failed" : "Unable to determine status of service '{service:s}'",
|
||||||
"service_no_log" : "No log to display for service '{:s}'",
|
"service_no_log" : "No log to display for service '{service:s}'",
|
||||||
"service_cmd_exec_failed" : "Unable to execute command '{:s}'",
|
"service_cmd_exec_failed" : "Unable to execute command '{command:s}'",
|
||||||
"services_configured": "Configuration successfully generated",
|
"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).",
|
"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",
|
"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}",
|
"service_add_configuration": "Adding the configuration file {file:s}",
|
||||||
|
@ -148,14 +152,14 @@
|
||||||
"updating_apt_cache" : "Updating the lists of available packages...",
|
"updating_apt_cache" : "Updating the lists of available packages...",
|
||||||
"update_cache_failed" : "Unable to update APT cache",
|
"update_cache_failed" : "Unable to update APT cache",
|
||||||
"packages_no_upgrade" : "There is no package to upgrade",
|
"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...",
|
"upgrading_packages" : "Upgrading packages...",
|
||||||
"packages_upgrade_failed" : "Unable to upgrade all packages",
|
"packages_upgrade_failed" : "Unable to upgrade all packages",
|
||||||
"system_upgraded" : "System successfully upgraded",
|
"system_upgraded" : "System successfully upgraded",
|
||||||
|
|
||||||
"backup_action_required" : "You must specify something to save",
|
"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_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_output_directory_not_empty" : "Output directory is not empty",
|
||||||
"backup_hook_unknown" : "Backup hook '{hook:s}' unknown",
|
"backup_hook_unknown" : "Backup hook '{hook:s}' unknown",
|
||||||
"backup_running_hooks" : "Running backup hooks...",
|
"backup_running_hooks" : "Running backup hooks...",
|
||||||
|
@ -190,10 +194,10 @@
|
||||||
"backup_deleted" : "Backup successfully deleted",
|
"backup_deleted" : "Backup successfully deleted",
|
||||||
|
|
||||||
"field_invalid" : "Invalid field '{:s}'",
|
"field_invalid" : "Invalid field '{:s}'",
|
||||||
"mail_domain_unknown" : "Unknown mail address domain '{:s}'",
|
"mail_domain_unknown" : "Unknown mail address domain '{domain:s}'",
|
||||||
"mail_alias_remove_failed" : "Unable to remove mail alias '{:s}'",
|
"mail_alias_remove_failed" : "Unable to remove mail alias '{mail:s}'",
|
||||||
"mail_forward_remove_failed" : "Unable to remove mail forward '{:s}'",
|
"mail_forward_remove_failed" : "Unable to remove mail forward '{mail:s}'",
|
||||||
"user_unknown" : "Unknown user",
|
"user_unknown" : "Unknown user: {user:s}",
|
||||||
"system_username_exists" : "Username already exists in the system users",
|
"system_username_exists" : "Username already exists in the system users",
|
||||||
"user_creation_failed" : "Unable to create user",
|
"user_creation_failed" : "Unable to create user",
|
||||||
"user_created" : "User successfully created",
|
"user_created" : "User successfully created",
|
||||||
|
|
|
@ -85,7 +85,7 @@ def app_fetchlist(url=None, name=None):
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
name -- Name of the list (default yunohost)
|
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
|
# Create app path if not exists
|
||||||
|
@ -93,7 +93,7 @@ def app_fetchlist(url=None, name=None):
|
||||||
except OSError: os.makedirs(repo_path)
|
except OSError: os.makedirs(repo_path)
|
||||||
|
|
||||||
if url is None:
|
if url is None:
|
||||||
url = 'https://yunohost.org/official.json'
|
url = 'https://app.yunohost.org/official.json'
|
||||||
name = 'yunohost'
|
name = 'yunohost'
|
||||||
else:
|
else:
|
||||||
if name is None:
|
if name is None:
|
||||||
|
@ -131,7 +131,7 @@ def app_removelist(name):
|
||||||
logger.success(m18n.n('appslist_removed'))
|
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
|
List apps
|
||||||
|
|
||||||
|
@ -140,12 +140,15 @@ def app_list(offset=None, limit=None, filter=None, raw=False):
|
||||||
offset -- Starting number for app fetching
|
offset -- Starting number for app fetching
|
||||||
limit -- Maximum number of app fetched
|
limit -- Maximum number of app fetched
|
||||||
raw -- Return the full app_dict
|
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)
|
if offset: offset = int(offset)
|
||||||
else: offset = 0
|
else: offset = 0
|
||||||
if limit: limit = int(limit)
|
if limit: limit = int(limit)
|
||||||
else: limit = 1000
|
else: limit = 1000
|
||||||
|
installed = with_backup or installed
|
||||||
|
|
||||||
app_dict = {}
|
app_dict = {}
|
||||||
if raw:
|
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():
|
for app_id, app_info_dict in sorted_app_dict.items():
|
||||||
if i < limit:
|
if i < limit:
|
||||||
if (filter and ((filter in app_id) or (filter in app_info_dict['manifest']['name']))) or not filter:
|
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:
|
if raw:
|
||||||
app_info_dict['installed'] = installed
|
app_info_dict['installed'] = app_installed
|
||||||
if installed:
|
if app_installed:
|
||||||
app_info_dict['status'] = _get_app_status(app_id)
|
app_info_dict['status'] = _get_app_status(app_id)
|
||||||
list_dict[app_id] = app_info_dict
|
list_dict[app_id] = app_info_dict
|
||||||
else:
|
else:
|
||||||
label = None
|
label = None
|
||||||
if installed:
|
if app_installed:
|
||||||
app_info_dict_raw = app_info(app=app_id, raw=True)
|
app_info_dict_raw = app_info(app=app_id, raw=True)
|
||||||
label = app_info_dict_raw['settings']['label']
|
label = app_info_dict_raw['settings']['label']
|
||||||
list_dict.append({
|
list_dict.append({
|
||||||
|
@ -209,7 +223,7 @@ def app_list(offset=None, limit=None, filter=None, raw=False):
|
||||||
# FIXME: Temporarly allow undefined license
|
# FIXME: Temporarly allow undefined license
|
||||||
'license': app_info_dict['manifest'].get('license',
|
'license': app_info_dict['manifest'].get('license',
|
||||||
m18n.n('license_undefined')),
|
m18n.n('license_undefined')),
|
||||||
'installed': installed
|
'installed': app_installed
|
||||||
})
|
})
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
@ -515,8 +529,40 @@ def app_install(auth, app, label=None, args=None):
|
||||||
# Move scripts and manifest to the right place
|
# Move scripts and manifest to the right place
|
||||||
os.system('cp %s/manifest.json %s' % (app_tmp_folder, app_setting_path))
|
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))
|
os.system('cp -R %s/scripts %s' % (app_tmp_folder, app_setting_path))
|
||||||
|
|
||||||
|
# Execute the app install script
|
||||||
|
install_retcode = 1
|
||||||
try:
|
try:
|
||||||
if hook_exec(app_tmp_folder + '/scripts/install', args=args_list, env=env_dict) == 0:
|
install_retcode = hook_exec(
|
||||||
|
os.path.join(app_tmp_folder, 'scripts/install'), args_list, env=env_dict)
|
||||||
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
install_retcode = -1
|
||||||
|
except:
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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
|
# Store app status
|
||||||
with open(app_setting_path + '/status.json', 'w+') as f:
|
with open(app_setting_path + '/status.json', 'w+') as f:
|
||||||
json.dump(status, f)
|
json.dump(status, f)
|
||||||
|
@ -526,26 +572,10 @@ def app_install(auth, app, label=None, args=None):
|
||||||
os.system('chmod -R 400 %s' % app_setting_path)
|
os.system('chmod -R 400 %s' % app_setting_path)
|
||||||
os.system('chown -R root: %s' % app_setting_path)
|
os.system('chown -R root: %s' % app_setting_path)
|
||||||
os.system('chown -R admin: %s/scripts' % 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'))
|
|
||||||
except:
|
|
||||||
# Execute remove script and clean folders
|
|
||||||
hook_remove(app_instance_name)
|
|
||||||
shutil.rmtree(app_setting_path)
|
|
||||||
shutil.rmtree(app_tmp_folder)
|
|
||||||
|
|
||||||
# Reraise proper exception
|
app_ssowatconf(auth)
|
||||||
try:
|
|
||||||
raise
|
logger.success(m18n.n('installation_complete'))
|
||||||
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'))
|
|
||||||
|
|
||||||
|
|
||||||
def app_remove(auth, app):
|
def app_remove(auth, app):
|
||||||
|
@ -624,10 +654,7 @@ def app_addaccess(auth, apps, users=[]):
|
||||||
try:
|
try:
|
||||||
user_info(auth, allowed_user)
|
user_info(auth, allowed_user)
|
||||||
except MoulinetteError:
|
except MoulinetteError:
|
||||||
# FIXME: Add username keyword in user_unknown
|
logger.warning(m18n.n('user_unknown', user=allowed_user))
|
||||||
logger.warning('{0}{1}'.format(
|
|
||||||
m18n.g('colon', m18n.n('user_unknown')),
|
|
||||||
allowed_user))
|
|
||||||
continue
|
continue
|
||||||
allowed_users.add(allowed_user)
|
allowed_users.add(allowed_user)
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,13 @@ from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils import filesystem
|
from moulinette.utils import filesystem
|
||||||
from moulinette.utils.log import getActionLogger
|
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'
|
backup_path = '/home/yunohost.backup'
|
||||||
archives_path = '%s/archives' % backup_path
|
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
|
# TODO: Add a 'clean' argument to clean output directory
|
||||||
from yunohost.hook import hook_info, hook_callback, hook_exec
|
|
||||||
|
|
||||||
tmp_dir = None
|
tmp_dir = None
|
||||||
|
|
||||||
# Validate what to backup
|
# Validate what to backup
|
||||||
|
@ -167,9 +172,6 @@ def backup_create(name=None, description=None, output_directory=None,
|
||||||
|
|
||||||
# Backup apps
|
# Backup apps
|
||||||
if not ignore_apps:
|
if not ignore_apps:
|
||||||
from yunohost.app import app_info
|
|
||||||
from yunohost.app import _parse_app_instance_name
|
|
||||||
|
|
||||||
# Filter applications to backup
|
# Filter applications to backup
|
||||||
apps_list = set(os.listdir('/etc/yunohost/apps'))
|
apps_list = set(os.listdir('/etc/yunohost/apps'))
|
||||||
apps_filtered = set()
|
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)
|
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
|
||||||
|
|
||||||
hook_exec(tmp_script, args=[tmp_app_bkp_dir, app_instance_name],
|
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:
|
except:
|
||||||
logger.exception(m18n.n('backup_app_failed', app=app_instance_name))
|
logger.exception(m18n.n('backup_app_failed', app=app_instance_name))
|
||||||
# Cleaning app backup directory
|
# Cleaning app backup directory
|
||||||
|
@ -288,21 +291,20 @@ def backup_create(name=None, description=None, output_directory=None,
|
||||||
return { 'archive': info }
|
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
|
Restore from a local backup archive
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
name -- Name of the local backup archive
|
name -- Name of the local backup archive
|
||||||
hooks -- List of restoration hooks names to execute
|
hooks -- List of restoration hooks names to execute
|
||||||
|
ignore_hooks -- Do not execute backup hooks
|
||||||
apps -- List of application names to restore
|
apps -- List of application names to restore
|
||||||
ignore_apps -- Do not restore apps
|
ignore_apps -- Do not restore apps
|
||||||
force -- Force restauration on an already installed system
|
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
|
# Validate what to restore
|
||||||
if ignore_hooks and ignore_apps:
|
if ignore_hooks and ignore_apps:
|
||||||
raise MoulinetteError(errno.EINVAL,
|
raise MoulinetteError(errno.EINVAL,
|
||||||
|
@ -380,8 +382,6 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals
|
||||||
_clean_tmp_dir()
|
_clean_tmp_dir()
|
||||||
raise MoulinetteError(errno.EEXIST, m18n.n('restore_failed'))
|
raise MoulinetteError(errno.EEXIST, m18n.n('restore_failed'))
|
||||||
else:
|
else:
|
||||||
from yunohost.tools import tools_postinstall
|
|
||||||
|
|
||||||
# Retrieve the domain from the backup
|
# Retrieve the domain from the backup
|
||||||
try:
|
try:
|
||||||
with open("%s/yunohost/current_host" % tmp_dir, 'r') as f:
|
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
|
# Add apps restore hook
|
||||||
if not ignore_apps:
|
if not ignore_apps:
|
||||||
from yunohost.app import _is_installed
|
|
||||||
from yunohost.app import _parse_app_instance_name
|
|
||||||
|
|
||||||
# Filter applications to restore
|
# Filter applications to restore
|
||||||
apps_list = set(info['apps'].keys())
|
apps_list = set(info['apps'].keys())
|
||||||
apps_filtered = set()
|
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:
|
for app_instance_name in apps_filtered:
|
||||||
tmp_app_dir = '{:s}/apps/{:s}'.format(tmp_dir, app_instance_name)
|
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
|
# Check if the app is not already installed
|
||||||
if _is_installed(app_instance_name):
|
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)
|
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
|
||||||
|
|
||||||
hook_exec(tmp_script, args=[tmp_app_dir + '/backup', app_instance_name],
|
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:
|
except:
|
||||||
logger.exception(m18n.n('restore_app_failed', app=app_instance_name))
|
logger.exception(m18n.n('restore_app_failed', app=app_instance_name))
|
||||||
# Cleaning app directory
|
# 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']:
|
if not result['hooks'] and not result['apps']:
|
||||||
_clean_tmp_dir(1)
|
_clean_tmp_dir(1)
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('restore_nothings_done'))
|
raise MoulinetteError(errno.EINVAL, m18n.n('restore_nothings_done'))
|
||||||
|
if result['apps']:
|
||||||
|
app_ssowatconf(auth)
|
||||||
|
|
||||||
_clean_tmp_dir()
|
_clean_tmp_dir()
|
||||||
logger.success(m18n.n('restore_complete'))
|
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
|
human_readable -- Print sizes in human readable format
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from yunohost.monitor import binary_to_human
|
|
||||||
|
|
||||||
archive_file = '%s/%s.tar.gz' % (archives_path, name)
|
archive_file = '%s/%s.tar.gz' % (archives_path, name)
|
||||||
if not os.path.isfile(archive_file):
|
if not os.path.isfile(archive_file):
|
||||||
raise MoulinetteError(errno.EIO,
|
raise MoulinetteError(errno.EIO,
|
||||||
|
@ -602,7 +600,6 @@ def backup_delete(name):
|
||||||
name -- Name of the local backup archive
|
name -- Name of the local backup archive
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from yunohost.hook import hook_callback
|
|
||||||
hook_callback('pre_backup_delete', args=[name])
|
hook_callback('pre_backup_delete', args=[name])
|
||||||
|
|
||||||
archive_file = '%s/%s.tar.gz' % (archives_path, name)
|
archive_file = '%s/%s.tar.gz' % (archives_path, name)
|
||||||
|
|
|
@ -24,12 +24,12 @@
|
||||||
Subscribe and Update DynDNS Hosts
|
Subscribe and Update DynDNS Hosts
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import requests
|
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
import glob
|
import glob
|
||||||
import base64
|
import base64
|
||||||
import errno
|
import errno
|
||||||
|
import requests
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
|
@ -62,6 +62,10 @@ class IPRouteLine(object):
|
||||||
for k, v in self.m.groupdict().items():
|
for k, v in self.m.groupdict().items():
|
||||||
setattr(self, k, v)
|
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):
|
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']
|
try: error = json.loads(r.text)['error']
|
||||||
except: error = "Server error"
|
except: error = "Server error"
|
||||||
raise MoulinetteError(errno.EPERM,
|
raise MoulinetteError(errno.EPERM,
|
||||||
m18n.n('dyndns_registration_failed', error))
|
m18n.n('dyndns_registration_failed', error=error))
|
||||||
|
|
||||||
logger.success(m18n.n('dyndns_registered'))
|
logger.success(m18n.n('dyndns_registered'))
|
||||||
|
|
||||||
dyndns_installcron()
|
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):
|
ipv4=None, ipv6=None):
|
||||||
"""
|
"""
|
||||||
Update IP on DynDNS platform
|
Update IP on DynDNS platform
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
domain -- Full domain to subscribe with
|
domain -- Full domain to update
|
||||||
dyn_host -- Dynette DNS server to inform
|
dyn_host -- Dynette DNS server to inform
|
||||||
key -- Public DNS key
|
key -- Public DNS key
|
||||||
ipv4 -- IP address to send
|
ipv4 -- IP address to send
|
||||||
ipv6 -- IPv6 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
|
# IPv4
|
||||||
if ipv4 is None:
|
if ipv4 is None:
|
||||||
ipv4 = get_public_ip()
|
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'
|
old_ipv6 = '0000:0000:0000:0000:0000:0000:0000:0000'
|
||||||
|
|
||||||
if old_ip != ipv4 or old_ipv6 != ipv6:
|
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 = domain.split('.')[1:]
|
||||||
host = '.'.join(host)
|
host = '.'.join(host)
|
||||||
lines = [
|
lines = [
|
||||||
|
@ -209,11 +240,7 @@ def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None,
|
||||||
for line in lines:
|
for line in lines:
|
||||||
zone.write(line + '\n')
|
zone.write(line + '\n')
|
||||||
|
|
||||||
if key is None:
|
if os.system('/usr/bin/nsupdate -k %s /etc/yunohost/dyndns/zone' % key) == 0:
|
||||||
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:
|
|
||||||
logger.success(m18n.n('dyndns_ip_updated'))
|
logger.success(m18n.n('dyndns_ip_updated'))
|
||||||
with open('/etc/yunohost/dyndns/old_ip', 'w') as f:
|
with open('/etc/yunohost/dyndns/old_ip', 'w') as f:
|
||||||
f.write(ipv4)
|
f.write(ipv4)
|
||||||
|
|
|
@ -83,7 +83,7 @@ def firewall_allow(protocol, port, ipv4_only=False, ipv6_only=False,
|
||||||
firewall[i][p].append(port)
|
firewall[i][p].append(port)
|
||||||
else:
|
else:
|
||||||
ipv = "IPv%s" % i[3]
|
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
|
# Add port forwarding with UPnP
|
||||||
if not no_upnp and port not in firewall['uPnP'][p]:
|
if not no_upnp and port not in firewall['uPnP'][p]:
|
||||||
firewall['uPnP'][p].append(port)
|
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)
|
firewall[i][p].remove(port)
|
||||||
else:
|
else:
|
||||||
ipv = "IPv%s" % i[3]
|
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
|
# Remove port forwarding with UPnP
|
||||||
if upnp and port in firewall['uPnP'][p]:
|
if upnp and port in firewall['uPnP'][p]:
|
||||||
firewall['uPnP'][p].remove(port)
|
firewall['uPnP'][p].remove(port)
|
||||||
|
@ -335,7 +335,7 @@ def firewall_upnp(action='status', no_refresh=False):
|
||||||
if action == 'status':
|
if action == 'status':
|
||||||
no_refresh = True
|
no_refresh = True
|
||||||
else:
|
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
|
# Refresh port mapping using UPnP
|
||||||
if not no_refresh:
|
if not no_refresh:
|
||||||
|
|
|
@ -110,7 +110,7 @@ def hook_info(action, name):
|
||||||
})
|
})
|
||||||
|
|
||||||
if not hooks:
|
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 {
|
return {
|
||||||
'action': action,
|
'action': action,
|
||||||
'name': name,
|
'name': name,
|
||||||
|
@ -275,7 +275,8 @@ def hook_callback(action, hooks=[], args=None):
|
||||||
return result
|
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
|
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
|
args -- A list of arguments to pass to the script
|
||||||
raise_on_error -- Raise if the script returns a non-zero exit code
|
raise_on_error -- Raise if the script returns a non-zero exit code
|
||||||
no_trace -- Do not print each command that will be executed
|
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
|
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'))
|
raise MoulinetteError(errno.EIO, m18n.g('file_not_exist'))
|
||||||
|
|
||||||
# Construct command variables
|
# Construct command variables
|
||||||
cmd_fdir, cmd_fname = os.path.split(path)
|
|
||||||
cmd_fname = './{0}'.format(cmd_fname)
|
|
||||||
|
|
||||||
cmd_args = ''
|
cmd_args = ''
|
||||||
if args and isinstance(args, list):
|
if args and isinstance(args, list):
|
||||||
# Concatenate arguments and escape them with double quotes to prevent
|
# Concatenate arguments and escape them with double quotes to prevent
|
||||||
# bash related issue if an argument is empty and is not the last
|
# bash related issue if an argument is empty and is not the last
|
||||||
cmd_args = '"{:s}"'.format('" "'.join(str(s) for s in args))
|
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 = ''
|
envcli = ''
|
||||||
if env is not None:
|
if env is not None:
|
||||||
envcli = ' '.join([ '{key}="{val}"'.format(key=key, val=val) for key,val in env.items()])
|
envcli = ' '.join([ '{key}="{val}"'.format(key=key, val=val) for key,val in env.items()])
|
||||||
|
|
||||||
# Construct command to execute
|
# Construct command to execute
|
||||||
command = ['sudo', '-u', 'admin', '-H', 'sh', '-c']
|
command = ['sudo', '-n', '-u', 'admin', '-H', 'sh', '-c']
|
||||||
if no_trace:
|
if no_trace:
|
||||||
cmd = 'cd "{0:s}" && {1:s} /bin/bash "{2:s}" {3:s}'
|
cmd = '{envcli} /bin/bash "{script}" {args}'
|
||||||
else:
|
else:
|
||||||
# use xtrace on fd 7 which is redirected to stdout
|
# 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'
|
cmd = '{envcli} BASH_XTRACEFD=7 /bin/bash -x "{script}" {args} 7>&1'
|
||||||
command.append(cmd.format(cmd_fdir, envcli, cmd_fname, cmd_args))
|
command.append(cmd.format(envcli=envcli, script=cmd_script, args=cmd_args))
|
||||||
|
|
||||||
if logger.isEnabledFor(log.DEBUG):
|
if logger.isEnabledFor(log.DEBUG):
|
||||||
logger.info(m18n.n('executing_command', command=' '.join(command)))
|
logger.info(m18n.n('executing_command', command=' '.join(command)))
|
||||||
else:
|
else:
|
||||||
logger.info(m18n.n('executing_script', script='{0}/{1}'.format(
|
logger.info(m18n.n('executing_script', script=path))
|
||||||
cmd_fdir, cmd_fname)))
|
|
||||||
|
|
||||||
# Define output callbacks and call command
|
# Define output callbacks and call command
|
||||||
callbacks = (
|
callbacks = (
|
||||||
lambda l: logger.info(l.rstrip()),
|
lambda l: logger.info(l.rstrip()),
|
||||||
lambda l: logger.warning(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
|
# Check and return process' return code
|
||||||
if returncode is None:
|
if returncode is None:
|
||||||
if raise_on_error:
|
if raise_on_error:
|
||||||
raise MoulinetteError(m18n.n('hook_exec_not_terminated'))
|
raise MoulinetteError(m18n.n('hook_exec_not_terminated', path=path))
|
||||||
else:
|
else:
|
||||||
logger.error(m18n.n('hook_exec_not_terminated'))
|
logger.error(m18n.n('hook_exec_not_terminated', path=path))
|
||||||
return 1
|
return 1
|
||||||
elif raise_on_error and returncode != 0:
|
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
|
return returncode
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ def monitor_disk(units=None, mountpoint=None, human_readable=False):
|
||||||
for dname in devices_names:
|
for dname in devices_names:
|
||||||
_set(dname, 'not-available')
|
_set(dname, 'not-available')
|
||||||
else:
|
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:
|
if result_dname is not None:
|
||||||
return result[result_dname]
|
return result[result_dname]
|
||||||
|
@ -237,7 +237,7 @@ def monitor_network(units=None, human_readable=False):
|
||||||
'gateway': gateway,
|
'gateway': gateway,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', u))
|
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown', unit=u))
|
||||||
|
|
||||||
if len(units) == 1:
|
if len(units) == 1:
|
||||||
return result[units[0]]
|
return result[units[0]]
|
||||||
|
@ -287,7 +287,7 @@ def monitor_system(units=None, human_readable=False):
|
||||||
elif u == 'infos':
|
elif u == 'infos':
|
||||||
result[u] = json.loads(glances.getSystem())
|
result[u] = json.loads(glances.getSystem())
|
||||||
else:
|
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:
|
if len(units) == 1 and type(result[units[0]]) is not str:
|
||||||
return result[units[0]]
|
return result[units[0]]
|
||||||
|
|
|
@ -75,9 +75,9 @@ def service_add(name, status=None, log=None, runlevel=None):
|
||||||
try:
|
try:
|
||||||
_save_services(services)
|
_save_services(services)
|
||||||
except:
|
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):
|
def service_remove(name):
|
||||||
|
@ -93,14 +93,14 @@ def service_remove(name):
|
||||||
try:
|
try:
|
||||||
del services[name]
|
del services[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', name))
|
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service=name))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_save_services(services)
|
_save_services(services)
|
||||||
except:
|
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):
|
def service_start(names):
|
||||||
|
@ -115,12 +115,12 @@ def service_start(names):
|
||||||
names = [names]
|
names = [names]
|
||||||
for name in names:
|
for name in names:
|
||||||
if _run_service_command('start', name):
|
if _run_service_command('start', name):
|
||||||
logger.success(m18n.n('service_started', name))
|
logger.success(m18n.n('service_started', service=name))
|
||||||
else:
|
else:
|
||||||
if service_status(name)['status'] != 'running':
|
if service_status(name)['status'] != 'running':
|
||||||
raise MoulinetteError(errno.EPERM,
|
raise MoulinetteError(errno.EPERM,
|
||||||
m18n.n('service_start_failed', name))
|
m18n.n('service_start_failed', service=name))
|
||||||
logger.info(m18n.n('service_already_started', name))
|
logger.info(m18n.n('service_already_started', service=name))
|
||||||
|
|
||||||
|
|
||||||
def service_stop(names):
|
def service_stop(names):
|
||||||
|
@ -135,12 +135,12 @@ def service_stop(names):
|
||||||
names = [names]
|
names = [names]
|
||||||
for name in names:
|
for name in names:
|
||||||
if _run_service_command('stop', name):
|
if _run_service_command('stop', name):
|
||||||
logger.success(m18n.n('service_stopped', name))
|
logger.success(m18n.n('service_stopped', service=name))
|
||||||
else:
|
else:
|
||||||
if service_status(name)['status'] != 'inactive':
|
if service_status(name)['status'] != 'inactive':
|
||||||
raise MoulinetteError(errno.EPERM,
|
raise MoulinetteError(errno.EPERM,
|
||||||
m18n.n('service_stop_failed', name))
|
m18n.n('service_stop_failed', service=name))
|
||||||
logger.info(m18n.n('service_already_stopped', name))
|
logger.info(m18n.n('service_already_stopped', service=name))
|
||||||
|
|
||||||
|
|
||||||
def service_enable(names):
|
def service_enable(names):
|
||||||
|
@ -155,10 +155,10 @@ def service_enable(names):
|
||||||
names = [names]
|
names = [names]
|
||||||
for name in names:
|
for name in names:
|
||||||
if _run_service_command('enable', name):
|
if _run_service_command('enable', name):
|
||||||
logger.success(m18n.n('service_enabled', name))
|
logger.success(m18n.n('service_enabled', service=name))
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EPERM,
|
raise MoulinetteError(errno.EPERM,
|
||||||
m18n.n('service_enable_failed', name))
|
m18n.n('service_enable_failed', service=name))
|
||||||
|
|
||||||
|
|
||||||
def service_disable(names):
|
def service_disable(names):
|
||||||
|
@ -173,10 +173,10 @@ def service_disable(names):
|
||||||
names = [names]
|
names = [names]
|
||||||
for name in names:
|
for name in names:
|
||||||
if _run_service_command('disable', name):
|
if _run_service_command('disable', name):
|
||||||
logger.success(m18n.n('service_disabled', name))
|
logger.success(m18n.n('service_disabled', service=name))
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EPERM,
|
raise MoulinetteError(errno.EPERM,
|
||||||
m18n.n('service_disable_failed', name))
|
m18n.n('service_disable_failed', service=name))
|
||||||
|
|
||||||
|
|
||||||
def service_status(names=[]):
|
def service_status(names=[]):
|
||||||
|
@ -200,7 +200,7 @@ def service_status(names=[]):
|
||||||
for name in names:
|
for name in names:
|
||||||
if check_names and name not in services.keys():
|
if check_names and name not in services.keys():
|
||||||
raise MoulinetteError(errno.EINVAL,
|
raise MoulinetteError(errno.EINVAL,
|
||||||
m18n.n('service_unknown', name))
|
m18n.n('service_unknown', service=name))
|
||||||
|
|
||||||
status = None
|
status = None
|
||||||
if 'status' not in services[name] or \
|
if 'status' not in services[name] or \
|
||||||
|
@ -221,7 +221,7 @@ def service_status(names=[]):
|
||||||
shell=True)
|
shell=True)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
if 'usage:' in e.output.lower():
|
if 'usage:' in e.output.lower():
|
||||||
logger.warning(m18n.n('service_status_failed', name))
|
logger.warning(m18n.n('service_status_failed', service=name))
|
||||||
else:
|
else:
|
||||||
result[name]['status'] = 'inactive'
|
result[name]['status'] = 'inactive'
|
||||||
else:
|
else:
|
||||||
|
@ -253,7 +253,7 @@ def service_log(name, number=50):
|
||||||
services = _get_services()
|
services = _get_services()
|
||||||
|
|
||||||
if name not in services.keys():
|
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]:
|
if 'log' in services[name]:
|
||||||
log_list = services[name]['log']
|
log_list = services[name]['log']
|
||||||
|
@ -268,7 +268,7 @@ def service_log(name, number=50):
|
||||||
else:
|
else:
|
||||||
result[log_path] = _tail(log_path, int(number))
|
result[log_path] = _tail(log_path, int(number))
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EPERM, m18n.n('service_no_log', name))
|
raise MoulinetteError(errno.EPERM, m18n.n('service_no_log', service=name))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -289,9 +289,10 @@ def service_regenconf(service=None, force=False):
|
||||||
|
|
||||||
if service is not None:
|
if service is not None:
|
||||||
hook_callback('conf_regen', [service], args=[force])
|
hook_callback('conf_regen', [service], args=[force])
|
||||||
|
logger.success(m18n.n('service_configured', service=service))
|
||||||
else:
|
else:
|
||||||
hook_callback('conf_regen', args=[force])
|
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):
|
def _run_service_command(action, service):
|
||||||
|
@ -304,8 +305,7 @@ def _run_service_command(action, service):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if service not in _get_services().keys():
|
if service not in _get_services().keys():
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown',
|
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service=service))
|
||||||
service))
|
|
||||||
|
|
||||||
cmd = None
|
cmd = None
|
||||||
if action in ['start', 'stop', 'restart', 'reload']:
|
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)
|
ret = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
# TODO: Log output?
|
# 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 False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ def tools_upgrade(auth, ignore_apps=False, ignore_packages=False):
|
||||||
# ... and set a hourly cron up to upgrade critical packages
|
# ... and set a hourly cron up to upgrade critical packages
|
||||||
if critical_upgrades:
|
if critical_upgrades:
|
||||||
logger.info(m18n.n('packages_upgrade_critical_later',
|
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:
|
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))
|
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))
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ def user_create(auth, username, firstname, lastname, mail, password,
|
||||||
if mail[mail.find('@')+1:] not in domain_list(auth)['domains']:
|
if mail[mail.find('@')+1:] not in domain_list(auth)['domains']:
|
||||||
raise MoulinetteError(errno.EINVAL,
|
raise MoulinetteError(errno.EINVAL,
|
||||||
m18n.n('mail_domain_unknown',
|
m18n.n('mail_domain_unknown',
|
||||||
mail[mail.find('@')+1:]))
|
domain=mail[mail.find('@')+1:]))
|
||||||
|
|
||||||
# Get random UID/GID
|
# Get random UID/GID
|
||||||
uid_check = gid_check = 0
|
uid_check = gid_check = 0
|
||||||
|
@ -275,7 +275,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
|
||||||
# Populate user informations
|
# Populate user informations
|
||||||
result = auth.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch)
|
result = auth.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch)
|
||||||
if not result:
|
if not result:
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown'))
|
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown', user=username))
|
||||||
user = result[0]
|
user = result[0]
|
||||||
|
|
||||||
# Get modifications from arguments
|
# 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:
|
if mail[mail.find('@')+1:] not in domains:
|
||||||
raise MoulinetteError(errno.EINVAL,
|
raise MoulinetteError(errno.EINVAL,
|
||||||
m18n.n('mail_domain_unknown',
|
m18n.n('mail_domain_unknown',
|
||||||
mail[mail.find('@')+1:]))
|
domain=mail[mail.find('@')+1:]))
|
||||||
del user['mail'][0]
|
del user['mail'][0]
|
||||||
new_attr_dict['mail'] = [mail] + user['mail']
|
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:
|
if mail[mail.find('@')+1:] not in domains:
|
||||||
raise MoulinetteError(errno.EINVAL,
|
raise MoulinetteError(errno.EINVAL,
|
||||||
m18n.n('mail_domain_unknown',
|
m18n.n('mail_domain_unknown',
|
||||||
mail[mail.find('@')+1:]))
|
domain=mail[mail.find('@')+1:]))
|
||||||
user['mail'].append(mail)
|
user['mail'].append(mail)
|
||||||
new_attr_dict['mail'] = user['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)
|
user['mail'].remove(mail)
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EINVAL,
|
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']
|
new_attr_dict['mail'] = user['mail']
|
||||||
|
|
||||||
if add_mailforward:
|
if add_mailforward:
|
||||||
|
@ -345,7 +345,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None,
|
||||||
user['maildrop'].remove(mail)
|
user['maildrop'].remove(mail)
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EINVAL,
|
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']
|
new_attr_dict['maildrop'] = user['maildrop']
|
||||||
|
|
||||||
if mailbox_quota is not None:
|
if mailbox_quota is not None:
|
||||||
|
@ -381,7 +381,7 @@ def user_info(auth, username):
|
||||||
if result:
|
if result:
|
||||||
user = result[0]
|
user = result[0]
|
||||||
else:
|
else:
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown'))
|
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown', user=username))
|
||||||
|
|
||||||
result_dict = {
|
result_dict = {
|
||||||
'username': user['uid'][0],
|
'username': user['uid'][0],
|
||||||
|
|
Loading…
Add table
Reference in a new issue