diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 39d39aeb..58abeec6 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -351,7 +351,7 @@ app: ### app_remove() TODO: Write help remove: action_help: Remove app - api: DELETE /app/ + api: DELETE /app arguments: app: help: App(s) to delete @@ -476,6 +476,13 @@ app: full: --users nargs: "+" + ### app_clearaccess() + clearaccess: + action_help: Reset access rights for the app + api: POST /app/access + arguments: + apps: + nargs: "+" ############################# # Backup # @@ -908,6 +915,26 @@ tools: help: Subscribe domain to a DynDNS service action: store_true + ### tools_update() + update: + action_help: YunoHost update + api: POST /update + + ### tools_changelog() + changelog: + action_help: YunoHost changelog + api: POST /changelog + + ### tools_upgrade() + upgrade: + action_help: YunoHost upgrade + api: POST /upgrade + + ### tools_upgradelog() + upgradelog: + action_help: Show dpkg log + api: POST /upgradelog + ############################# # Hook # diff --git a/lib/yunohost/app.py b/lib/yunohost/app.py index f75cae7a..9436c707 100644 --- a/lib/yunohost/app.py +++ b/lib/yunohost/app.py @@ -70,8 +70,8 @@ def app_fetchlist(url=None, name=None): Fetch application list from app server Keyword argument: - name -- Name of the list (default fapp) - url -- URL of remote JSON list (default http://fapp.yunohost.org/app/list/raw) + name -- Name of the list (default yunohost) + url -- URL of remote JSON list (default http://app.yunohost.org/list.json) """ # Create app path if not exists @@ -93,7 +93,7 @@ def app_fetchlist(url=None, name=None): os.rename(list_file +'.tmp', list_file) os.system("touch /etc/cron.d/yunohost-applist-"+ name) - os.system("echo '00 00 * * * root yunohost app fetchlist -u "+ url +" -n "+ name +" --no-ldap >> /dev/null' >/etc/cron.d/yunohost-applist-"+ name) + os.system("echo '00 00 * * * root yunohost app fetchlist -u "+ url +" -n "+ name +" --no-ldap > /dev/null 2>&1' >/etc/cron.d/yunohost-applist-"+ name) win_msg(_("List successfully fetched")) @@ -532,7 +532,11 @@ def app_addaccess(apps, users): apps """ - #TODO: Adapt to SSOwat + if not users: + users = [] + for user in user_list()['Users']: + users.append(user['Username']) + if not isinstance(users, list): users = [users] if not isinstance(apps, list): apps = [apps] @@ -568,6 +572,8 @@ def app_addaccess(apps, users): app_ssowatconf() + return { 'allowed_users': new_users.split(',') } + def app_removeaccess(apps, users): """ @@ -578,7 +584,9 @@ def app_removeaccess(apps, users): apps """ - #TODO: Remove access + remove_all = False + if not users: + remove_all = True if not isinstance(users, list): users = [users] if not isinstance(apps, list): apps = [apps] for app in apps: @@ -591,7 +599,9 @@ def app_removeaccess(apps, users): app_settings = yaml.load(f) if 'skipped_uris' not in app_settings or app_settings['skipped_uris'] != '/': - if 'allowed_users' in app_settings: + if remove_all: + new_users = '' + elif 'allowed_users' in app_settings: for allowed_user in app_settings['allowed_users'].split(','): if allowed_user not in users: if new_users == '': @@ -610,6 +620,34 @@ def app_removeaccess(apps, users): app_ssowatconf() + return { 'allowed_users': new_users.split(',') } + + +def app_clearaccess(apps): + """ + Reset access rights for the app + + Keyword argument: + apps + + """ + if not isinstance(apps, list): apps = [apps] + + for app in apps: + if not _is_installed(app): + raise YunoHostError(22, _("App is not installed")) + + with open(apps_setting_path + app +'/settings.yml') as f: + app_settings = yaml.load(f) + + if 'mode' in app_settings: + app_setting(app, 'mode', delete=True) + + if 'allowed_users' in app_settings: + app_setting(app, 'allowed_users', delete=True) + + app_ssowatconf() + def app_setting(app, key, value=None, delete=False): """ @@ -797,7 +835,12 @@ def app_ssowatconf(): users[user['Username']] = app_map(user=user['Username']) skipped_urls = [] + skipped_regex = [] unprotected_urls = [] + unprotected_regex = [] + protected_urls = [] + protected_regex = [] + apps = {} for app in app_list()['Apps']: if _is_installed(app['ID']): @@ -808,31 +851,55 @@ def app_ssowatconf(): if item[-1:] == '/': item = item[:-1] skipped_urls.append(app_settings['domain'] + app_settings['path'][:-1] + item) + if 'skipped_regex' in app_settings: + for item in app_settings['skipped_regex'].split(','): + skipped_regex.append(item) if 'unprotected_uris' in app_settings: for item in app_settings['unprotected_uris'].split(','): if item[-1:] == '/': item = item[:-1] unprotected_urls.append(app_settings['domain'] + app_settings['path'][:-1] + item) + if 'unprotected_regex' in app_settings: + for item in app_settings['unprotected_regex'].split(','): + unprotected_regex.append(item) + if 'protected_uris' in app_settings: + for item in app_settings['protected_uris'].split(','): + if item[-1:] == '/': + item = item[:-1] + protected_urls.append(app_settings['domain'] + app_settings['path'][:-1] + item) + if 'protected_regex' in app_settings: + for item in app_settings['protected_regex'].split(','): + protected_regex.append(item) for domain in domains: skipped_urls.extend([domain +'/ynhadmin', domain +'/ynhapi']) - conf_dict = { - 'portal_domain': main_domain, - 'portal_path': '/ynhsso/', - 'portal_port': '443', - 'portal_scheme': 'https', - 'additional_headers': { + with open('/etc/ssowat/conf.json') as f: + conf_dict = json.load(f) + + if not 'portal_domain' in conf_dict: + conf_dict['portal_domain'] = main_domain + if not 'portal_path' in conf_dict: + conf_dict['portal_path'] = '/ynhsso/' + if not 'portal_port' in conf_dict: + conf_dict['portal_port'] = '443' + if not 'portal_scheme' in conf_dict: + conf_dict['portal_scheme'] = 'https' + if not 'additional_headers' in conf_dict: + conf_dict['additional_headers'] = { 'Auth-User': 'uid', 'Remote-User': 'uid', 'Name': 'cn', 'Email': 'mail' - }, - 'domains': domains, - 'skipped_urls': skipped_urls, - 'unprotected_urls': unprotected_urls, - 'users': users - } + } + conf_dict['domains'] = domains + conf_dict['skipped_urls'] = skipped_urls + conf_dict['unprotected_urls'] = unprotected_urls + conf_dict['protected_urls'] = protected_urls + conf_dict['skipped_regex'] = skipped_regex + conf_dict['unprotected_regex'] = unprotected_regex + conf_dict['protected_regex'] = protected_regex + conf_dict['users'] = users with open('/etc/ssowat/conf.json', 'wb') as f: json.dump(conf_dict, f) diff --git a/lib/yunohost/data/checkupdate b/lib/yunohost/data/checkupdate new file mode 100644 index 00000000..82626e5c --- /dev/null +++ b/lib/yunohost/data/checkupdate @@ -0,0 +1,67 @@ +#!/bin/bash + +if [ ! -d /tmp/yunohost ]; +then + mkdir /tmp/yunohost +fi + +if [ -f /tmp/yunohost/changelog ]; +then + rm /tmp/yunohost/changelog +fi + +apt-get update -y > /dev/null 2>&1 +if [[ $? != 0 ]]; +then + exit 2 +else + echo OK > /tmp/yunohost/update_status +fi + +# Set $DIRCACHE +eval `/usr/bin/apt-config shell DIRCACHE Dir::Cache` + + +# get the list of packages which are pending an upgrade +PKGNAMES=`/usr/bin/apt-get -q -y --ignore-hold --allow-unauthenticated -s dist-upgrade | \ + /bin/grep ^Inst | /usr/bin/cut -d\ -f2 | /usr/bin/sort` + +if [[ $PKGNAMES = "" ]]; +then + exit 1 +fi + +if [ -n "$PKGNAMES" ] ; then + + # do the upgrade downloads + /usr/bin/apt-get --ignore-hold -qq -d --allow-unauthenticated --force-yes dist-upgrade > /dev/null +fi + + +PKGPATH="/${DIRCACHE}archives/" +for PKG in $PKGNAMES ; do + VER=`LC_ALL=C /usr/bin/apt-cache policy $PKG |\ + /bin/grep Candidate: | /usr/bin/cut -f 4 -d \ ` + OLDVER=`LC_ALL=C /usr/bin/apt-cache policy $PKG |\ + /bin/grep Installed: | /usr/bin/cut -f 4 -d \ ` + VERFILE=`echo "$VER" | /bin/sed -e "s/:/%3a/g"` + if ls ${PKGPATH}${PKG}_${VERFILE}_*.deb >& /dev/null ; then + DEBS="$DEBS ${PKGPATH}${PKG}_${VERFILE}_*.deb" + fi + echo -e "$PKG $OLDVER -> $VER" +done + +MISSING_DEBS=`apt-get -y --ignore-hold --allow-unauthenticated --print-uris dist-upgrade \ + | grep "file:" \ + | sed "s/'file:\(.*\)' .*/\1/g"` + +DEBS=`echo $MISSING_DEBS $DEBS | /usr/bin/sort` + +if [[ $DEBS = "" ]]; +then + exit 3 +else + if [ -x /usr/bin/apt-listchanges ] ; then + /usr/bin/apt-listchanges --which=both -f text $DEBS > /tmp/yunohost/changelog 2>/dev/null + fi +fi diff --git a/lib/yunohost/data/services.yml b/lib/yunohost/data/services.yml index fc0bee7b..ec5c37d4 100644 --- a/lib/yunohost/data/services.yml +++ b/lib/yunohost/data/services.yml @@ -31,7 +31,7 @@ php5-fpm: status: service log: /var/log/php5-fpm.log yunohost-api: - status: service + status: cat /usr/share/pyshared/yunohost-cli/twistd.pid log: /var/log/yunohost.log postgrey: status: service diff --git a/lib/yunohost/data/upgrade b/lib/yunohost/data/upgrade new file mode 100644 index 00000000..b8a81cce --- /dev/null +++ b/lib/yunohost/data/upgrade @@ -0,0 +1,5 @@ +/bin/bash +rm /tmp/yunohost/update_status +sudo apt-get upgrade -y > /tmp/yunohost/update_log 2>&1 +if [ $(echo $?) = 0 ]; then echo "OK" > /tmp/yunohost/upgrade_status; else echo "NOK" > /tmp/yunohost/upgrade_status; fi +rm /tmp/yunohost/upgrade.run diff --git a/lib/yunohost/dyndns.py b/lib/yunohost/dyndns.py index 83a4db36..e96e592c 100644 --- a/lib/yunohost/dyndns.py +++ b/lib/yunohost/dyndns.py @@ -140,7 +140,7 @@ def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None, ip=Non with open('/etc/yunohost/dyndns/old_ip', 'w') as f: f.write(new_ip) else: - os.remove('/etc/yunohost/dyndns/old_ip') + os.system('rm /etc/yunohost/dyndns/old_ip > /dev/null 2>&1') raise YunoHostError(1, _("An error occured during DynDNS update")) diff --git a/lib/yunohost/firewall.py b/lib/yunohost/firewall.py index ce011841..c6c5767b 100644 --- a/lib/yunohost/firewall.py +++ b/lib/yunohost/firewall.py @@ -39,6 +39,7 @@ except ImportError: sys.stderr.write('Error: Yunohost CLI Require yaml lib\n') sys.stderr.write('apt-get install python-yaml\n') sys.exit(1) +from hook import hook_callback from moulinette.helpers import YunoHostError, win_msg diff --git a/lib/yunohost/monitor.py b/lib/yunohost/monitor.py index be01eadb..e8c881e3 100644 --- a/lib/yunohost/monitor.py +++ b/lib/yunohost/monitor.py @@ -65,7 +65,19 @@ def monitor_disk(units=None, mountpoint=None, human_readable=False): # Get mounted block devices devices = {} - output = subprocess.check_output('lsblk -o NAME,MOUNTPOINT -l -n'.split()) + try: + output = subprocess.check_output('lsblk -o NAME,MOUNTPOINT -l -n'.split()) + except subprocess.CalledProcessError: + output = '' + + # Try to find at least root partition + if not output: + for p in psutil.disk_partitions(all=True): + if p.mountpoint == '/': + output = '%s /' % p.device.replace('/dev/', '') + break + + # Format results for d in output.split('\n'): m = re.search(r'([a-z]+[0-9]*)[ ]+(\/\S*)', d) # Extract device name (1) and its mountpoint (2) if m and (mountpoint is None or m.group(2) == mountpoint): diff --git a/lib/yunohost/tools.py b/lib/yunohost/tools.py index e69dfac2..c6950e85 100644 --- a/lib/yunohost/tools.py +++ b/lib/yunohost/tools.py @@ -34,6 +34,7 @@ import getpass import subprocess import requests import json +from subprocess import Popen, PIPE from domain import domain_add, domain_list from dyndns import dyndns_subscribe from backup import backup_init @@ -103,7 +104,7 @@ def tools_adminpw(old_password, new_password): raise YunoHostError(22, _("Invalid password")) -def tools_maindomain(old_domain, new_domain, dyndns=False): +def tools_maindomain(old_domain=None, new_domain=None, dyndns=False): """ Main domain change tool @@ -117,6 +118,9 @@ def tools_maindomain(old_domain, new_domain, dyndns=False): with open('/etc/yunohost/current_host', 'r') as f: old_domain = f.readline().rstrip() + if not new_domain: + return { 'current_main_domain': old_domain } + validate(r'^([a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)(\.[a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)*(\.[a-zA-Z]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)$', old_domain) config_files = [ @@ -124,8 +128,9 @@ def tools_maindomain(old_domain, new_domain, dyndns=False): '/etc/metronome/metronome.cfg.lua', '/etc/dovecot/dovecot.conf', '/usr/share/yunohost/yunohost-config/others/startup', - '/home/yunohost.backup/tahoe/tahoe.cfg' - '/etc/amavis/conf.d/05-node_id' + '/home/yunohost.backup/tahoe/tahoe.cfg', + '/etc/amavis/conf.d/05-node_id', + '/etc/amavis/conf.d/50-user' ] config_dir = [] @@ -153,7 +158,8 @@ def tools_maindomain(old_domain, new_domain, dyndns=False): 'service nginx restart', 'service metronome restart', 'service postfix restart', - 'service dovecot restart' + 'service dovecot restart', + 'service amavis restart' ] try: @@ -221,21 +227,6 @@ def tools_postinstall(domain, password, dyndns=False): if os.system('hostname -d') != 0: os.system('hostname yunohost.yunohost.org') - # Activate "full" mode if RAM >= 512MB - for L in open("/proc/meminfo"): - if "MemTotal" in L: - if int(L.split(" ")[-2]) < 500000 or not requests.get('http://ip.yunohost.org/'): - os.system('touch /etc/yunohost/light') - else: - os.system('service dspam stop') - os.system('chmod -x /etc/cron.daily/dspam') - os.system('update-rc.d dspam remove') - os.system('sed -i "s/yes/no/g" /etc/default/dspam') - os.system('sed -i "s/dspam=no/dspam=yes/" /etc/yunohost/yunohost.conf') - os.system('apt-get install -y -qq yunohost-config-amavis') - os.system('service amavis start') - os.system('apt-get install --reinstall -y -qq yunohost-config-postfix yunohost-config-dovecot') - # Create SSL CA ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA' command_list = [ @@ -276,3 +267,65 @@ def tools_postinstall(domain, password, dyndns=False): win_msg(_("YunoHost has been successfully configured")) +def tools_update(): + """ + Update distribution + + """ + process = Popen("/usr/bin/checkupdate", stdout=PIPE) + stdout, stderr = process.communicate() + if process.returncode == 1: + win_msg( _("Not upgrade found")) + elif process.returncode == 2: + raise YunoHostError(17, _("Error during update")) + else: + return { "Update" : stdout.splitlines() } + + +def tools_changelog(): + """ + Show Changelog + + """ + if os.path.isfile('/tmp/yunohost/update_status'): + with open('/tmp/yunohost/changelog', 'r') as f: + read_data = f.read() + return { "Changelog" : read_data.splitlines() } + else: + raise YunoHostError(17, _("Launch update before upgrade")) + + +def tools_upgrade(): + """ + Upgrade distribution + + """ + if os.path.isfile('/tmp/yunohost/upgrade.run'): + win_msg( _("Upgrade in progress")) + else: + if os.path.isfile('/tmp/yunohost/upgrade_status'): + with open('/tmp/yunohost/upgrade_status', 'r') as f: + read_data = f.read() + os.system('rm /tmp/yunohost/upgrade_status') + if read_data.strip() == "OK": + win_msg( _("YunoHost has been successfully upgraded")) + else: + raise YunoHostError(17, _("Error during upgrade")) + elif os.path.isfile('/tmp/yunohost/update_status'): + os.system('at now -f /usr/share/yunohost/upgrade') + win_msg( _("Upgrade in progress")) + else: + raise YunoHostError(17, _("Launch update before upgrade")) + + +def tools_upgradelog(): + """ + Show upgrade log + + """ + if os.path.isfile('/tmp/yunohost/upgrade.run'): + win_msg( _("Upgrade in progress")) + else: + with open('/tmp/yunohost/update_log', 'r') as f: + read_data = f.read() + return { "DPKG LOG" : read_data.splitlines() }