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
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
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
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
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
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
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
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