From 81dccca288969ab1aee5c1853c1398123f92635d Mon Sep 17 00:00:00 2001 From: kload Date: Fri, 18 Oct 2013 13:48:01 +0000 Subject: [PATCH] App system hooks --- action_map.yml | 12 +++++ yunohost.tac | 4 +- yunohost_app.py | 115 +++++++++++++++++++---------------------------- yunohost_hook.py | 11 ++--- 4 files changed, 65 insertions(+), 77 deletions(-) diff --git a/action_map.yml b/action_map.yml index 907540e6..60d7773c 100644 --- a/action_map.yml +++ b/action_map.yml @@ -332,6 +332,18 @@ app: help: Return the full app_dict action: store_true + ### app_setting() + addaccess: + action_help: Set ou get an app setting value + api: GET /app/{app}/setting + arguments: + app: + help: App ID + key: + help: Key to get/set + -v: + full: --value + help: Value to set ### app_addaccess() TODO: Write help addaccess: diff --git a/yunohost.tac b/yunohost.tac index df42b738..324f6f31 100755 --- a/yunohost.tac +++ b/yunohost.tac @@ -24,8 +24,8 @@ gettext.install('YunoHost') dev = False installed = True -ssl_key = '/usr/share/yunohost/yunohost-config/ssl/yunoCA/certs/yunohost_key.pem' -ssl_crt = '/usr/share/yunohost/yunohost-config/ssl/yunoCA/newcerts/02.pem' +ssl_key = '/etc/ssl/private/yunohost_key.pem' +ssl_crt = '/etc/ssl/certs/yunohost_crt.pem' action_dict = {} api = APIResource() diff --git a/yunohost_app.py b/yunohost_app.py index d070be26..7343c397 100644 --- a/yunohost_app.py +++ b/yunohost_app.py @@ -33,6 +33,7 @@ import time from yunohost import YunoHostError, YunoHostLDAP, win_msg, random_password, is_true from yunohost_domain import domain_list, domain_add from yunohost_user import user_info +from yunohost_hook import hook_exec repo_path = '/var/cache/yunohost/repo' apps_path = '/usr/share/yunohost/apps' @@ -249,7 +250,7 @@ def app_upgrade(app, url=None, file=None): raise YunoHostError(1, app_id + _(" is not installed")) if app_id in upgraded_apps: - raise YunoHostError(1, _("Conflict, multiple upgrades of the same app: ")+ app_id +' (instance n°'+ number +')') + continue #TODO: fix that (and check for instance number) current_app_dict = app_info(app_id, instance=number, raw=True) @@ -264,22 +265,17 @@ def app_upgrade(app, url=None, file=None): else: continue - - # Execute App upgrade script - #TODO: display fail messages from script - _exec_app_script(step='upgrade', path=app_tmp_folder +'/scripts', var_dict={}, parameters=manifest['parameters']) - - - # Write App settings app_setting_path = apps_setting_path +'/'+ app_id - current_app_dict['settings']['update_time'] = int(time.time()) + # Execute App upgrade script + if hook_exec(app_setting_path+ '/scripts/upgrade') != 0: + #TODO: display fail messages from script + pass + else: + app_setting(app_id, 'update_time', int(time.time()) - with open(app_setting_path +'/settings.yml', 'w') as f: - yaml.safe_dump(current_app_dict['settings'], f, default_flow_style=False) - win_msg(_("App setting file updated")) - - os.system('mv "'+ app_tmp_folder +'/*" '+ app_setting_path) + # Move scripts and manifest to the right place + os.system('mv "'+ app_tmp_folder +'/manifest.json" "'+ app_tmp_folder +'/scripts" '+ app_setting_path) # So much win upgraded_apps.append(app_id) @@ -302,11 +298,9 @@ def app_install(app, label=None): """ #TODO: Create tool for ssowat #TODO: Create tool for nginx (check path availability & stuff) - #TODO: Create tool for MySQL DB ? with YunoHostLDAP() as yldap: - # Fetch or extract sources try: os.listdir(install_tmp) except OSError: os.makedirs(install_tmp) @@ -350,23 +344,20 @@ def app_install(app, label=None): if os.path.exists(app_setting_path): shutil.rmtree(app_setting_path) os.makedirs(app_setting_path) - yaml_dict = { - 'id': app_id, - 'install_time': int(time.time()) - } + os.system('touch '+ app_setting_path +'/settings.yml') + app_setting(app_id, 'id', app_id) + app_setting(app_id, 'install_time', int(time.time())) - if label: yaml_dict['label'] = label - else: yaml_dict['label'] = manifest['name'] + if label: + app_setting(app_id, 'label', label) + else: + app_setting(app_id, 'label', manifest['name']) - # Write App settings - with open(app_setting_path +'/settings.yml', 'w') as f: - yaml.safe_dump(yaml_dict, f, default_flow_style=False) - win_msg(_("App setting file created")) - - os.system('mv "'+ app_final_path +'/manifest.json" "'+ app_final_path +'/scripts" '+ app_setting_path) + # Move scripts and manifest to the right place + os.system('mv "'+ app_tmp_folder +'/manifest.json" "'+ app_tmp_folder +'/scripts" '+ app_setting_path) # Execute App install script - if _exec_app_script(step='install', path=app_tmp_folder +'/scripts', var_dict={}, parameters=manifest['parameters']) != 0: + if hook_exec(app_setting_path+ '/scripts/install') != 0: #TODO: display script fail messages shutil.rmtree(app_setting_path) @@ -385,13 +376,9 @@ def app_remove(app): if not _is_installed(app): raise YunoHostError(22, _("App is not installed")) - app_final_path = apps_path +'/'+ app - app_dict = app_info(app, raw=True) - app_settings = app_dict['settings'] - manifest = app_dict['manifest'] - #TODO: display fail messages from script - _exec_app_script(step='remove', path=app_tmp_folder +'/scripts', var_dict=script_var_dict, parameters=manifest['parameters']) + if hook_exec(apps_setting_path +'/'+ app + '/scripts/remove') != 0: + pass win_msg(_("App removed: ")+ app) @@ -474,6 +461,29 @@ def app_removeaccess(apps, users): #TODO: Regenerate SSOwat conf +def app_setting(app, key, value=None): + """ + + """ + settings_file = apps_setting_path + app +'/settings.yml' + + with open(settings_file) as f: + app_settings = yaml.load(f) + + if value is not None: + if value == '' and key in app_settings: + del app_settings[key] + else: + app_settings[key] = value + elif key in app_settings: + return app_settings[key] + + with open(settings_file, 'w') as f: + yaml.safe_dump(app_settings, f, default_flow_style=False) + + return True + + def _extract_app_from_file(path): """ Unzip or untar application tarball in app_tmp_folder, or copy it from a directory @@ -562,41 +572,6 @@ def _fetch_app_from_git(app): return manifest -def _exec_app_script(step, path, var_dict, parameters): - """ - Execute step user script - - Keyword arguments: - step -- Name of the script to call regarding the current step (e.g. install|upgrade|remove|etc.) - path -- Absolute path of the script's directory - var_dict -- Dictionnary of environnement variable to pass to the script - parameters -- Parameters to pass to the script - - """ - scripts = [ step, step +'.sh', step +'.py' ] - - for script in scripts: - script_path = path +'/'+ script - if os.path.exists(script_path): - st = os.stat(script_path) - os.chmod(script_path, st.st_mode | stat.S_IEXEC) - - user = 'yunohost' - os.system('chown -R '+ user +': '+ app_tmp_folder) - - env_vars = '' - for key, value in var_dict.items(): - env_vars = env_vars + key + "='"+ value +"' " - - command = 'su - '+ user +' -c "'+ env_vars +' sh '+ path +'/'+ script +'"' - if os.system(command) == 0: - win_msg(_("Script executed: ") + script) - else: - raise YunoHostError(1, _("Script execution failed: ") + script) - - break - - def _installed_instance_number(app, last=False): """ Check if application is installed and return instance number diff --git a/yunohost_hook.py b/yunohost_hook.py index f73aaec4..77f4e72a 100644 --- a/yunohost_hook.py +++ b/yunohost_hook.py @@ -54,11 +54,12 @@ def hook_callback(action): action -- Action name """ - try: os.listdir(hook_folder + action) - except OSError: os.makedirs(hook_folder + action) + with YunoHostLDAP() as yldap: + try: os.listdir(hook_folder + action) + except OSError: os.makedirs(hook_folder + action) - for hook in os.listdir(hook_folder + action): - hook_exec(file=hook_folder + action +'/'+ hook) + for hook in os.listdir(hook_folder + action): + hook_exec(file=hook_folder + action +'/'+ hook) def hook_check(file): @@ -116,4 +117,4 @@ def hook_exec(file, args=None): else: raise YunoHostError(22, _("Missing arguments") + ': ' + arg_name) - os.system('su - admin -c "bash \\"'+ file +'\\" '+ ' '.join(arg_list) +'"') + return os.system('su - admin -c "bash \\"'+ file +'\\" '+ ' '.join(arg_list) +'"') #TODO: Allow python script