Merge branch 'stretch-unstable' into stdinfo

This commit is contained in:
Alexandre Aubin 2018-08-22 17:09:57 +00:00
commit efa9c9bd69
19 changed files with 366 additions and 55 deletions

View file

@ -11,7 +11,7 @@ prototype interfaces for your application.
Issues
------
- [Please report issues on YunoHost bugtracker](https://dev.yunohost.org/projects/yunohost/issues) (no registration needed).
- [Please report issues on YunoHost bugtracker](https://github.com/YunoHost/issues).
Overview
--------

92
debian/changelog vendored
View file

@ -1,3 +1,95 @@
moulinette (3.1.0) stable; urgency=low
* Fix datetime output formats (#163)
* Add the missing Info: prefix for info messages
* Rework a bit the way we handle async outputs (#166)
* Don't crash the moulinette if we fail to format a string (#168)
Thanks to all contributors : ljf, Bram, Aleks !
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 15 Aug 2018 21:44:00 +0000
moulinette (3.0.0) stable; urgency=low
Merging with Jessie's branches
Releasing as stable
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 17 Jun 2018 03:46:00 +0000
moulinette (3.0.0~beta1.1) testing; urgency=low
Merging with Jessie's branches
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 28 May 2018 02:55:00 +0000
moulinette (3.0.0~beta1) testing; urgency=low
Beta release for Stretch
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 03 May 2018 03:04:45 +0000
moulinette (2.7.14) stable; urgency=low
* Improve French, Occitan, Portuguese, Arabic translations
* Release as stable
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 17 Jun 2018 01:42:12 +0000
moulinette (2.7.13) testing; urgency=low
* [i18n] Improve translations for Portugueuse, Occitan
* [enh] Add read_yaml util (#161)
Contributors : Bram, by0ne, Quent-in
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 28 May 2018 02:55:00 +0000
moulinette (2.7.12) stable; urgency=low
* Bumping version number for stable release
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 06 May 2018 16:57:18 +0000
moulinette (2.7.11) testing; urgency=low
* [i18n] Improve translations for Arabic, Dutch, French, Occitan, Spanish
* [enh] Improve performances by lazy-loading some imports
* [enh] Log time needed to load a python module for an action
* [fix] Avoid cases where get_cookie returns None
* [mod] Improve exception logging in ldap stuff
Thanks to all contributors (pitchum, Bram, ButteflyOfFire, J. Keerl, Matthieu, Jibec, David B, Quenti, bjarkan) <3 !
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 01 May 2018 23:33:59 +0000
moulinette (2.7.7) stable; urgency=low
(Bumping version for stable release)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 18 Jan 2018 17:41:43 -0500
moulinette (2.7.6) testing; urgency=low
* [fix] Indicate where those damn logs files are
* [i18n] Improve Spanish and French translations
Thanks to all contributors (Bram, Jibec, David B.) ! <3
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 16 Jan 2018 17:12:19 -0500
moulinette (2.7.5) stable; urgency=low
(Bumping version for stable release)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 02 Dec 2017 12:26:43 -0500
moulinette (2.7.3) testing; urgency=low
* Optional expected status code for download_text/json (#153)
* Allow to give lock to multiple processes (#154)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 12 Oct 2017 16:09:27 -0400
moulinette (2.7.2) stable; urgency=low
* Revert hack for buildchain, found a proper solution

View file

@ -3,6 +3,7 @@ File system operation utils
.. autofunction:: moulinette.utils.filesystem.read_file
.. autofunction:: moulinette.utils.filesystem.read_json
.. autofunction:: moulinette.utils.filesystem.read_yaml
.. autofunction:: moulinette.utils.filesystem.write_to_file
.. autofunction:: moulinette.utils.filesystem.append_to_file
.. autofunction:: moulinette.utils.filesystem.write_to_json

54
locales/ar.json Normal file
View file

@ -0,0 +1,54 @@
{
"argument_required": "المُعامِل '{argument}' مطلوب",
"authentication_profile_required": "المصادقة مع الملف الشخصي '{profile}' مطلوبة",
"authentication_required": "المصادقة مطلوبة",
"authentication_required_long": "المصادقة مطلوبة قبل القيام بهذا الإجراء",
"colon": "{}: ",
"confirm": "تأكيد {prompt}",
"deprecated_command": "'{prog} {command}' تم التخلي عنه و سوف تتم إزالته مستقبلا",
"deprecated_command_alias": "'{prog} {old}' تم التخلي عنه و سوف يتم إزالته مستقبلا، إستخدم '{prog} {new}' بدلا من ذلك",
"error": "خطأ :",
"error_see_log": "طرأ هناك خطأ. يرجى الإطلاع على السجلات للمزيد مِن التفاصيل على المسار /var/log/yunohost/.",
"file_exists": "إنّ الملف موجود من قبل : '{path}'",
"file_not_exist": "الملف غير موجود : '{path}'",
"folder_exists": "إنّ المجلد موجود من قبل : '{path}'",
"folder_not_exist": "المجلد غير موجود",
"instance_already_running": "هناك نسخة خادوم تشتغل مِن قبل",
"invalid_argument": "المُعامِل غير صالح '{argument}': {error}",
"invalid_password": "كلمة السر خاطئة",
"invalid_usage": "إستعمال غير صالح، إستخدم --help لعرض المساعدة",
"ldap_attribute_already_exists": "الخاصية '{attribute}' موجودة مسبقا و تحمل القيمة '{value}'",
"ldap_operation_error": "طرأ هناك خطأ أثناء عملية في LDAP",
"ldap_server_down": "لا يمكن الإتصال بخادم LDAP",
"logged_in": "مُتّصل",
"logged_out": "تم تسجيل خروجك",
"not_logged_in": "لم تقم بعدُ بتسجيل دخولك",
"operation_interrupted": "تم توقيف العملية",
"password": "كلمة السر",
"pattern_not_match": "لا يتطابق مع النموذج",
"permission_denied": "رُفض التصريح",
"root_required": "يتوجب عليك أن تكون مدير الجذر root للقيام بهذا الإجراء",
"server_already_running": "هناك خادم يشتغل على ذاك المنفذ",
"success": "تم بنجاح !",
"unable_authenticate": "تعذرت المصادقة",
"unable_retrieve_session": "تعذرت مواصلة الجلسة",
"unknown_group": "الفريق '{group}' مجهول",
"unknown_user": "المستخدم '{user}' مجهول",
"values_mismatch": "القيمتين غير متطابقتين",
"warning": "تحذير :",
"websocket_request_expected": "كان ينتظر طلبًا عبر الويب سوكت WebSocket",
"cannot_open_file": "ليس بالإمكان فتح الملف {file:s} (السبب : {error:s})",
"cannot_write_file": "لا يمكن الكتابة في الملف {file:s} (السبب : {error:s})",
"unknown_error_reading_file": "طرأ هناك خطأ ما أثناء عملية قراءة الملف {file:s}",
"corrupted_json": "قراءة json مُشوّهة مِن {ressource:s} (السبب : {error:s})",
"error_writing_file": "طرأ هناك خطأ أثناء الكتابة في الملف {file:s}: {error:s}",
"error_removing": "خطأ أثناء عملية حذف {path:s}: {error:s}",
"error_changing_file_permissions": "خطأ أثناء عملية تعديل التصريحات لـ {path:s}: {error:s}",
"invalid_url": "خطأ في عنوان الرابط {url:s} (هل هذا الموقع موجود حقًا ؟)",
"download_ssl_error": "خطأ في الإتصال الآمن عبر الـ SSL أثناء محاولة الإتصال بـ {url:s}",
"download_timeout": "{url:s} استغرق مدة طويلة جدا للإستجابة، فتوقّف.",
"download_unknown_error": "خطأ أثناء عملية تنزيل البيانات مِن {url:s} : {error:s}",
"download_bad_status_code": "{url:s} أعاد رمز الحالة {code:s}",
"command_unknown": "الأمر '{command:s}' غير معروف ؟",
"corrupted_yaml": "قراءة مُشوّهة لنسق yaml مِن {ressource:s} (السبب : {error:s})"
}

View file

@ -8,11 +8,12 @@
"deprecated_command": "'{prog} {command}' is deprecated and will be removed in the future",
"deprecated_command_alias": "'{prog} {old}' is deprecated and will be removed in the future, use '{prog} {new}' instead",
"error": "Error:",
"error_see_log": "An error occurred. Please see the log for details.",
"error_see_log": "An error occurred. Please see the logs for details, they are located in /var/log/yunohost/.",
"file_exists": "File already exists: '{path}'",
"file_not_exist": "File does not exist: '{path}'",
"folder_exists": "Folder already exists: '{path}'",
"folder_not_exist": "Folder does not exist",
"info": "Info:",
"instance_already_running": "An instance is already running",
"invalid_argument": "Invalid argument '{argument}': {error}",
"invalid_password": "Invalid password",
@ -42,6 +43,7 @@
"cannot_write_file": "Could not write file {file:s} (reason: {error:s})",
"unknown_error_reading_file": "Unknown error while trying to read file {file:s}",
"corrupted_json": "Corrupted json read from {ressource:s} (reason: {error:s})",
"corrupted_yaml": "Corrupted yaml read from {ressource:s} (reason: {error:s})",
"error_writing_file": "Error when writing file {file:s}: {error:s}",
"error_removing": "Error when removing {path:s}: {error:s}",
"error_changing_file_permissions": "Error when changing permissions for {path:s}: {error:s}",

View file

@ -8,12 +8,12 @@
"deprecated_command": "'{prog} {command}' está obsoleto y será eliminado en el futuro",
"deprecated_command_alias": "'{prog} {old}' está obsoleto y se eliminará en el futuro, use '{prog} {new}' en su lugar",
"error": "Error:",
"error_see_log": "Ha ocurrido un error. Consulte el registro para obtener más información.",
"error_see_log": "Ha ocurrido un error. Consulte el registro para obtener más información, localizado en /var/log/yunohost/.",
"file_exists": "El archivo ya existe: '{path}'",
"file_not_exist": "El archivo no existe: '{path}'",
"folder_exists": "El directorio ya existe: '{path}'",
"folder_not_exist": "El directorio no existe",
"instance_already_running": "El programa ya se está ejecutando",
"instance_already_running": "Una instancia ya se está ejecutando",
"invalid_argument": "Argumento no válido '{argument}': {error}",
"invalid_password": "Contraseña no válida",
"invalid_usage": "Uso no válido, utilice --help para ver la ayuda",
@ -36,5 +36,18 @@
"unknown_user": "Usuario '{user}' desconocido",
"values_mismatch": "Los valores no coinciden",
"warning": "Advertencia:",
"websocket_request_expected": "Una petición de WebSocket prevista"
"websocket_request_expected": "Se esperaba una petición WebSocket",
"cannot_open_file": "No se pudo abrir el fichero{file:s} (motivo:{error:s})",
"cannot_write_file": "No se pudo escribir el fichero {file:s} (motivo: {error:s})",
"unknown_error_reading_file": "Error desconocido al intentar leer el fichero {file:s}",
"corrupted_json": "Json corrupto leido desde {ressource:s} (motivo: {error:s})",
"error_writing_file": "Error al escribir el fichero {file:s}: {error:s}",
"error_removing": "Error al eliminar {path:s}: {error:s}",
"error_changing_file_permissions": "Error al cambiar los permisos para {path:s}: {error:s}",
"invalid_url": "Url no válida {url:s} (¿existe este sitio web?)",
"download_ssl_error": "Error SSL al conectar con {url:s}",
"download_timeout": "{url:s} tardó demasiado en responder, me rindo.",
"download_unknown_error": "Error al descargar datos desde {url:s} : {error:s}",
"download_bad_status_code": "{url:s} devolvió el código de estado {code:s}",
"command_unknown": "Comando '{command:s}' desconocido ?"
}

View file

@ -1,14 +1,14 @@
{
"argument_required": "L'argument « {argument} » est requis",
"authentication_profile_required": "Authentification au profil « {profile} » requise",
"authentication_profile_required": "Lauthentification au profil « {profile} » requise",
"authentication_required": "Authentification requise",
"authentication_required_long": "L'authentification est requise pour exécuter cette action",
"authentication_required_long": "Lauthentification est requise pour exécuter cette action",
"colon": "{} : ",
"confirm": "Confirmez : {prompt}",
"deprecated_command": "« {prog} {command} » est déprécié et sera bientôt supprimé",
"deprecated_command_alias": "« {prog} {old} » est déprécié et sera bientôt supprimé, utilisez « {prog} {new} » à la place",
"error": "Erreur :",
"error_see_log": "Une erreur est survenue. Veuillez consulter les journaux pour plus de détails.",
"error_see_log": "Une erreur est survenue. Veuillez consulter les journaux pour plus de détails, ils sont situés en /var/log/yunohost/.",
"file_exists": "Le fichier existe déjà : « {path} »",
"file_not_exist": "Le fichier « {path} » n'existe pas",
"folder_exists": "Le dossier existe déjà : « {path} »",
@ -27,7 +27,7 @@
"password": "Mot de passe",
"pattern_not_match": "Ne correspond pas au motif",
"permission_denied": "Permission refusée",
"root_required": "Vous devez avoir les droits super-utilisateur pour exécuter cette action",
"root_required": "Vous devez être super-utilisateur pour exécuter cette action",
"server_already_running": "Un serveur est déjà en cours d'exécution sur ce port",
"success": "Succès !",
"unable_authenticate": "Impossible de vous authentifier",
@ -49,5 +49,6 @@
"download_timeout": "{url:s} a pris trop de temps pour répondre, abandon.",
"download_unknown_error": "Erreur lors du téléchargement des données à partir de {url:s}:{error:s}",
"download_bad_status_code": "{url:s} code de statut renvoyé {code:s}",
"command_unknown": "Commande {command:s} inconnue ?"
"command_unknown": "Commande '{command:s}' inconnue ?",
"corrupted_yaml": "YAML corrompu lu {ressource:s} depuis (cause : {error:s})"
}

View file

@ -1,21 +1,21 @@
{
"argument_required": "Argument {argument} is vereist",
"authentication_profile_required": "Authenticatie tot profiel '{profile}' is vereist",
"authentication_required": "Authenticatie vereist",
"authentication_required_long": "Authenticatie is vereist om deze actie uit te voeren",
"authentication_required": "Aanmelding vereist",
"authentication_required_long": "Aanmelding is vereist om deze actie uit te voeren",
"colon": "{}: ",
"confirm": "Bevestig {prompt}",
"error": "Fout:",
"error_see_log": "Er is een fout opgetreden, zie logboek voor meer informatie.",
"file_exists": "Kan '{path}' niet aanmaken: Bestand bestaat al",
"error_see_log": "Er is een fout opgetreden, zie logboek voor meer informatie. Je kan deze vinden in /var/log/yunohost/.",
"file_exists": "Kan '{path}' niet aanmaken: bestand bestaat al",
"file_not_exist": "Bestand bestaat niet: '{path}'",
"folder_exists": "kan map {path} niet aanmaken: Bestand bestaat al",
"folder_exists": "Deze map bestaat al: '{path}'",
"folder_not_exist": "Map bestaat niet",
"instance_already_running": "Er is al een instantie aan het draaien",
"invalid_argument": "Onjuist argument '{argument}': {error}",
"instance_already_running": "Er is al een instantie actief",
"invalid_argument": "Ongeldig argument '{argument}': {error}",
"invalid_password": "Ongeldig wachtwoord",
"invalid_usage": "Geef 'pass --help' in voor meer informatie",
"ldap_attribute_already_exists": "Attribuut bestaat al: '{attribute}={value}'",
"invalid_usage": "Ongeldig gebruik, doe --help om de hulptekst te lezen",
"ldap_attribute_already_exists": "Attribuut '{attribute}' bestaat al met waarde '{value}'",
"ldap_operation_error": "Er is een fout opgetreden bij het uitvoeren van LDAP operatie",
"ldap_server_down": "Kan LDAP server niet bereiken",
"logged_in": "Ingelogd",
@ -26,7 +26,7 @@
"pattern_not_match": "Past niet in het patroon",
"permission_denied": "Toegang geweigerd",
"root_required": "Je moet root zijn om deze actie uit te voeren",
"server_already_running": "Er is al een server aktief op die poort",
"server_already_running": "Er is al een server actief op die poort",
"success": "Succes!",
"unable_authenticate": "Aanmelding niet mogelijk",
"unable_retrieve_session": "Kan de sessie niet ophalen",
@ -34,7 +34,20 @@
"warning": "Waarschuwing:",
"websocket_request_expected": "Verwachtte een WebSocket request",
"deprecated_command": "'{prog} {command}' is verouderd en wordt binnenkort verwijderd",
"deprecated_command_alias": "'{prog} {old}' is verouderd en wordt binnenkort verwijderd, gebruik '{prog} {new}' in plaats daarvan",
"deprecated_command_alias": "'{prog} {old}' is verouderd en wordt binnenkort verwijderd, gebruik in de plaats '{prog} {new}'",
"unknown_group": "Groep '{group}' is onbekend",
"unknown_user": "Gebruiker '{user}' is onbekend"
"unknown_user": "Gebruiker '{user}' is onbekend",
"cannot_open_file": "Niet mogelijk om bestand {file:s} te openen (reden: {error:s})",
"cannot_write_file": "Niet gelukt om bestand {file:s} te schrijven (reden: {error:s})",
"unknown_error_reading_file": "Ongekende fout tijdens het lezen van bestand {file:s}",
"corrupted_json": "Corrupte json gelezen van {ressource:s} (reden: {error:s})",
"error_writing_file": "Fout tijdens het schrijven van bestand {file:s}: {error:s}",
"error_removing": "Fout tijdens het verwijderen van {path:s}: {error:s}",
"error_changing_file_permissions": "Fout tijdens het veranderen van machtiging voor {path:s}: {error:s}",
"invalid_url": "Ongeldige URL {url:s} (bestaat deze website?)",
"download_ssl_error": "SSL fout gedurende verbinding met {url:s}",
"download_timeout": "{url:s} neemt te veel tijd om te antwoorden, we geven het op.",
"download_unknown_error": "Fout tijdens het downloaden van data van {url:s}: {error:s}",
"download_bad_status_code": "{url:s} stuurt status code {code:s}",
"command_unknown": "Opdracht '{command:s}' ongekend ?"
}

54
locales/oc.json Normal file
View file

@ -0,0 +1,54 @@
{
"argument_required": "Largument {argument} es requesit",
"authentication_profile_required": "Lidentificacion del perfil {profile} es requesida",
"authentication_required": "Autentificacion requesida",
"authentication_required_long": "Una autentificacion es requesida per acomplir aquesta accion",
"logged_in": "Connectat",
"logged_out": "Desconnectat",
"password": "Senhal",
"colon": "{}: ",
"confirm": "Confirmatz: {prompt}",
"deprecated_command": "« {prog} {command} » es despreciat e serà lèu suprimit",
"deprecated_command_alias": "« {prog} {old} » es despreciat e serà lèu suprimit, utilizatz « {prog} {new} » allòc",
"error": "Error:",
"error_see_log": "Una error ses producha. Mercés de consultar los jornals per mai detalhs, son plaçats dins /var/log/yunohost/.",
"file_exists": "Lo fichièr existís ja: « {path} »",
"file_not_exist": "Lo fichièr « {path} » existís pas",
"folder_exists": "Lo repertòri existís ja: « {path} »",
"folder_not_exist": "Lo repertòri existís pas",
"instance_already_running": "Una instància es ja en execucion",
"invalid_argument": "Argument « {argument} » incorrècte: {error}",
"invalid_password": "Senhal incorrècte",
"ldap_server_down": "Impossible daténher lo servidor LDAP",
"not_logged_in": "Cap de session començada",
"pattern_not_match": "Correspond pas al patron",
"permission_denied": "Permission refusada",
"root_required": "Cal èsser root per realizar aquesta accion",
"unable_retrieve_session": "Impossible de recuperar la session",
"unknown_group": "Grop « {group} » desconegut",
"unknown_user": "Utilizaire « {user} » desconegut",
"values_mismatch": "Las valors correspondon pas",
"warning": "Atencion:",
"invalid_usage": "Usatge invalid, utilizatz --help per accedir a lajuda",
"ldap_attribute_already_exists": "Latribut « {attribute} » existís ja amb la valor: {value}",
"ldap_operation_error": "Una error ses producha pendent loperacion LDAP",
"operation_interrupted": "Operacion interrompuda",
"server_already_running": "Un servidor es ja en execucion sus aqueste pòrt",
"success": "Capitada!",
"unable_authenticate": "Impossible de vos autentificar",
"websocket_request_expected": "Una requèsta WebSocket èra esperada",
"cannot_open_file": "Impossible de dobrir lo fichièr {file:s} (rason: {error:s})",
"cannot_write_file": "Escritura impossibla del fichièr {file:s} (rason: {error:s})",
"unknown_error_reading_file": "Error desconeguda en ensajar de legir lo fichièr {file:s}",
"error_writing_file": "Error en escriure lo fichièr {file:s}: {error:s}",
"error_removing": "Error en suprimir {path:s}: {error:s}",
"error_changing_file_permissions": "Error en modificar las permissions per {path:s}: {error:s}",
"invalid_url": "Url invalida {url:s} (existís aqueste site?)",
"download_ssl_error": "Error SSL en se connectant a {url:s}",
"download_timeout": "{url:s} a trigat per respondre, avèm quitat desperar.",
"download_unknown_error": "Error en telecargar de donadas de {url:s}: {error:s}",
"download_bad_status_code": "{url:s} tòrna lo còdi destat {code:s}",
"command_unknown": "Comanda {command:s} desconeguda?",
"corrupted_json": "Fichièr Json corromput legit de {ressource:s} (rason: {error:s})",
"corrupted_yaml": "Fichièr YAML corromput legit de {ressource:s} (rason: {error:s})"
}

View file

@ -34,7 +34,21 @@
"websocket_request_expected": "Esperado um pedido a WebSocket",
"deprecated_command": "'{prog} {command}' está obsoleto e será removido no futuro",
"deprecated_command_alias": "'{prog} {old}' está obsoleto e será removido no futuro, em vez disso, usa '{prog} {new}'",
"error_see_log": "Um erro ocorreu. Por favor, veja mais detalhes no log.",
"error_see_log": "Ocorreu um erro . Por favor, veja os logs para maiores detalhes, eles estão localizados em /var/log/yunohost/.",
"unknown_group": "Grupo '{group}' desconhecido",
"unknown_user": "Nome de utilizador '{user}' desconhecido"
"unknown_user": "Nome de utilizador '{user}' desconhecido",
"cannot_open_file": "Não foi possível abrir o arquivo {file:s} (reason: {error:s})",
"cannot_write_file": "Não foi possível abrir o arquivo {file:s} (reason: {error:s})",
"unknown_error_reading_file": "Erro desconhecido ao tentar ler o arquivo {file:s}",
"error_writing_file": "Erro ao gravar arquivo {file:s}: {error:s}",
"error_removing": "Erro ao remover {path:s}: {error:s}",
"error_changing_file_permissions": "Erro ao alterar as permissões para {path:s}: {error:s}",
"invalid_url": "URL inválida {url:s} (does this site exists ?)",
"download_ssl_error": "Erro de SSL ao conectar-se a {url:s}",
"download_timeout": "{url:s} demorou muito para responder, desistiu.",
"download_unknown_error": "Erro quando baixando os dados de {url:s} : {error:s}",
"download_bad_status_code": "{url:s} retornou o código de status {code:s}",
"command_unknown": "Comando '{command:s}' desconhecido ?",
"corrupted_json": "Json corrompido lido do {ressource:s} (motivo: {error:s})",
"corrupted_yaml": "Yaml corrompido lido do {ressource:s} (motivo: {error:s})"
}

View file

@ -391,7 +391,7 @@ class ActionsMap(object):
with open(actionsmap_pkl) as f:
actionsmaps[n] = pickle.load(f)
# TODO: Switch to python3 and catch proper exception
except IOError:
except (IOError, EOFError):
self.use_cache = False
actionsmaps = self.generate_cache(namespaces)
elif use_cache: # cached file doesn't exists
@ -469,10 +469,13 @@ class ActionsMap(object):
# Lock the moulinette for the namespace
with MoulinetteLock(namespace, timeout):
start = time()
try:
mod = __import__('%s.%s' % (namespace, category),
globals=globals(), level=0,
fromlist=[func_name])
logger.debug('loading python module %s took %.3fs',
'%s.%s' % (namespace, category), time() - start)
func = getattr(mod, func_name)
except (AttributeError, ImportError):
logger.exception("unable to load function %s.%s",
@ -495,7 +498,7 @@ class ActionsMap(object):
return func(**arguments)
finally:
stop = time()
logger.debug('action [%s] ended after %.3fs',
logger.debug('action [%s] executed in %.3fs',
log_id, stop - start)
@staticmethod

View file

@ -62,7 +62,8 @@ class Authenticator(BaseAuthenticator):
try:
# Retrieve identity
who = self.con.whoami_s()
except:
except Exception as e:
logger.warning("Error during ldap authentication process: %s", e)
return False
else:
if who[3:] == self.userdn:
@ -131,9 +132,9 @@ class Authenticator(BaseAuthenticator):
try:
result = self.con.search_s(base, ldap.SCOPE_SUBTREE, filter, attrs)
except:
except Exception as e:
logger.exception("error during LDAP search operation with: base='%s', "
"filter='%s', attrs=%s", base, filter, attrs)
"filter='%s', attrs=%s and exception %s", base, filter, attrs, e)
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
result_list = []
@ -162,9 +163,9 @@ class Authenticator(BaseAuthenticator):
try:
self.con.add_s(dn, ldif)
except:
except Exception as e:
logger.exception("error during LDAP add operation with: rdn='%s', "
"attr_dict=%s", rdn, attr_dict)
"attr_dict=%s and exception %s", rdn, attr_dict, e)
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
else:
return True
@ -183,8 +184,8 @@ class Authenticator(BaseAuthenticator):
dn = rdn + ',' + self.basedn
try:
self.con.delete_s(dn)
except:
logger.exception("error during LDAP delete operation with: rdn='%s'", rdn)
except Exception as e:
logger.exception("error during LDAP delete operation with: rdn='%s' and exception %s", rdn, e)
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
else:
return True
@ -212,9 +213,10 @@ class Authenticator(BaseAuthenticator):
dn = new_rdn + ',' + self.basedn
self.con.modify_ext_s(dn, ldif)
except:
except Exception as e:
logger.exception("error during LDAP update operation with: rdn='%s', "
"attr_dict=%s, new_rdn=%s", rdn, attr_dict, new_rdn)
"attr_dict=%s, new_rdn=%s and exception: %s", rdn, attr_dict,
new_rdn, e)
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
else:
return True

View file

@ -88,14 +88,23 @@ class Translator(object):
- key -- The key to translate
"""
failed_to_format = False
if key in self._translations.get(self.locale, {}):
return self._translations[self.locale][key].encode('utf-8').format(*args, **kwargs)
try:
return self._translations[self.locale][key].encode('utf-8').format(*args, **kwargs)
except KeyError as e:
logger.exception("Failed to format translated string '%s' with error: %s" % (key, e))
failed_to_format = True
if self.default_locale != self.locale and key in self._translations.get(self.default_locale, {}):
if failed_to_format or (self.default_locale != self.locale and key in self._translations.get(self.default_locale, {})):
logger.info("untranslated key '%s' for locale '%s'",
key, self.locale)
return self._translations[self.default_locale][key].encode('utf-8').format(*args, **kwargs)
try:
return self._translations[self.default_locale][key].encode('utf-8').format(*args, **kwargs)
except KeyError as e:
logger.exception("Failed to format translatable string '%s' with error: %s" % (key, e))
return self._translations[self.locale][key].encode('utf-8')
logger.exception("unable to retrieve key '%s' for default locale '%s'",
key, self.default_locale)
@ -500,7 +509,7 @@ class MoulinetteLock(object):
lock_pids = f.read().strip().split('\n')
# Make sure to convert those pids to integers
lock_pids = [ int(pid) for pid in lock_pids ]
lock_pids = [int(pid) for pid in lock_pids if pid.strip() != '']
return lock_pids

View file

@ -438,7 +438,7 @@ class _ActionsMapPlugin(object):
try:
s_secret = self.secrets[s_id]
s_hash = request.get_cookie('session.hashes',
secret=s_secret)[authenticator.name]
secret=s_secret, default={})[authenticator.name]
except KeyError:
if authenticator.name == 'default':
msg = m18n.g('authentication_required')

View file

@ -1,4 +1,5 @@
import os
import yaml
import errno
import shutil
import json
@ -64,6 +65,28 @@ def read_json(file_path):
return loaded_json
def read_yaml(file_path):
"""
Safely read a yaml file
Keyword argument:
file_path -- Path to the yaml file
"""
# Read file
file_content = read_file(file_path)
# Try to load yaml to check if it's syntaxically correct
try:
loaded_yaml = yaml.safe_load(file_content)
except ValueError as e:
raise MoulinetteError(errno.EINVAL,
m18n.g('corrupted_yaml',
ressource=file_path, error=str(e)))
return loaded_yaml
def write_to_file(file_path, data, file_mode="w"):
"""
Write a single string or a list of string to a text file.

View file

@ -1,5 +1,4 @@
import errno
import requests
import json
from moulinette import m18n
@ -17,6 +16,7 @@ def download_text(url, timeout=30, expected_status_code=200):
expected_status_code -- Status code expected from the request. Can be
None to ignore the status code.
"""
import requests # lazy loading this module for performance reasons
# Assumptions
assert isinstance(url, str)

View file

@ -95,22 +95,33 @@ def call_async_output(args, callback, **kwargs):
if stdinfo:
stdinfo_reader, stdinfo_consum = async_file_reading(stdinfo_f, callback[2])
while not stdout_reader.eof() or not stderr_reader.eof():
while not stdout_reader.eof() and not stderr_reader.eof():
while not stdout_consum.empty() or not stderr_consum.empty():
# alternate between the 2 consumers to avoid desynchronisation
# this way is not 100% perfect but should do it
stdout_consum.process_next_line()
stderr_consum.process_next_line()
stdinfo_consum.process_next_line()
time.sleep(.1)
stderr_reader.join()
stderr_consum.join()
# clear the queues
stdout_consum.process_current_queue()
stderr_consum.process_current_queue()
stdinfo_consum.process_current_queue()
else:
while not stdout_reader.eof():
stdout_consum.process_current_queue()
time.sleep(.1)
stdout_reader.join()
stdout_consum.join()
# clear the queue
stdout_consum.process_current_queue()
if stdinfo:
# Remove the stdinfo pipe
os.remove(stdinfo)
os.rmdir(os.path.dirname(stdinfo))
stdinfo_reader.join()
stdinfo_consum.join()
stdinfo_consum.process_current_queue()
# on slow hardware, in very edgy situations it is possible that the process
# isn't finished just after having closed stdout and stderr, so we wait a

View file

@ -1,5 +1,6 @@
import logging
from json.encoder import JSONEncoder
import datetime
logger = logging.getLogger('moulinette.utils.serialize')
@ -24,6 +25,10 @@ class JSONExtendedEncoder(JSONEncoder):
hasattr(o, '__iter__') and hasattr(o, 'next')):
return list(o)
# Display the date in its iso format ISO-8601 Internet Profile (RFC 3339)
if isinstance(o, datetime.datetime) or isinstance(o, datetime.date):
return o.isoformat()
# Return the repr for object that json can't encode
logger.warning('cannot properly encode in JSON the object %s, '
'returned repr is: %r', type(o), o)

View file

@ -73,14 +73,29 @@ class AsynchronousFileReader(Process):
Process.join(self, timeout)
def consume_queue(queue, callback):
"""Consume the queue and give content to the callback."""
while True:
line = queue.get()
if line:
if line == StopIteration:
break
callback(line)
class Consummer(object):
def __init__(self, queue, callback):
self.queue = queue
self.callback = callback
def empty(self):
return self.queue.empty()
def process_next_line(self):
if not self.empty():
line = self.queue.get()
if line:
if line == StopIteration:
return
self.callback(line)
def process_current_queue(self):
while not self.empty():
line = self.queue.get()
if line:
if line == StopIteration:
break
self.callback(line)
def async_file_reading(fd, callback):
@ -88,6 +103,5 @@ def async_file_reading(fd, callback):
queue = SimpleQueue()
reader = AsynchronousFileReader(fd, queue)
reader.start()
consummer = Process(target=consume_queue, args=(queue, callback))
consummer.start()
consummer = Consummer(queue, callback)
return (reader, consummer)