Example #1
0
def install_package(
        package_name,
        package_version=None,
        service_name=None,
        options_file=None,
        options_json=None,
        wait_for_completion=False,
        timeout_sec=600,
        expected_running_tasks=0
):
    """ Install a package via the DC/OS library

        :param package_name: name of the package
        :type package_name: str
        :param package_version: version of the package (defaults to latest)
        :type package_version: str
        :param service_name: unique service name for the package
        :type service_name: str
        :param options_file: filename that has options to use and is JSON format
        :type options_file: str
        :param options_json: dict that has options to use and is JSON format
        :type options_json: dict
        :param wait_for_completion: whether or not to wait for the app's deployment to complete
        :type wait_for_completion: bool
        :param timeout_sec: number of seconds to wait for task completion
        :type timeout_sec: int
        :param expected_running_tasks: number of service tasks to check for, or zero to disable
        :type expected_task_count: int

        :return: True if installation was successful, False otherwise
        :rtype: bool
    """

    start = time.time()

    if options_file:
        options = _get_options(options_file)
    elif options_json:
        options = options_json
    else:
        options = {}

    package_manager = _get_package_manager()
    pkg = package_manager.get_package_version(package_name, package_version)

    if package_version is None:
        # Get the resolved version for logging below
        package_version = 'auto:{}'.format(pkg.version())

    if service_name is None:
        # Get the service name from the marathon template
        try:
            labels = pkg.marathon_json(options).get('labels')
            if 'DCOS_SERVICE_NAME' in labels:
                service_name = labels['DCOS_SERVICE_NAME']
        except errors.DCOSException as e:
            pass

    print('\n{}installing {} with service={} version={} options={}'.format(
        shakedown.cli.helpers.fchr('>>'), package_name, service_name, package_version, options))

    try:
        # Print pre-install notes to console log
        pre_install_notes = pkg.package_json().get('preInstallNotes')
        if pre_install_notes:
            print(pre_install_notes)

        package_manager.install_app(pkg, options, service_name)

        # Print post-install notes to console log
        post_install_notes = pkg.package_json().get('postInstallNotes')
        if post_install_notes:
            print(post_install_notes)

        # Optionally wait for the app's deployment to finish
        if wait_for_completion:
            print("\n{}waiting for {} deployment to complete...".format(
                shakedown.cli.helpers.fchr('>>'), service_name))
            if expected_running_tasks > 0 and service_name is not None:
                wait_for_service_tasks_running(service_name, expected_running_tasks, timeout_sec)

            app_id = pkg.marathon_json(options).get('id')
            shakedown.deployment_wait(timeout_sec, app_id)
            print('\n{}install completed after {}\n'.format(
                shakedown.cli.helpers.fchr('>>'), pretty_duration(time.time() - start)))
        else:
            print('\n{}install started after {}\n'.format(
                shakedown.cli.helpers.fchr('>>'), pretty_duration(time.time() - start)))
    except errors.DCOSException as e:
        print('\n{}{}'.format(
            shakedown.cli.helpers.fchr('>>'), e))

    # Install subcommands (if defined)
    if pkg.cli_definition():
        print("{}installing CLI commands for package '{}'".format(
            shakedown.cli.helpers.fchr('>>'), package_name))
        subcommand.install(pkg)

    return True
Example #2
0
def _install(package_name, package_version, options_path, app_id, cli, global_,
             app, yes):
    """Install the specified package.

    :param package_name: the package to install
    :type package_name: str
    :param package_version: package version to install
    :type package_version: str
    :param options_path: path to file containing option values
    :type options_path: str
    :param app_id: app ID for installation of this package
    :type app_id: str
    :param cli: indicates if the cli should be installed
    :type cli: bool
    :param global_: indicates that the cli should be installed globally
    :type global_: bool
    :param app: indicate if the application should be installed
    :type app: bool
    :param yes: automatically assume yes to all prompts
    :type yes: bool
    :returns: process status
    :rtype: int
    """

    if cli is False and app is False:
        # Install both if neither flag is specified
        cli = app = True

    # Fail early if options file isn't valid
    user_options = util.read_file_json(options_path)

    package_manager = get_package_manager()
    pkg = package_manager.get_package_version(package_name, package_version)

    pkg_json = pkg.package_json()

    selected = pkg_json.get('selected')
    if selected:
        link = ('https://mesosphere.com/'
                'catalog-terms-conditions/#certified-services')
    else:
        link = ('https://mesosphere.com/'
                'catalog-terms-conditions/#community-services')
    emitter.publish(('By Deploying, you agree to '
                     'the Terms and Conditions ' + link))

    pre_install_notes = pkg_json.get('preInstallNotes')
    if app and pre_install_notes:
        emitter.publish(pre_install_notes)

    if not confirm('Continue installing?', yes):
        emitter.publish('Exiting installation.')
        return 0

    if app and pkg.marathon_template():

        # Even though package installation will check for template rendering
        # errors, we want to fail early, before trying to install.
        pkg.options(user_options)

        # Install in Marathon
        msg = 'Installing Marathon app for package [{}] version [{}]'.format(
            pkg.name(), pkg.version())
        if app_id is not None:
            msg += ' with app id [{}]'.format(app_id)

        emitter.publish(msg)

        if app_id is not None:
            msg = "Usage of --app-id is deprecated. Use --options instead " \
                  "and specify a file that contains [service.name] property"
            emitter.publish(msg)

        package_manager.install_app(pkg, user_options, app_id)

    if cli and pkg.cli_definition():
        # Install subcommand
        msg = 'Installing CLI subcommand for package [{}] version [{}]'.format(
            pkg.name(), pkg.version())
        emitter.publish(msg)

        subcommand.install(pkg, global_)

        subcommand_paths = subcommand.get_package_commands(package_name)
        new_commands = [
            os.path.basename(p).replace('-', ' ', 1) for p in subcommand_paths
        ]

        if new_commands:
            commands = ', '.join(new_commands)
            plural = "s" if len(new_commands) > 1 else ""
            emitter.publish("New command{} available: {}".format(
                plural, commands))

    post_install_notes = pkg_json.get('postInstallNotes')
    if app and post_install_notes:
        emitter.publish(post_install_notes)

    return 0
Example #3
0
def _install(package_name, package_version, options_path, app_id, cli, app,
             yes):
    """Install the specified package.

    :param package_name: the package to install
    :type package_name: str
    :param package_version: package version to install
    :type package_version: str
    :param options_path: path to file containing option values
    :type options_path: str
    :param app_id: app ID for installation of this package
    :type app_id: str
    :param cli: indicates if the cli should be installed
    :type cli: bool
    :param app: indicate if the application should be installed
    :type app: bool
    :param yes: automatically assume yes to all prompts
    :type yes: bool
    :returns: process status
    :rtype: int
    """

    if cli is False and app is False:
        # Install both if neither flag is specified
        cli = app = True

    config = util.get_config()

    pkg = package.resolve_package(package_name, config)
    if pkg is None:
        msg = "Package [{}] not found\n".format(package_name) + \
              "You may need to run 'dcos package update' to update your " + \
              "repositories"
        raise DCOSException(msg)

    pkg_revision = pkg.latest_package_revision(package_version)
    if pkg_revision is None:
        if package_version is not None:
            msg = "Version {} of package [{}] is not available".format(
                package_version, package_name)
        else:
            msg = "Package [{}] not available".format(package_name)
        raise DCOSException(msg)

    user_options = _user_options(options_path)

    pkg_json = pkg.package_json(pkg_revision)
    pre_install_notes = pkg_json.get('preInstallNotes')
    if pre_install_notes:
        emitter.publish(pre_install_notes)
        if not _confirm('Continue installing?', yes):
            emitter.publish('Exiting installation.')
            return 0

    options = pkg.options(pkg_revision, user_options)

    revision_map = pkg.package_revisions_map()
    package_version = revision_map.get(pkg_revision)

    if app and pkg.has_marathon_definition(pkg_revision):
        # Install in Marathon
        msg = 'Installing Marathon app for package [{}] version [{}]'.format(
            pkg.name(), package_version)
        if app_id is not None:
            msg += ' with app id [{}]'.format(app_id)

        emitter.publish(msg)

        init_client = marathon.create_client(config)

        package.install_app(
            pkg,
            pkg_revision,
            init_client,
            options,
            app_id)

    if cli and pkg.has_command_definition(pkg_revision):
        # Install subcommand
        msg = 'Installing CLI subcommand for package [{}] version [{}]'.format(
            pkg.name(), package_version)
        emitter.publish(msg)

        subcommand.install(pkg, pkg_revision, options)

        subcommand_paths = subcommand.get_package_commands(package_name)
        new_commands = [os.path.basename(p).replace('-', ' ', 1)
                        for p in subcommand_paths]

        if new_commands:
            commands = ', '.join(new_commands)
            plural = "s" if len(new_commands) > 1 else ""
            emitter.publish("New command{} available: {}".format(plural,
                                                                 commands))

    post_install_notes = pkg_json.get('postInstallNotes')
    if post_install_notes:
        emitter.publish(post_install_notes)

    return 0
Example #4
0
def _install(package_name, package_version, options_path, app_id, cli, app,
             yes):
    """Install the specified package.

    :param package_name: the package to install
    :type package_name: str
    :param package_version: package version to install
    :type package_version: str
    :param options_path: path to file containing option values
    :type options_path: str
    :param app_id: app ID for installation of this package
    :type app_id: str
    :param cli: indicates if the cli should be installed
    :type cli: bool
    :param app: indicate if the application should be installed
    :type app: bool
    :param yes: automatically assume yes to all prompts
    :type yes: bool
    :returns: process status
    :rtype: int
    """

    if cli is False and app is False:
        # Install both if neither flag is specified
        cli = app = True

    # Expand ~ in the options file path
    if options_path:
        options_path = os.path.expanduser(options_path)
    user_options = _user_options(options_path)

    package_manager = _get_package_manager()
    pkg = package_manager.get_package_version(package_name, package_version)

    pkg_json = pkg.package_json()
    pre_install_notes = pkg_json.get('preInstallNotes')
    if app and pre_install_notes:
        emitter.publish(pre_install_notes)
        if not _confirm('Continue installing?', yes):
            emitter.publish('Exiting installation.')
            return 0

    # render options before start installation
    options = pkg.options(user_options)

    if app and pkg.has_mustache_definition():

        # Install in Marathon
        msg = 'Installing Marathon app for package [{}] version [{}]'.format(
            pkg.name(), pkg.version())
        if app_id is not None:
            msg += ' with app id [{}]'.format(app_id)

        emitter.publish(msg)

        package_manager.install_app(pkg, options, app_id)

    if cli and pkg.has_command_definition():
        # Install subcommand
        msg = 'Installing CLI subcommand for package [{}] version [{}]'.format(
            pkg.name(), pkg.version())
        emitter.publish(msg)

        subcommand.install(pkg, pkg.options(user_options))

        subcommand_paths = subcommand.get_package_commands(package_name)
        new_commands = [
            os.path.basename(p).replace('-', ' ', 1) for p in subcommand_paths
        ]

        if new_commands:
            commands = ', '.join(new_commands)
            plural = "s" if len(new_commands) > 1 else ""
            emitter.publish("New command{} available: {}".format(
                plural, commands))

    post_install_notes = pkg_json.get('postInstallNotes')
    if app and post_install_notes:
        emitter.publish(post_install_notes)

    return 0
Example #5
0
def install_package(
        package_name,
        package_version=None,
        service_name=None,
        options_file=None,
        options_json=None,
        wait_for_completion=False,
        timeout_sec=600,
        expected_running_tasks=0
):
    """ Install a package via the DC/OS library

        :param package_name: name of the package
        :type package_name: str
        :param package_version: version of the package (defaults to latest)
        :type package_version: str
        :param service_name: unique service name for the package
        :type service_name: str
        :param options_file: filename that has options to use and is JSON format
        :type options_file: str
        :param options_json: dict that has options to use and is JSON format
        :type options_json: dict
        :param wait_for_completion: whether or not to wait for the app's deployment to complete
        :type wait_for_completion: bool
        :param timeout_sec: number of seconds to wait for task completion
        :type timeout_sec: int
        :param expected_running_tasks: number of service tasks to check for, or zero to disable
        :type expected_task_count: int

        :return: True if installation was successful, False otherwise
        :rtype: bool
    """

    start = time.time()

    if options_file:
        options = _get_options(options_file)
    elif options_json:
        options = options_json
    else:
        options = {}

    package_manager = _get_package_manager()
    pkg = package_manager.get_package_version(package_name, package_version)

    if package_version is None:
        # Get the resolved version for logging below
        package_version = 'auto:{}'.format(pkg.version())

    if service_name is None:
        # Get the service name from the marathon template
        try:
            labels = pkg.marathon_json(options).get('labels')
            if 'DCOS_SERVICE_NAME' in labels:
                service_name = labels['DCOS_SERVICE_NAME']
        except errors.DCOSException as e:
            pass

    print('\n{}installing {} with service={} version={} options={}'.format(
        shakedown.cli.helpers.fchr('>>'), package_name, service_name, package_version, options))

    try:
        # Print pre-install notes to console log
        pre_install_notes = pkg.package_json().get('preInstallNotes')
        if pre_install_notes:
            print(pre_install_notes)

        package_manager.install_app(pkg, options, service_name)

        # Print post-install notes to console log
        post_install_notes = pkg.package_json().get('postInstallNotes')
        if post_install_notes:
            print(post_install_notes)

        # Optionally wait for the app's deployment to finish
        if wait_for_completion:
            print("\n{}waiting for {} deployment to complete...".format(
                shakedown.cli.helpers.fchr('>>'), service_name))
            if expected_running_tasks > 0 and service_name is not None:
                wait_for_service_tasks_running(service_name, expected_running_tasks, timeout_sec)

            app_id = pkg.marathon_json(options).get('id')
            shakedown.deployment_wait(timeout_sec, app_id)
            print('\n{}install completed after {}\n'.format(
                shakedown.cli.helpers.fchr('>>'), pretty_duration(time.time() - start)))
        else:
            print('\n{}install started after {}\n'.format(
                shakedown.cli.helpers.fchr('>>'), pretty_duration(time.time() - start)))
    except errors.DCOSException as e:
        print('\n{}{}'.format(
            shakedown.cli.helpers.fchr('>>'), e))

    # Install subcommands (if defined)
    if pkg.cli_definition():
        print("{}installing CLI commands for package '{}'".format(
            shakedown.cli.helpers.fchr('>>'), package_name))
        subcommand.install(pkg)

    return True
Example #6
0
def _install(package_name, package_version, options_path, app_id, cli, app,
             yes):
    """Install the specified package.

    :param package_name: the package to install
    :type package_name: str
    :param package_version: package version to install
    :type package_version: str
    :param options_path: path to file containing option values
    :type options_path: str
    :param app_id: app ID for installation of this package
    :type app_id: str
    :param cli: indicates if the cli should be installed
    :type cli: bool
    :param app: indicate if the application should be installed
    :type app: bool
    :param yes: automatically assume yes to all prompts
    :type yes: bool
    :returns: process status
    :rtype: int
    """

    if cli is False and app is False:
        # Install both if neither flag is specified
        cli = app = True

    # Expand ~ in the options file path
    if options_path:
        options_path = os.path.expanduser(options_path)
    user_options = _user_options(options_path)

    package_manager = _get_package_manager()
    pkg = package_manager.get_package_version(package_name, package_version)

    pkg_json = pkg.package_json()
    pre_install_notes = pkg_json.get('preInstallNotes')
    if app and pre_install_notes:
        emitter.publish(pre_install_notes)
        if not _confirm('Continue installing?', yes):
            emitter.publish('Exiting installation.')
            return 0

    if app and pkg.has_mustache_definition():

        # render options before start installation
        options = pkg.options(user_options)

        # Install in Marathon
        msg = 'Installing Marathon app for package [{}] version [{}]'.format(
            pkg.name(), pkg.version())
        if app_id is not None:
            msg += ' with app id [{}]'.format(app_id)

        emitter.publish(msg)

        package_manager.install_app(
            pkg,
            options,
            app_id)

    if cli and pkg.has_cli_definition():
        # Install subcommand
        msg = 'Installing CLI subcommand for package [{}] version [{}]'.format(
            pkg.name(), pkg.version())
        emitter.publish(msg)

        subcommand.install(pkg)

        subcommand_paths = subcommand.get_package_commands(package_name)
        new_commands = [os.path.basename(p).replace('-', ' ', 1)
                        for p in subcommand_paths]

        if new_commands:
            commands = ', '.join(new_commands)
            plural = "s" if len(new_commands) > 1 else ""
            emitter.publish("New command{} available: {}".format(plural,
                                                                 commands))

    post_install_notes = pkg_json.get('postInstallNotes')
    if app and post_install_notes:
        emitter.publish(post_install_notes)

    return 0
Example #7
0
def _install(package_name, package_version, options_path, app_id, cli, app,
             yes):
    """Install the specified package.

    :param package_name: the package to install
    :type package_name: str
    :param package_version: package version to install
    :type package_version: str
    :param options_path: path to file containing option values
    :type options_path: str
    :param app_id: app ID for installation of this package
    :type app_id: str
    :param cli: indicates if the cli should be installed
    :type cli: bool
    :param app: indicate if the application should be installed
    :type app: bool
    :param yes: automatically assume yes to all prompts
    :type yes: bool
    :returns: process status
    :rtype: int
    """

    if cli is False and app is False:
        # Install both if neither flag is specified
        cli = app = True

    config = util.get_config()

    pkg = package.resolve_package(package_name, config)
    if pkg is None:
        msg = "Package [{}] not found\n".format(package_name) + \
              "You may need to run 'dcos package update' to update your " + \
              "repositories"
        raise DCOSException(msg)

    pkg_revision = pkg.latest_package_revision(package_version)
    if pkg_revision is None:
        if package_version is not None:
            msg = "Version {} of package [{}] is not available".format(
                package_version, package_name)
        else:
            msg = "Package [{}] not available".format(package_name)
        raise DCOSException(msg)

    user_options = _user_options(options_path)

    pkg_json = pkg.package_json(pkg_revision)
    pre_install_notes = pkg_json.get('preInstallNotes')
    if pre_install_notes:
        emitter.publish(pre_install_notes)
        if not _confirm('Continue installing?', yes):
            emitter.publish('Exiting installation.')
            return 0

    options = pkg.options(pkg_revision, user_options)

    revision_map = pkg.package_revisions_map()
    package_version = revision_map.get(pkg_revision)

    if app and (pkg.has_marathon_definition(pkg_revision)
                or pkg.has_marathon_mustache_definition(pkg_revision)):
        # Install in Marathon
        msg = 'Installing Marathon app for package [{}] version [{}]'.format(
            pkg.name(), package_version)
        if app_id is not None:
            msg += ' with app id [{}]'.format(app_id)

        emitter.publish(msg)

        init_client = marathon.create_client(config)

        package.install_app(pkg, pkg_revision, init_client, options, app_id)

    if cli and pkg.has_command_definition(pkg_revision):
        # Install subcommand
        msg = 'Installing CLI subcommand for package [{}] version [{}]'.format(
            pkg.name(), package_version)
        emitter.publish(msg)

        subcommand.install(pkg, pkg_revision, options)

        subcommand_paths = subcommand.get_package_commands(package_name)
        new_commands = [
            os.path.basename(p).replace('-', ' ', 1) for p in subcommand_paths
        ]

        if new_commands:
            commands = ', '.join(new_commands)
            plural = "s" if len(new_commands) > 1 else ""
            emitter.publish("New command{} available: {}".format(
                plural, commands))

    post_install_notes = pkg_json.get('postInstallNotes')
    if post_install_notes:
        emitter.publish(post_install_notes)

    return 0
Example #8
0
def install_package(package_name,
                    package_version=None,
                    app_id=None,
                    options_file=None,
                    wait_for_completion=False,
                    timeout_sec=600):
    """ Install a package via the DC/OS library

        :param package_name: name of the package
        :type package_name: str
        :param package_version: version of the package (defaults to latest)
        :type package_version: str
        :param app_id: unique app_id for the package
        :type app_id: str
        :param options_file: filename that has options to use and is JSON format
        :type options_file: str
        :param wait_for_completion: whether or not to wait for task completion before returning
        :type wait_for_completion: bool
        :param timeout_sec: number of seconds to wait for task completion
        :type timeout_sec: int

        :return: True if installation was successful, False otherwise
        :rtype: bool
    """

    options = _get_options(options_file)
    cosmos = _get_cosmos()
    pkg = cosmos.get_package_version(package_name, package_version)

    # Install subcommands (if defined)
    if pkg.has_cli_definition():
        print("\n{}installing CLI commands for package '{}'\n".format(
            shakedown.cli.helpers.fchr('>>'), package_name))
        subcommand.install(pkg)

    print("\n{}installing package '{}'\n".format(
        shakedown.cli.helpers.fchr('>>'), package_name))

    # Print pre-install notes to console log
    pre_install_notes = pkg.package_json().get('preInstallNotes')
    if pre_install_notes:
        print(pre_install_notes)

    cosmos.install_app(pkg, options, app_id)

    # Print post-install notes to console log
    post_install_notes = pkg.package_json().get('postInstallNotes')
    if post_install_notes:
        print(post_install_notes)

    # Optionally wait for the service to register as a framework
    if wait_for_completion:
        now = time.time()
        future = now + timeout_sec

        while now < future:
            if shakedown.get_service(package_name):
                return True

            time.sleep(1)
            now = time.time()

        return False

    return True
Example #9
0
def _install(package_name, options_path, app_id, cli, app, yes):
    """Install the specified package.

    :param package_name: the package to install
    :type package_name: str
    :param options_path: path to file containing option values
    :type options_path: str
    :param app_id: app ID for installation of this package
    :type app_id: str
    :param cli: indicates if the cli should be installed
    :type cli: bool
    :param app: indicate if the application should be installed
    :type app: bool
    :param yes: automatically assume yes to all prompts
    :type yes: bool
    :returns: process status
    :rtype: int
    """

    if cli is False and app is False:
        # Install both if neither flag is specified
        cli = app = True

    config = util.get_config()

    pkg = package.resolve_package(package_name, config)
    if pkg is None:
        msg = "Package [{}] not found\n".format(package_name) + \
              "You may need to run 'dcos package update' to update your " + \
              "repositories"
        raise DCOSException(msg)

    # TODO(CD): Make package version to install configurable
    pkg_version = pkg.latest_version()

    pre_install_notes = pkg.package_json(pkg_version).get('preInstallNotes')
    if pre_install_notes:
        emitter.publish(pre_install_notes)
        if not _confirm('Continue installing?', yes):
            emitter.publish('Exiting installation.')
            return 0

    user_options = _user_options(options_path)

    options = pkg.options(pkg_version, user_options)

    if app and pkg.has_marathon_definition(pkg_version):
        # Install in Marathon
        version_map = pkg.software_versions()
        sw_version = version_map.get(pkg_version, '?')

        message = 'Installing package [{}] version [{}]'.format(
            pkg.name(), sw_version)
        if app_id is not None:
            message += ' with app id [{}]'.format(app_id)

        emitter.publish(message)

        init_client = marathon.create_client(config)

        package.install_app(
            pkg,
            pkg_version,
            init_client,
            options,
            app_id)

    if cli and pkg.has_command_definition(pkg_version):
        # Install subcommand
        emitter.publish('Installing CLI subcommand for package [{}]'.format(
            pkg.name()))

        subcommand.install(pkg, pkg_version, options)

    post_install_notes = pkg.package_json(pkg_version).get('postInstallNotes')
    if post_install_notes:
        emitter.publish(post_install_notes)

    return 0