コード例 #1
0
ファイル: test_apps.py プロジェクト: grenagit/yunohost
def test_systemfuckedup_during_app_upgrade(mocker, secondary_domain):

    install_break_yo_system(secondary_domain, breakwhat="upgrade")

    with pytest.raises(YunohostError):
        with message(mocker, "app_action_broke_system"):
            app_upgrade("break_yo_system", file=os.path.join(get_test_apps_dir(), "break_yo_system_ynh"))
コード例 #2
0
ファイル: test_apps.py プロジェクト: grenagit/yunohost
def test_failed_multiple_app_upgrade(mocker, secondary_domain):

    install_legacy_app(secondary_domain, "/legacy")
    install_break_yo_system(secondary_domain, breakwhat="upgrade")

    with pytest.raises(YunohostError):
        with message(mocker, "app_not_upgraded"):
            app_upgrade(
                ["break_yo_system", "legacy_app"],
                file={
                    "break_yo_system": os.path.join(get_test_apps_dir(), "break_yo_system_ynh"),
                    "legacy": os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
                },
            )
コード例 #3
0
ファイル: test_permission.py プロジェクト: grenagit/yunohost
def test_permission_protection_management_by_helper():
    app_install(os.path.join(get_test_apps_dir(), "permissions_app_ynh"),
                args="domain=%s&domain_2=%s&path=%s&admin=%s" %
                (maindomain, other_domains[0], "/urlpermissionapp", "alice"),
                force=True)

    res = user_permission_list(full=True)['permissions']
    assert res['permissions_app.main']['protected'] is False
    assert res['permissions_app.admin']['protected'] is True
    assert res['permissions_app.dev']['protected'] is False

    app_upgrade(["permissions_app"],
                file=os.path.join(get_test_apps_dir(), "permissions_app_ynh"))

    res = user_permission_list(full=True)['permissions']
    assert res['permissions_app.main']['protected'] is False
    assert res['permissions_app.admin']['protected'] is False
    assert res['permissions_app.dev']['protected'] is True
コード例 #4
0
ファイル: tools.py プロジェクト: trogeat/yunohost
def tools_upgrade(operation_logger,
                  apps=None,
                  system=False,
                  allow_yunohost_upgrade=True):
    """
    Update apps & package cache, then display changelog

    Keyword arguments:
       apps -- List of apps to upgrade (or [] to update all apps)
       system -- True to upgrade system
    """
    from yunohost.utils import packages

    if packages.dpkg_is_broken():
        raise YunohostValidationError("dpkg_is_broken")

    # Check for obvious conflict with other dpkg/apt commands already running in parallel
    if not packages.dpkg_lock_available():
        raise YunohostValidationError("dpkg_lock_not_available")

    if system is not False and apps is not None:
        raise YunohostValidationError("tools_upgrade_cant_both")

    if system is False and apps is None:
        raise YunohostValidationError("tools_upgrade_at_least_one")

    #
    # Apps
    # This is basically just an alias to yunohost app upgrade ...
    #

    if apps is not None:

        # Make sure there's actually something to upgrade

        upgradable_apps = [app["id"] for app in _list_upgradable_apps()]

        if not upgradable_apps or (len(apps) and all(app not in upgradable_apps
                                                     for app in apps)):
            logger.info(m18n.n("apps_already_up_to_date"))
            return

        # Actually start the upgrades

        try:
            app_upgrade(app=apps)
        except Exception as e:
            logger.warning("unable to upgrade apps: %s" % str(e))
            logger.error(m18n.n("app_upgrade_some_app_failed"))

        return

    #
    # System
    #

    if system is True:

        # Check that there's indeed some packages to upgrade
        upgradables = list(_list_upgradable_apt_packages())
        if not upgradables:
            logger.info(m18n.n("already_up_to_date"))

        logger.info(m18n.n("upgrading_packages"))
        operation_logger.start()

        # Critical packages are packages that we can't just upgrade
        # randomly from yunohost itself... upgrading them is likely to
        critical_packages = [
            "moulinette", "yunohost", "yunohost-admin", "ssowat"
        ]

        critical_packages_upgradable = [
            p["name"] for p in upgradables if p["name"] in critical_packages
        ]
        noncritical_packages_upgradable = [
            p["name"] for p in upgradables
            if p["name"] not in critical_packages
        ]

        # Prepare dist-upgrade command
        dist_upgrade = "DEBIAN_FRONTEND=noninteractive"
        dist_upgrade += " APT_LISTCHANGES_FRONTEND=none"
        dist_upgrade += " apt-get"
        dist_upgrade += (
            " --fix-broken --show-upgraded --assume-yes --quiet -o=Dpkg::Use-Pty=0"
        )
        for conf_flag in ["old", "miss", "def"]:
            dist_upgrade += ' -o Dpkg::Options::="--force-conf{}"'.format(
                conf_flag)
        dist_upgrade += " dist-upgrade"

        #
        # "Regular" packages upgrade
        #
        if noncritical_packages_upgradable:

            logger.info(m18n.n("tools_upgrade_regular_packages"))

            # Mark all critical packages as held
            for package in critical_packages:
                check_output("apt-mark hold %s" % package)

            # Doublecheck with apt-mark showhold that packages are indeed held ...
            held_packages = check_output("apt-mark showhold").split("\n")
            if any(p not in held_packages for p in critical_packages):
                logger.warning(
                    m18n.n("tools_upgrade_cant_hold_critical_packages"))
                operation_logger.error(m18n.n("packages_upgrade_failed"))
                raise YunohostError(m18n.n("packages_upgrade_failed"))

            logger.debug("Running apt command :\n{}".format(dist_upgrade))

            def is_relevant(line):
                irrelevants = [
                    "service sudo-ldap already provided",
                    "Reading database ...",
                ]
                return all(i not in line.rstrip() for i in irrelevants)

            callbacks = (
                lambda l: logger.info("+ " + l.rstrip() + "\r")
                if is_relevant(l) else logger.debug(l.rstrip() + "\r"),
                lambda l: logger.warning(l.rstrip())
                if is_relevant(l) else logger.debug(l.rstrip()),
            )
            returncode = call_async_output(dist_upgrade, callbacks, shell=True)
            if returncode != 0:
                upgradables = list(_list_upgradable_apt_packages())
                noncritical_packages_upgradable = [
                    p["name"] for p in upgradables
                    if p["name"] not in critical_packages
                ]
                logger.warning(
                    m18n.n(
                        "tools_upgrade_regular_packages_failed",
                        packages_list=", ".join(
                            noncritical_packages_upgradable),
                    ))
                operation_logger.error(m18n.n("packages_upgrade_failed"))
                raise YunohostError(m18n.n("packages_upgrade_failed"))

        #
        # Critical packages upgrade
        #
        if critical_packages_upgradable and allow_yunohost_upgrade:

            logger.info(m18n.n("tools_upgrade_special_packages"))

            # Mark all critical packages as unheld
            for package in critical_packages:
                check_output("apt-mark unhold %s" % package)

            # Doublecheck with apt-mark showhold that packages are indeed unheld ...
            held_packages = check_output("apt-mark showhold").split("\n")
            if any(p in held_packages for p in critical_packages):
                logger.warning(
                    m18n.n("tools_upgrade_cant_unhold_critical_packages"))
                operation_logger.error(m18n.n("packages_upgrade_failed"))
                raise YunohostError(m18n.n("packages_upgrade_failed"))

            #
            # Here we use a dirty hack to run a command after the current
            # "yunohost tools upgrade", because the upgrade of yunohost
            # will also trigger other yunohost commands (e.g. "yunohost tools migrations run")
            # (also the upgrade of the package, if executed from the webadmin, is
            # likely to kill/restart the api which is in turn likely to kill this
            # command before it ends...)
            #
            logfile = operation_logger.log_path
            dist_upgrade = dist_upgrade + " 2>&1 | tee -a {}".format(logfile)

            MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
            wait_until_end_of_yunohost_command = (
                "(while [ -f {} ]; do sleep 2; done)".format(MOULINETTE_LOCK))
            mark_success = (
                "(echo 'Done!' | tee -a {} && echo 'success: true' >> {})".
                format(logfile, operation_logger.md_path))
            mark_failure = (
                "(echo 'Failed :(' | tee -a {} && echo 'success: false' >> {})"
                .format(logfile, operation_logger.md_path))
            update_log_metadata = "sed -i \"s/ended_at: .*$/ended_at: $(date -u +'%Y-%m-%d %H:%M:%S.%N')/\" {}"
            update_log_metadata = update_log_metadata.format(
                operation_logger.md_path)

            # Dirty hack such that the operation_logger does not add ended_at
            # and success keys in the log metadata.  (c.f. the code of the
            # is_unit_operation + operation_logger.close()) We take care of
            # this ourselves (c.f. the mark_success and updated_log_metadata in
            # the huge command launched by os.system)
            operation_logger.ended_at = "notyet"

            upgrade_completed = "\n" + m18n.n(
                "tools_upgrade_special_packages_completed")
            command = "({wait} && {dist_upgrade}) && {mark_success} || {mark_failure}; {update_metadata}; echo '{done}'".format(
                wait=wait_until_end_of_yunohost_command,
                dist_upgrade=dist_upgrade,
                mark_success=mark_success,
                mark_failure=mark_failure,
                update_metadata=update_log_metadata,
                done=upgrade_completed,
            )

            logger.warning(
                m18n.n("tools_upgrade_special_packages_explanation"))
            logger.debug("Running command :\n{}".format(command))
            open("/tmp/yunohost-selfupgrade",
                 "w").write("rm /tmp/yunohost-selfupgrade; " + command)
            # Using systemd-run --scope is like nohup/disown and &, but more robust somehow
            # (despite using nohup/disown and &, the self-upgrade process was still getting killed...)
            # ref: https://unix.stackexchange.com/questions/420594/why-process-killed-with-nohup
            # (though I still don't understand it 100%...)
            os.system("systemd-run --scope bash /tmp/yunohost-selfupgrade &")
            return

        else:
            logger.success(m18n.n("system_upgraded"))
            operation_logger.success()
コード例 #5
0
def tools_upgrade(auth, ignore_apps=False, ignore_packages=False):
    """
    Update apps & package cache, then display changelog

    Keyword arguments:
        ignore_apps -- Ignore apps upgrade
        ignore_packages -- Ignore APT packages upgrade

    """
    failure = False

    # Retrieve interface
    is_api = True if msettings.get('interface') == 'api' else False

    if not ignore_packages:
        cache = apt.Cache()
        cache.open(None)
        cache.upgrade(True)

        # If API call
        if is_api:
            critical_packages = ("moulinette", "yunohost", "yunohost-admin",
                                 "ssowat", "python")
            critical_upgrades = set()

            for pkg in cache.get_changes():
                if pkg.name in critical_packages:
                    critical_upgrades.add(pkg.name)
                    # Temporarily keep package ...
                    pkg.mark_keep()

            # ... and set a hourly cron up to upgrade critical packages
            if critical_upgrades:
                logger.info(
                    m18n.n('packages_upgrade_critical_later',
                           packages=', '.join(critical_upgrades)))
                with open('/etc/cron.d/yunohost-upgrade', 'w+') as f:
                    f.write(
                        '00 * * * * root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin apt-get install %s -y && rm -f /etc/cron.d/yunohost-upgrade\n'
                        % ' '.join(critical_upgrades))

        if cache.get_changes():
            logger.info(m18n.n('upgrading_packages'))

            try:
                # Apply APT changes
                # TODO: Logs output for the API
                cache.commit(apt.progress.text.AcquireProgress(),
                             apt.progress.base.InstallProgress())
            except Exception as e:
                failure = True
                logger.warning('unable to upgrade packages: %s' % str(e))
                logger.error(m18n.n('packages_upgrade_failed'))
            else:
                logger.info(m18n.n('done'))
        else:
            logger.info(m18n.n('packages_no_upgrade'))

    if not ignore_apps:
        try:
            app_upgrade(auth)
        except Exception as e:
            failure = True
            logger.warning('unable to upgrade apps: %s' % str(e))
            logger.error(m18n.n('app_upgrade_failed'))

    if not failure:
        logger.success(m18n.n('system_upgraded'))

    # Return API logs if it is an API call
    if is_api:
        return {"log": service_log('yunohost-api', number="100").values()[0]}
コード例 #6
0
ファイル: tools.py プロジェクト: Josue-T/moulinette-yunohost
def tools_upgrade(ignore_apps=False, ignore_packages=False):
    """
    Update apps & package cache, then display changelog

    Keyword arguments:
        ignore_apps -- Ignore apps upgrade
        ignore_packages -- Ignore APT packages upgrade

    """
    from yunohost.app import app_upgrade

    is_api = True if msettings.get('interface') == 'api' else False

    if not ignore_packages:
        cache = apt.Cache()
        cache.open(None)
        cache.upgrade(True)

        # If API call
        if is_api:
            critical_packages = ("moulinette", "moulinette-yunohost",
                "yunohost-admin", "yunohost-config-nginx", "ssowat", "python")
            critical_upgrades = set()

            for pkg in cache.get_changes():
                if pkg.name in critical_packages:
                    critical_upgrades.add(pkg.name)
                    # Temporarily keep package ...
                    pkg.mark_keep()
            # ... and set a hourly cron up to upgrade critical packages
            if critical_upgrades:
                msignals.display(m18n.n('packages_upgrade_critical_later')
                                    % ', '.join(critical_upgrades))
                with open('/etc/cron.d/yunohost-upgrade', 'w+') as f:
                    f.write('00 * * * * root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin apt-get install %s -y && rm -f /etc/cron.d/yunohost-upgrade' % ' '.join(critical_upgrades))

        if cache.get_changes():
            msignals.display(m18n.n('upgrading_packages'))
            try:
                # Apply APT changes
                # TODO: Logs output for the API
                cache.commit(apt.progress.text.AcquireProgress(),
                             apt.progress.base.InstallProgress())
            except Exception as e:
                logging.warning('unable to upgrade packages: %s' % str(e))
                msignals.display(m18n.n('packages_upgrade_failed'), 'error')
            else:
                msignals.display(m18n.n('done'))
        else:
            msignals.display(m18n.n('packages_no_upgrade'))

    if not ignore_apps:
        try:
            app_upgrade()
        except: pass

    msignals.display(m18n.n('system_upgraded'), 'success')

    # Return API logs if it is an API call
    if msettings.get('interface') == 'api':
        from yunohost.service import service_log
        return { "log": service_log('yunohost-api', number="100").values()[0] }