mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
[enh] Replace category by related_to fields
This commit is contained in:
parent
73828306df
commit
650b768229
6 changed files with 118 additions and 128 deletions
|
@ -1614,16 +1614,18 @@ log:
|
|||
action_help: List logs
|
||||
api: GET /logs
|
||||
arguments:
|
||||
-l:
|
||||
-l:
|
||||
full: --limit
|
||||
help: Maximum number of logs per categories
|
||||
help: Maximum number of logs
|
||||
type: int
|
||||
--full:
|
||||
help: Show more details
|
||||
action: store_true
|
||||
|
||||
### log_display()
|
||||
display:
|
||||
action_help: Display a log content
|
||||
api: GET /logs/<file_name_list>
|
||||
arguments:
|
||||
file_name_list:
|
||||
file_name:
|
||||
help: Log filenames for which to display the content
|
||||
nargs: "*"
|
||||
|
|
|
@ -424,7 +424,7 @@ def app_map(app=None, raw=False, user=None):
|
|||
return result
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def app_change_url(uo, auth, app, domain, path):
|
||||
"""
|
||||
Modify the URL at which an application is installed.
|
||||
|
@ -482,6 +482,8 @@ def app_change_url(uo, auth, app, domain, path):
|
|||
env_dict["YNH_APP_NEW_DOMAIN"] = domain
|
||||
env_dict["YNH_APP_NEW_PATH"] = path.rstrip("/")
|
||||
|
||||
if domain != old_domain:
|
||||
uo.related_to.append(('domain', old_domain))
|
||||
uo.extra.update({'env': env_dict})
|
||||
uo.start()
|
||||
|
||||
|
@ -619,7 +621,8 @@ def app_upgrade(auth, app=[], url=None, file=None):
|
|||
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
|
||||
|
||||
# Start register change on system
|
||||
uo = UnitOperation('app_upgrade', 'app', app_instance_name, env=env_dict)
|
||||
related_to = [('app', app_instance_name)]
|
||||
uo = UnitOperation('app_upgrade', related_to, env=env_dict)
|
||||
|
||||
# Execute App upgrade script
|
||||
os.system('chown -hR admin: %s' % INSTALL_TMP)
|
||||
|
@ -669,7 +672,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
|
|||
return {"log": service_log('yunohost-api', number="100").values()[0]}
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def app_install(uo, auth, app, label=None, args=None, no_remove_on_failure=False):
|
||||
"""
|
||||
Install apps
|
||||
|
@ -794,7 +797,7 @@ def app_install(uo, auth, app, label=None, args=None, no_remove_on_failure=False
|
|||
|
||||
# Execute remove script
|
||||
uo_remove = UnitOperation('remove_on_failed_install',
|
||||
'app', app_instance_name,
|
||||
[('app', app_instance_name)],
|
||||
env=env_dict_remove)
|
||||
|
||||
remove_retcode = hook_exec(
|
||||
|
@ -843,7 +846,7 @@ def app_install(uo, auth, app, label=None, args=None, no_remove_on_failure=False
|
|||
hook_callback('post_app_install', args=args_list, env=env_dict)
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def app_remove(uo, auth, app):
|
||||
"""
|
||||
Remove app
|
||||
|
@ -1051,7 +1054,7 @@ def app_debug(app):
|
|||
}
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def app_makedefault(uo, auth, app, domain=None):
|
||||
"""
|
||||
Redirect domain root to an app
|
||||
|
@ -1069,7 +1072,7 @@ def app_makedefault(uo, auth, app, domain=None):
|
|||
|
||||
if domain is None:
|
||||
domain = app_domain
|
||||
uo.related_to['domain']=[domain]
|
||||
uo.related_to.append(('domain',domain))
|
||||
elif domain not in domain_list(auth)['domains']:
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown'))
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ def _dyndns_available(provider, domain):
|
|||
return r == u"Domain %s is available" % domain
|
||||
|
||||
|
||||
@is_unit_operation('domain', lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def dyndns_subscribe(uo, subscribe_host="dyndns.yunohost.org", domain=None, key=None):
|
||||
"""
|
||||
Subscribe to a DynDNS service
|
||||
|
@ -127,9 +127,7 @@ def dyndns_subscribe(uo, subscribe_host="dyndns.yunohost.org", domain=None, key=
|
|||
"""
|
||||
if domain is None:
|
||||
domain = _get_maindomain()
|
||||
|
||||
uo.on = [domain]
|
||||
uo.related_to['domain'] = [domain]
|
||||
uo.related_to.append(('domain', domain))
|
||||
uo.start()
|
||||
|
||||
# Verify if domain is provided by subscribe_host
|
||||
|
@ -176,7 +174,7 @@ def dyndns_subscribe(uo, subscribe_host="dyndns.yunohost.org", domain=None, key=
|
|||
dyndns_installcron()
|
||||
|
||||
|
||||
@is_unit_operation('domain',lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def dyndns_update(uo, dyn_host="dyndns.yunohost.org", domain=None, key=None,
|
||||
ipv4=None, ipv6=None):
|
||||
"""
|
||||
|
@ -219,21 +217,24 @@ def dyndns_update(uo, dyn_host="dyndns.yunohost.org", domain=None, key=None,
|
|||
return
|
||||
else:
|
||||
logger.info("Updated needed, going on...")
|
||||
uo.on = [domain]
|
||||
uo.related_to['domain'] = [domain]
|
||||
uo.start()
|
||||
if domain is not None:
|
||||
uo.related_to.append(('domain', domain))
|
||||
|
||||
# If domain is not given, try to guess it from keys available...
|
||||
if domain is None:
|
||||
(domain, key) = _guess_current_dyndns_domain(dyn_host)
|
||||
uo.related_to.append(('domain', domain))
|
||||
uo.start()
|
||||
# If key is not given, pick the first file we find with the domain given
|
||||
elif key is None:
|
||||
keys = glob.glob('/etc/yunohost/dyndns/K{0}.+*.private'.format(domain))
|
||||
else:
|
||||
uo.start()
|
||||
if key is None:
|
||||
keys = glob.glob('/etc/yunohost/dyndns/K{0}.+*.private'.format(domain))
|
||||
|
||||
if not keys:
|
||||
raise MoulinetteError(errno.EIO, m18n.n('dyndns_key_not_found'))
|
||||
if not keys:
|
||||
raise MoulinetteError(errno.EIO, m18n.n('dyndns_key_not_found'))
|
||||
|
||||
key = keys[0]
|
||||
key = keys[0]
|
||||
|
||||
# This mean that hmac-md5 is used
|
||||
# (Re?)Trigger the migration to sha256 and return immediately.
|
||||
|
|
|
@ -43,154 +43,140 @@ RELATED_CATEGORIES = ['app', 'domain', 'service', 'user']
|
|||
|
||||
logger = getActionLogger('yunohost.log')
|
||||
|
||||
def log_list(limit=None):
|
||||
def log_list(limit=None, full=False):
|
||||
"""
|
||||
List available logs
|
||||
|
||||
Keyword argument:
|
||||
limit -- Maximum number of logs per categories
|
||||
limit -- Maximum number of logs
|
||||
"""
|
||||
|
||||
result = {"categories": []}
|
||||
result = {"operations": []}
|
||||
|
||||
if not os.path.exists(OPERATIONS_PATH):
|
||||
return result
|
||||
|
||||
for category in sorted(os.listdir(OPERATIONS_PATH)):
|
||||
result["categories"].append({"name": category, "operations": []})
|
||||
for operation in filter(lambda x: x.endswith(METADATA_FILE_EXT), os.listdir(os.path.join(OPERATIONS_PATH, category))):
|
||||
operations = filter(lambda x: x.endswith(METADATA_FILE_EXT), os.listdir(OPERATIONS_PATH))
|
||||
operations = reversed(sorted(operations))
|
||||
|
||||
base_filename = operation[:-len(METADATA_FILE_EXT)]
|
||||
md_filename = operation
|
||||
md_path = os.path.join(OPERATIONS_PATH, category, md_filename)
|
||||
if limit is not None:
|
||||
operations = operations[:limit]
|
||||
|
||||
operation = base_filename.split("-")
|
||||
for operation in operations:
|
||||
|
||||
operation_datetime = datetime.strptime(" ".join(operation[:2]), "%Y%m%d %H%M%S")
|
||||
base_filename = operation[:-len(METADATA_FILE_EXT)]
|
||||
md_filename = operation
|
||||
md_path = os.path.join(OPERATIONS_PATH, md_filename)
|
||||
|
||||
result["categories"][-1]["operations"].append({
|
||||
"started_at": operation_datetime,
|
||||
"description": m18n.n("log_" + operation[2], *operation[3:]),
|
||||
"name": base_filename,
|
||||
"path": md_path,
|
||||
})
|
||||
operation = base_filename.split("-")
|
||||
|
||||
result["categories"][-1]["operations"] = list(reversed(sorted(result["categories"][-1]["operations"], key=lambda x: x["started_at"])))
|
||||
operation_datetime = datetime.strptime(" ".join(operation[:2]), "%Y%m%d %H%M%S")
|
||||
|
||||
if limit is not None:
|
||||
result["categories"][-1]["operations"] = result["categories"][-1]["operations"][:limit]
|
||||
result["operations"].append({
|
||||
"started_at": operation_datetime,
|
||||
"description": m18n.n("log_" + operation[2], *operation[3:]),
|
||||
"name": base_filename,
|
||||
"path": md_path,
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def log_display(file_name_list):
|
||||
def log_display(file_name):
|
||||
"""
|
||||
Display full log or specific logs listed
|
||||
|
||||
Argument:
|
||||
file_name_list
|
||||
file_name
|
||||
"""
|
||||
|
||||
if not os.path.exists(OPERATIONS_PATH):
|
||||
if file_name.endswith(METADATA_FILE_EXT):
|
||||
base_filename = file_name[:-len(METADATA_FILE_EXT)]
|
||||
elif file_name.endswith(LOG_FILE_EXT):
|
||||
base_filename = file_name[:-len(LOG_FILE_EXT)]
|
||||
else:
|
||||
base_filename = file_name
|
||||
md_filename = base_filename + METADATA_FILE_EXT
|
||||
md_path = os.path.join(OPERATIONS_PATH, md_filename)
|
||||
log_filename = base_filename + LOG_FILE_EXT
|
||||
log_path = os.path.join(OPERATIONS_PATH, log_filename)
|
||||
operation = base_filename.split("-")
|
||||
|
||||
if not os.path.exists(md_path) and not os.path.exists(log_path):
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('log_does_exists', log=" ".join(file_name_list)))
|
||||
m18n.n('log_does_exists', log=file_name))
|
||||
infos = {}
|
||||
infos['description'] = m18n.n("log_" + operation[2], *operation[3:]),
|
||||
infos['name'] = base_filename
|
||||
|
||||
result = {"operations": []}
|
||||
if os.path.exists(md_path):
|
||||
with open(md_path, "r") as md_file:
|
||||
try:
|
||||
metadata = yaml.safe_load(md_file)
|
||||
infos['metadata_path'] = md_path
|
||||
infos['metadata'] = metadata
|
||||
except yaml.YAMLError as exc:
|
||||
print(exc)
|
||||
|
||||
for category in os.listdir(OPERATIONS_PATH):
|
||||
for operation in filter(lambda x: x.endswith(METADATA_FILE_EXT), os.listdir(os.path.join(OPERATIONS_PATH, category))):
|
||||
if operation not in file_name_list and file_name_list:
|
||||
continue
|
||||
|
||||
base_filename = operation[:-len(METADATA_FILE_EXT)]
|
||||
md_filename = operation
|
||||
md_path = os.path.join(OPERATIONS_PATH, category, md_filename)
|
||||
log_filename = base_filename + LOG_FILE_EXT
|
||||
log_path = os.path.join(OPERATIONS_PATH, category, log_filename)
|
||||
operation = base_filename.split("-")
|
||||
|
||||
with open(md_path, "r") as md_file:
|
||||
try:
|
||||
infos = yaml.safe_load(md_file)
|
||||
except yaml.YAMLError as exc:
|
||||
print(exc)
|
||||
|
||||
with open(log_path, "r") as content:
|
||||
logs = content.read()
|
||||
logs = [{"datetime": x.split(": ", 1)[0].replace("_", " "), "line": x.split(": ", 1)[1]} for x in logs.split("\n") if x]
|
||||
infos['logs'] = logs
|
||||
infos['description'] = m18n.n("log_" + operation[2], *operation[3:]),
|
||||
infos['name'] = base_filename
|
||||
if os.path.exists(log_path):
|
||||
with open(log_path, "r") as content:
|
||||
logs = content.read()
|
||||
logs = [{"datetime": x.split(": ", 1)[0].replace("_", " "), "line": x.split(": ", 1)[1]} for x in logs.split("\n") if x]
|
||||
infos['log_path'] = log_path
|
||||
result['operations'].append(infos)
|
||||
infos['logs'] = logs
|
||||
|
||||
if len(file_name_list) > 0 and len(result['operations']) < len(file_name_list):
|
||||
logger.error(m18n.n('log_does_exists', log="', '".join(file_name_list)))
|
||||
return infos
|
||||
|
||||
if len(result['operations']) > 0:
|
||||
result['operations'] = sorted(result['operations'], key=lambda operation: operation['started_at'])
|
||||
return result
|
||||
|
||||
def is_unit_operation(categorie=None, operation_key=None, lazy=False):
|
||||
def is_unit_operation(entities='app,domain,service,user', exclude='auth,password', operation_key=None, auto=True):
|
||||
def decorate(func):
|
||||
def func_wrapper(*args, **kwargs):
|
||||
cat = categorie
|
||||
entities_list = entities.split(',')
|
||||
exclude_list = exclude.split(',')
|
||||
op_key = operation_key
|
||||
on = None
|
||||
related_to = {}
|
||||
inject = lazy
|
||||
to_start = not lazy
|
||||
related_to = []
|
||||
|
||||
if cat is None:
|
||||
cat = func.__module__.split('.')[1]
|
||||
if op_key is None:
|
||||
op_key = func.__name__
|
||||
if cat in kwargs:
|
||||
on = kwargs[cat]
|
||||
for r_category in RELATED_CATEGORIES:
|
||||
if r_category in kwargs and kwargs[r_category] is not None:
|
||||
if r_category not in related_to:
|
||||
related_to[r_category] = []
|
||||
if isinstance(kwargs[r_category], basestring):
|
||||
related_to[r_category] += [kwargs[r_category]]
|
||||
|
||||
for entity in entities_list:
|
||||
entity = entity.split(':')
|
||||
entity_type = entity[-1]
|
||||
entity = entity[0]
|
||||
if entity in kwargs and kwargs[entity] is not None:
|
||||
if isinstance(kwargs[entity], basestring):
|
||||
related_to.append({entity_type: kwargs[entity]})
|
||||
else:
|
||||
related_to[r_category] += kwargs[r_category]
|
||||
for x in kwargs[entity]:
|
||||
related_to.append({entity_type: kwargs[x]})
|
||||
|
||||
context = kwargs.copy()
|
||||
if 'auth' in context:
|
||||
context.pop('auth', None)
|
||||
uo = UnitOperation(op_key, cat, on, related_to, args=context)
|
||||
if to_start:
|
||||
for field in exclude_list:
|
||||
if field in context:
|
||||
context.pop(field, None)
|
||||
uo = UnitOperation(op_key, related_to, args=context)
|
||||
if auto:
|
||||
uo.start()
|
||||
try:
|
||||
if inject:
|
||||
if not auto:
|
||||
args = (uo,) + args
|
||||
result = func(*args, **kwargs)
|
||||
finally:
|
||||
if uo.started_at is not None:
|
||||
uo.close(exc_info()[0])
|
||||
uo.close(exc_info()[0])
|
||||
return result
|
||||
return func_wrapper
|
||||
return decorate
|
||||
|
||||
class UnitOperation(object):
|
||||
def __init__(self, operation, category, on=None, related_to=None, **kwargs):
|
||||
def __init__(self, operation, related_to=None, **kwargs):
|
||||
# TODO add a way to not save password on app installation
|
||||
self.operation = operation
|
||||
self.category = category
|
||||
self.on = on
|
||||
if isinstance(self.on, basestring):
|
||||
self.on = [self.on]
|
||||
|
||||
self.related_to = related_to
|
||||
if related_to is None:
|
||||
if self.category in RELATED_CATEGORIES:
|
||||
self.related_to = {self.category: self.on}
|
||||
self.extra = kwargs
|
||||
self.started_at = None
|
||||
self.ended_at = None
|
||||
self.logger = None
|
||||
|
||||
self.path = os.path.join(OPERATIONS_PATH, category)
|
||||
self.path = OPERATIONS_PATH
|
||||
|
||||
if not os.path.exists(self.path):
|
||||
os.makedirs(self.path)
|
||||
|
@ -220,8 +206,8 @@ class UnitOperation(object):
|
|||
def name(self):
|
||||
name = [self.started_at.strftime("%Y%m%d-%H%M%S")]
|
||||
name += [self.operation]
|
||||
if self.on is not None:
|
||||
name += self.on
|
||||
if self.related_to:
|
||||
name += self.related_to[0].values()
|
||||
return '-'.join(name)
|
||||
|
||||
@property
|
||||
|
@ -229,10 +215,9 @@ class UnitOperation(object):
|
|||
data = {
|
||||
'started_at': self.started_at,
|
||||
'operation': self.operation,
|
||||
'related_to': self.related_to
|
||||
}
|
||||
if self.on is not None:
|
||||
data['on'] = self.on
|
||||
if self.related_to is not None:
|
||||
data['related_to'] = self.related_to
|
||||
if self.ended_at is not None:
|
||||
data['ended_at'] = self.ended_at
|
||||
data['success'] = self._success
|
||||
|
|
|
@ -139,7 +139,7 @@ def tools_adminpw(auth, new_password):
|
|||
logger.success(m18n.n('admin_password_changed'))
|
||||
|
||||
|
||||
@is_unit_operation('domain', lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def tools_maindomain(uo, auth, new_domain=None):
|
||||
"""
|
||||
Check the current main domain, or change it
|
||||
|
@ -157,8 +157,7 @@ def tools_maindomain(uo, auth, new_domain=None):
|
|||
if new_domain not in domain_list(auth)['domains']:
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown'))
|
||||
|
||||
uo.on = [new_domain]
|
||||
uo.related_to['domain'] = [new_domain]
|
||||
uo.related_to.append(('domain', new_domain))
|
||||
uo.start()
|
||||
|
||||
# Apply changes to ssl certs
|
||||
|
@ -471,7 +470,7 @@ def tools_update(ignore_apps=False, ignore_packages=False):
|
|||
return {'packages': packages, 'apps': apps}
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def tools_upgrade(uo, auth, ignore_apps=False, ignore_packages=False):
|
||||
"""
|
||||
Update apps & package cache, then display changelog
|
||||
|
@ -711,7 +710,7 @@ def tools_port_available(port):
|
|||
return False
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def tools_shutdown(uo, force=False):
|
||||
shutdown = force
|
||||
if not shutdown:
|
||||
|
@ -730,7 +729,7 @@ def tools_shutdown(uo, force=False):
|
|||
subprocess.check_call(['systemctl', 'poweroff'])
|
||||
|
||||
|
||||
@is_unit_operation(lazy=True)
|
||||
@is_unit_operation(auto=False)
|
||||
def tools_reboot(uo, force=False):
|
||||
reboot = force
|
||||
if not reboot:
|
||||
|
|
|
@ -90,7 +90,7 @@ def user_list(auth, fields=None):
|
|||
return {'users': users}
|
||||
|
||||
|
||||
@is_unit_operation()
|
||||
@is_unit_operation('username:user')
|
||||
def user_create(auth, username, firstname, lastname, mail, password,
|
||||
mailbox_quota="0"):
|
||||
"""
|
||||
|
@ -212,7 +212,7 @@ def user_create(auth, username, firstname, lastname, mail, password,
|
|||
raise MoulinetteError(169, m18n.n('user_creation_failed'))
|
||||
|
||||
|
||||
@is_unit_operation()
|
||||
@is_unit_operation('username:user')
|
||||
def user_delete(auth, username, purge=False):
|
||||
"""
|
||||
Delete user
|
||||
|
@ -248,7 +248,7 @@ def user_delete(auth, username, purge=False):
|
|||
logger.success(m18n.n('user_deleted'))
|
||||
|
||||
|
||||
@is_unit_operation()
|
||||
@is_unit_operation('username:user', exclude='auth,change_password')
|
||||
def user_update(auth, username, firstname=None, lastname=None, mail=None,
|
||||
change_password=None, add_mailforward=None, remove_mailforward=None,
|
||||
add_mailalias=None, remove_mailalias=None, mailbox_quota=None):
|
||||
|
|
Loading…
Add table
Reference in a new issue