[enh] Adapt yunohost_hook.py and allow bypass of the locking process

This commit is contained in:
kload 2014-04-24 11:35:18 +00:00
parent 18eb0f9406
commit 962b78329f
6 changed files with 98 additions and 56 deletions

View file

@ -50,6 +50,7 @@ _global:
uri: ldap://localhost:389 uri: ldap://localhost:389
base_dn: dc=yunohost,dc=org base_dn: dc=yunohost,dc=org
argument_auth: true argument_auth: true
lock: true
arguments: arguments:
-v: -v:
full: --version full: --version
@ -70,6 +71,7 @@ user:
api: GET /users api: GET /users
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
--fields: --fields:
help: fields to fetch help: fields to fetch
@ -183,6 +185,7 @@ user:
api: 'GET /users/<username>' api: 'GET /users/<username>'
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
username: username:
help: Username or mail to get informations help: Username or mail to get informations
@ -201,6 +204,7 @@ domain:
api: GET /domains api: GET /domains
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
-f: -f:
full: --filter full: --filter
@ -361,6 +365,8 @@ app:
api: POST /app api: POST /app
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
lock: false
arguments: arguments:
app: app:
help: App to install help: App to install
@ -375,6 +381,9 @@ app:
remove: remove:
action_help: Remove app action_help: Remove app
api: DELETE /app api: DELETE /app
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App(s) to delete help: App(s) to delete
@ -383,6 +392,9 @@ app:
upgrade: upgrade:
action_help: Upgrade app action_help: Upgrade app
api: PUT /app api: PUT /app
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App(s) to upgrade (default all) help: App(s) to upgrade (default all)
@ -450,6 +462,7 @@ app:
api: GET /app/checkurl api: GET /app/checkurl
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
url: url:
help: Url to check help: Url to check
@ -480,6 +493,7 @@ app:
api: PUT /ssowatconf api: PUT /ssowatconf
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
### app_addaccess() TODO: Write help ### app_addaccess() TODO: Write help
addaccess: addaccess:
@ -487,6 +501,7 @@ app:
api: PUT /app/access api: PUT /app/access
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
apps: apps:
nargs: "+" nargs: "+"
@ -500,6 +515,7 @@ app:
api: DELETE /app/access api: DELETE /app/access
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
apps: apps:
nargs: "+" nargs: "+"
@ -513,6 +529,7 @@ app:
api: POST /app/access api: POST /app/access
configuration: configuration:
authenticate: all authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
apps: apps:
nargs: "+" nargs: "+"

View file

@ -23,15 +23,13 @@
Manage hooks Manage hooks
""" """
import logging
logging.warning('the module yunohost.hook has not been revisited and updated yet')
import os import os
import sys import sys
import re import re
import json import json
from moulinette.helpers import YunoHostError, YunoHostLDAP, win_msg, colorize from moulinette.helpers import colorize
from moulinette.core import MoulinetteError
hook_folder = '/usr/share/yunohost/hooks/' hook_folder = '/usr/share/yunohost/hooks/'
@ -56,8 +54,8 @@ def hook_add(app, file):
finalpath = hook_folder + action +'/'+ priority +'-'+ app finalpath = hook_folder + action +'/'+ priority +'-'+ app
print app print app
os.system('cp '+ file +' '+ finalpath) os.system('cp %s %s' % (file, finalpath))
os.system('chown -hR admin: '+ hook_folder) os.system('chown -hR admin: %s' % hook_folder)
return { 'hook': finalpath } return { 'hook': finalpath }
@ -87,19 +85,18 @@ def hook_callback(action, args=None):
args -- Ordered list of arguments to pass to the script args -- Ordered list of arguments to pass to the script
""" """
with YunoHostLDAP() as yldap: try: os.listdir(hook_folder + action)
try: os.listdir(hook_folder + action) except OSError: pass
except OSError: pass else:
else: if args is None:
if args is None: args = []
args = [] elif not isinstance(args, list):
elif not isinstance(args, list): args = [args]
args = [args]
for hook in os.listdir(hook_folder + action): for hook in os.listdir(hook_folder + action):
try: try:
hook_exec(file=hook_folder + action +'/'+ hook, args=args) hook_exec(file=hook_folder + action +'/'+ hook, args=args)
except: pass except: pass
def hook_check(file): def hook_check(file):
@ -114,7 +111,7 @@ def hook_check(file):
with open(file[:file.index('scripts/')] + 'manifest.json') as f: with open(file[:file.index('scripts/')] + 'manifest.json') as f:
manifest = json.loads(str(f.read())) manifest = json.loads(str(f.read()))
except: except:
raise YunoHostError(22, _("Invalid app package")) raise MoulinetteError(22, _("Invalid app package"))
action = file[file.index('scripts/') + 8:] action = file[file.index('scripts/') + 8:]
if 'arguments' in manifest and action in manifest['arguments']: if 'arguments' in manifest and action in manifest['arguments']:
@ -132,41 +129,41 @@ def hook_exec(file, args=None):
args -- Arguments to pass to the script args -- Arguments to pass to the script
""" """
with YunoHostLDAP() as yldap: if isinstance(args, list):
if isinstance(args, list): arg_list = args
arg_list = args else:
else: required_args = hook_check(file)
required_args = hook_check(file) if args is None:
if args is None: args = {}
args = {}
arg_list = [] arg_list = []
for arg in required_args: for arg in required_args:
if arg['name'] in args: if arg['name'] in args:
if 'choices' in arg and args[arg['name']] not in arg['choices']: if 'choices' in arg and args[arg['name']] not in arg['choices']:
raise YunoHostError(22, _("Invalid choice") + ': ' + args[arg['name']]) raise MoulinetteError(22, _("Invalid choice") + ': ' + args[arg['name']])
arg_list.append(args[arg['name']]) arg_list.append(args[arg['name']])
else:
if os.isatty(1) and 'ask' in arg:
ask_string = arg['ask']['en'] #TODO: I18n
if 'choices' in arg:
ask_string = ask_string +' ('+ '|'.join(arg['choices']) +')'
if 'default' in arg:
ask_string = ask_string +' (default: '+ arg['default'] +')'
input_string = raw_input(colorize(ask_string + ': ', 'cyan'))
if input_string == '' and 'default' in arg:
input_string = arg['default']
arg_list.append(input_string)
elif 'default' in arg:
arg_list.append(arg['default'])
else: else:
if os.isatty(1) and 'ask' in arg: raise MoulinetteError(22, _("Missing argument : %s") % arg['name'])
ask_string = arg['ask']['en'] #TODO: I18n
if 'choices' in arg:
ask_string = ask_string +' ('+ '|'.join(arg['choices']) +')'
if 'default' in arg:
ask_string = ask_string +' (default: '+ arg['default'] +')'
input_string = raw_input(colorize(ask_string + ': ', 'cyan')) file_path = "./"
if "/" in file and file[0:2] != file_path:
if input_string == '' and 'default' in arg: file_path = os.path.dirname(file)
input_string = arg['default'] file = file.replace(file_path +"/", "")
return os.system('su - admin -c "cd \\"%s\\" && bash \\"%s\\" %s"' % (file_path, file, ' '.join(arg_list)))
arg_list.append(input_string) #TODO: Allow python script
elif 'default' in arg:
arg_list.append(arg['default'])
else:
raise YunoHostError(22, _("Missing arguments") + ': ' + arg['name'])
file_path = "./"
if "/" in file and file[0:2] != file_path:
file_path = os.path.dirname(file)
file = file.replace(file_path +"/", "")
return os.system('su - admin -c "cd \\"'+ file_path +'\\" && bash \\"'+ file +'\\" '+ ' '.join(arg_list) +'"') #TODO: Allow python script

View file

@ -347,6 +347,7 @@ class MoulinetteLock(object):
self._lockfile = '/var/run/moulinette_%s.lock' % namespace self._lockfile = '/var/run/moulinette_%s.lock' % namespace
self._locked = False self._locked = False
self._bypass = False
def acquire(self): def acquire(self):
"""Attempt to acquire the lock for the moulinette instance """Attempt to acquire the lock for the moulinette instance
@ -359,9 +360,16 @@ class MoulinetteLock(object):
start_time = time.time() start_time = time.time()
while True: while True:
if 'BYPASS_LOCK' in os.environ and os.environ['BYPASS_LOCK'] == 'yes':
self._bypass = True
break
if not os.path.isfile(self._lockfile): if not os.path.isfile(self._lockfile):
# Create the lock file # Create the lock file
(open(self._lockfile, 'w')).close() try:
(open(self._lockfile, 'w')).close()
except IOError:
raise MoulinetteError(errno.EPERM, _("Permission denied, did you forget 'sudo' ?"))
break break
if (time.time() - start_time) > self.timeout: if (time.time() - start_time) > self.timeout:
@ -378,7 +386,8 @@ class MoulinetteLock(object):
""" """
if self._locked: if self._locked:
os.unlink(self._lockfile) if not self._bypass:
os.unlink(self._lockfile)
self._locked = False self._locked = False
def __enter__(self): def __enter__(self):

View file

@ -263,6 +263,17 @@ class BaseActionsMapParser(object):
# TODO: Log error instead and tell valid values # TODO: Log error instead and tell valid values
raise MoulinetteError(errno.EINVAL, "Invalid value '%r' for configuration 'argument_auth'" % arg_auth) raise MoulinetteError(errno.EINVAL, "Invalid value '%r' for configuration 'argument_auth'" % arg_auth)
# -- 'lock'
try:
lock = configuration['lock']
except KeyError:
pass
else:
if isinstance(lock, bool):
conf['lock'] = lock
else:
raise MoulinetteError(errno.EINVAL, "Invalid value '%r' for configuration 'lock'" % lock)
return conf return conf
def _format_conf(self, name, value): def _format_conf(self, name, value):

View file

@ -393,6 +393,10 @@ class ActionsMapParser(BaseActionsMapParser):
raise MoulinetteError(errno.EINVAL, "No parser found for route '%s'" % route) raise MoulinetteError(errno.EINVAL, "No parser found for route '%s'" % route)
ret = argparse.Namespace() ret = argparse.Namespace()
if not self.get_conf(tid, 'lock'):
os.environ['BYPASS_LOCK'] = 'yes'
# Perform authentication if needed # Perform authentication if needed
if self.get_conf(tid, 'authenticate'): if self.get_conf(tid, 'authenticate'):
auth_conf, klass = self.get_conf(tid, 'authenticator') auth_conf, klass = self.get_conf(tid, 'authenticator')

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import errno import errno
import getpass import getpass
import argparse import argparse
@ -126,6 +127,9 @@ class ActionsMapParser(BaseActionsMapParser):
def parse_args(self, args, **kwargs): def parse_args(self, args, **kwargs):
ret = self._parser.parse_args(args) ret = self._parser.parse_args(args)
if not self.get_conf(ret._tid, 'lock'):
os.environ['BYPASS_LOCK'] = 'yes'
# Perform authentication if needed # Perform authentication if needed
if self.get_conf(ret._tid, 'authenticate'): if self.get_conf(ret._tid, 'authenticate'):
auth_conf, klass = self.get_conf(ret._tid, 'authenticator') auth_conf, klass = self.get_conf(ret._tid, 'authenticator')