def read_deployment_config(filepaths): from polyaxon.deploy import reader if not filepaths: return None filepaths = to_list(filepaths) for filepath in filepaths: if not os.path.isfile(filepath): Printer.print_error("`{}` must be a valid file".format(filepath), sys_exit=True) try: deployment_config = reader.read(filepaths) return deployment_config except Exception as e: handle_cli_error(e, message="Polyaxon deployment file is not valid.", sys_exit=True)
def upgrade_on_kubernetes(self): args = ["upgrade", self.k8s_name] if self.manager_path: args += [self.manager_path] else: args += [self.k8s_chart] if self.filepath: args += ["-f", self.filepath] if self.deployment_version: args += ["--version", self.deployment_version] args += ["--namespace={}".format(self.deployment_namespace)] if self.dry_run: args += ["--debug", "--dry-run"] click.echo("Running upgrade command ...") stdout = self.helm.execute(args=args, stream=settings.CLIENT_CONFIG.debug) click.echo(stdout) Printer.print_success("Deployment upgraded.")
def dashboard(ctx, _project, yes, url): """Open this operation's dashboard details in browser.""" owner, project_name = get_project_or_local(_project or ctx.obj.get("project"), is_cli=True) project_url = get_dashboard_url( subpath="{}/{}".format(owner, project_name)) if url: Printer.print_header( "The dashboard is available at: {}".format(project_url)) sys.exit(0) if not yes: click.confirm( "Dashboard page will now open in your browser. Continue?", abort=True, default=True, ) click.launch(project_url)
def get_run_or_local(run_uuid=None, is_cli: bool = False): if run_uuid: return run_uuid if is_cli: return RunConfigManager.get_config_or_raise().uuid try: run = RunConfigManager.get_config() except TypeError: Printer.print_error( "Found an invalid run config or run config cache, " "if you are using Polyaxon CLI please run: " "`polyaxon config purge --cache-only`", sys_exit=True, ) if run: return run.uuid return None
def bookmark(ctx): """Bookmark project. Uses [Caching](/references/polyaxon-cli/#caching) """ owner, project_name = get_project_or_local(ctx.obj.get("project")) try: polyaxon_client = PolyaxonClient() polyaxon_client.projects_v1.bookmark_project(owner, project_name) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not bookmark project `{}/{}`.".format( owner, project_name)) sys.exit(1) Printer.print_success("Project `{}/{}` is bookmarked.".format( owner, project_name))
def create(ctx, name, owner, description, tags, private, init): """Create a new project. Uses /docs/core/cli/#caching Example: \b $ polyaxon project create --name=cats-vs-dogs --description="Image Classification with DL" """ owner = owner or settings.AUTH_CONFIG.username if not owner and (not settings.CLI_CONFIG or settings.CLI_CONFIG.is_ce): owner = DEFAULT tags = validate_tags(tags) if not owner: Printer.print_error( "Please login first or provide a valid owner --owner. " "`polyaxon login --help`") sys.exit(1) try: project_config = V1Project(name=name, description=description, tags=tags, is_public=not private) polyaxon_client = ProjectClient(owner=owner) _project = polyaxon_client.create(project_config) config = polyaxon_client.client.sanitize_for_serialization(_project) cache.cache(config_manager=ProjectManager, config=config) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not create project `{}`.".format(name)) sys.exit(1) Printer.print_success("Project `{}` was created successfully.".format( _project.name)) click.echo("You can view this project on Polyaxon UI: {}".format( get_dashboard_url(subpath="{}/{}".format(owner, _project.name)))) if init: ctx.obj = {} ctx.invoke(init_project, project=name)
def run( ctx, name, owner, project_name, description, tags, specification, upload, log, can_upload, ): def create_run(): click.echo("Creating a run.") run = V1Run(content=specification.config_dump) try: polyaxon_client = PolyaxonClient() response = polyaxon_client.runs_v1.create_run( owner, project_name, run) cache.cache(config_manager=RunManager, response=response) Printer.print_success("A new run `{}` was created".format( response.uuid)) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not create a run.") sys.exit(1) # Check if we need to upload if upload: if can_upload: Printer.print_error( "Uploading is not supported when switching project context!") click.echo( "Please, either omit the `-u` option or `-p` / `--project=` option." ) sys.exit(1) ctx.invoke(upload_cmd, sync=False) create_run() logs_cmd = run_logs # Check if we need to invoke logs if log and logs_cmd: ctx.obj = {"project": "{}/{}".format(owner, project_name)} ctx.invoke(logs_cmd)
def ls(owner, query, sort, limit, offset): """List projects. Uses /docs/core/cli/#caching """ owner = owner or get_local_owner(is_cli=True) if not owner: Printer.print_error("Please provide a valid owner: --owner/-o.") sys.exit(1) try: polyaxon_client = ProjectClient(owner=owner) response = polyaxon_client.list(limit=limit, offset=offset, query=query, sort=sort) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not get list of projects.") sys.exit(1) meta = get_meta_response(response) if meta: Printer.print_header("Projects for owner {}".format(owner)) Printer.print_header("Navigation:") dict_tabulate(meta) else: Printer.print_header("No projects found for owner {}".format(owner)) objects = list_dicts_to_tabulate( [o.to_dict() for o in response.results], humanize_values=True, exclude_attrs=[ "uuid", "readme", "description", "owner", "user_email", "role", "settings", ], ) if objects: Printer.print_header("Projects:") dict_tabulate(objects, is_list_dict=True)
def update(ctx, name, description, private): """Update project. Uses /docs/core/cli/#caching Example: \b $ polyaxon update foobar --description="Image Classification with DL using TensorFlow" \b $ polyaxon update mike1/foobar --description="Image Classification with DL using TensorFlow" \b $ polyaxon update --tags="foo, bar" """ owner, project_name = get_project_or_local(ctx.obj.get("project"), is_cli=True) update_dict = {} if name: update_dict["name"] = name if description: update_dict["description"] = description if private is not None: update_dict["is_public"] = not private if not update_dict: Printer.print_warning( "No argument was provided to update the project.") sys.exit(1) try: polyaxon_client = ProjectClient(owner=owner) response = polyaxon_client.update(update_dict) except (ApiException, HTTPError) as e: handle_cli_error( e, message="Could not update project `{}`.".format(project_name)) sys.exit(1) Printer.print_success("Project updated.") get_project_details(response)
def get_compatibility(key: str, service: str, version: str, is_cli: bool = True): if not key: installation = CliConfigManager.get_value("installation") or {} key = installation.get("key") or uuid.uuid4().hex try: version = clean_version_for_compatibility(version) except Exception as e: CliConfigManager.reset(last_check=now()) if is_cli: handle_cli_error( e, message="Could parse the version {}.".format(version), ) polyaxon_client = PolyaxonClient(config=ClientConfig(), token=NO_AUTH) try: return polyaxon_client.versions_v1.get_compatibility( uuid=key, service=service, version=version, _request_timeout=15, ) except ApiException as e: if e.status == 403 and is_cli: session_expired() CliConfigManager.reset(last_check=now()) if is_cli: handle_cli_error( e, message="Could not reach the compatibility API.", ) except HTTPError: CliConfigManager.reset(last_check=now()) if is_cli: Printer.print_error( "Could not connect to remote server to fetch compatibility versions.", ) except Exception as e: CliConfigManager.reset(last_check=now()) if is_cli: Printer.print_error( "Unexpected error %s, " "could not connect to remote server to fetch compatibility versions." % e, )
def create_run(is_manged: bool = True): try: response = polyaxon_client.create( name=name, description=description, tags=tags, content=op_spec, is_managed=is_manged, ) Printer.print_success("A new run `{}` was created".format( response.uuid)) if not eager: cache_run(response) click.echo("You can view this run on Polyaxon UI: {}".format( get_dashboard_url(subpath="{}/{}/runs/{}".format( owner, project_name, response.uuid)))) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not create a run.") sys.exit(1)
def check_cli_version(config, is_cli: bool = True): """Check if the current cli version satisfies the server requirements""" from distutils.version import LooseVersion # pylint:disable=import-error min_version = clean_version_for_check(config.min_version) latest_version = clean_version_for_check(config.latest_version) current_version = clean_version_for_check(config.current_version) if not min_version or not latest_version or not current_version: if is_cli: Printer.print_error( "Could not get the min/latest versions from compatibility API.", sys_exit=True, ) else: return if LooseVersion(current_version) < LooseVersion(min_version): click.echo( "Your version of Polyaxon CLI ({}) is no longer supported.".format( config.current_version)) if click.confirm("Do you want to upgrade to " "version {} now?".format(config.latest_version)): pip_upgrade() sys.exit(0) else: indentation.puts("Your can manually run:") with indentation.indent(4): indentation.puts("pip install -U polyaxon") indentation.puts("to upgrade to the latest version `{}`".format( config.latest_version)) sys.exit(0) elif LooseVersion(current_version) < LooseVersion(latest_version): indentation.puts( "New version of Polyaxon CLI ({}) is now available. To upgrade run:" .format(config.latest_version)) with indentation.indent(4): indentation.puts("pip install -U polyaxon") elif LooseVersion(current_version) > LooseVersion(latest_version): indentation.puts( "Your version of CLI ({}) is ahead of the latest version " "supported by Polyaxon server ({}) on your cluster, " "and might be incompatible.".format(config.current_version, config.latest_version))
def install_on_kubernetes(self): args = ["install"] if self.manager_path: args += [self.manager_path] else: args += ["polyaxon/polyaxon"] args += ["--name=polyaxon", "--namespace=polyaxon"] if self.filepath: args += ["-f", self.filepath] if self.deployment_version: args += ["--version", self.deployment_version] if self.dry_run: args += ["--debug", "--dry-run"] click.echo("Running install command ...") stdout = self.helm.execute(args=args) click.echo(stdout) Printer.print_success("Deployment finished.")
def service(ctx, yes, external, url): """Open the operation service in browser. N.B. The operation must have a run kind service, otherwise it will raise an error. You can open the service embedded in Polyaxon UI or using the real service URL, please use the `--external` flag. """ owner, project_name, run_uuid = get_project_run_or_local( ctx.obj.get("project"), ctx.obj.get("run_uuid"), is_cli=True, ) client = RunClient(owner=owner, project=project_name, run_uuid=run_uuid) client.refresh_data() if client.run_data.kind != V1RunKind.SERVICE: Printer.print_warning("Command expected a operations of " "kind `service` received kind: {}!".format( client.run_data.kind)) sys.exit(1) dashboard_url = settings.CLIENT_CONFIG.host Printer.print_header("Waiting for running condition ...") client.wait_for_condition(statuses=[V1Statuses.RUNNING], print_status=True) client.refresh_data() namespace = client.run_data.settings.namespace run_url = "{}/{}/{}/runs/{}/service".format(dashboard_url, owner, project_name, run_uuid) service_endpoint = SERVICES_V1 if client.run_data.meta_info.get("rewrite_path", False): service_endpoint = REWRITE_SERVICES_V1 external_run_url = "{}/{}/{}/{}/{}/runs/{}/".format( dashboard_url, service_endpoint, namespace, owner, project_name, run_uuid) if url: Printer.print_header( "The service will be available at: {}".format(run_url)) Printer.print_header( "You can also view it in an external link at: {}".format( external_run_url)) sys.exit(0) if not yes: click.confirm( "Dashboard page will now open in your browser. Continue?", abort=True, default=True, ) if external: click.launch(external_run_url) sys.exit(0) click.launch(run_url)
def runs(ctx, limit, offset): """List bookmarked runs for user. Uses [Caching](/references/polyaxon-cli/#caching) Examples: \b ```bash $ polyaxon bookmark experiments ``` \b ```bash $ polyaxon bookmark -u adam experiments ``` """ user = get_username_or_local(ctx.obj.get("username")) try: params = get_query_params(limit=limit, offset=offset) polyaxon_client = PolyaxonClient() response = polyaxon_client.runs_v1.list_bookmarked_runs(user, **params) except (ApiException, HTTPError) as e: handle_cli_error( e, message="Could not get bookmarked experiments for user `{}`.".format(user), ) sys.exit(1) meta = get_meta_response(response) if meta: Printer.print_header("Bookmarked experiments for user `{}`.".format(user)) Printer.print_header("Navigation:") dict_tabulate(meta) else: Printer.print_header( "No bookmarked experiments found for user `{}`.".format(user) ) objects = [ Printer.add_status_color(o.to_light_dict(humanize_values=True)) for o in response.results ] objects = list_dicts_to_tabulate(objects) if objects: Printer.print_header("Experiments:") dict_tabulate(objects, is_list_dict=True)
def dashboard(model, version, yes, url): """Open this operation's dashboard details in browser.""" owner, model_registry, model_version, is_version = get_info(model, version) subpath = ("{}/registry/{}/versions?version={}".format( owner, model_registry, model_version) if is_version else "{}/registry/{}".format(owner, model_registry)) registry_url = get_dashboard_url(subpath=subpath) if url: Printer.print_header( "The dashboard is available at: {}".format(registry_url)) sys.exit(0) if not yes: click.confirm( "Dashboard page will now open in your browser. Continue?", abort=True, default=True, ) click.launch(registry_url)
def check_polyaxonfile( polyaxonfile=None, python_module=None, params=None, profile=None, queue=None, nocache=None, log=True, ): if not any([polyaxonfile, python_module]): polyaxonfile = PolyaxonFile.check_default_path(path=".") if not any([polyaxonfile, python_module]): polyaxonfile = "" polyaxonfile = to_list(polyaxonfile) exists = [os.path.isfile(f) for f in polyaxonfile] parsed_params = None if params: parsed_params = parse_params(params) if not any(exists) and not python_module: Printer.print_error( "Polyaxonfile is not present, " "please run {}".format(constants.INIT_COMMAND) ) sys.exit(1) if python_module: config = ConfigSpec.get_from(python_module) return config.read() try: plx_file = PolyaxonFile(polyaxonfile) plx_file = plx_file.get_op_specification( params=parsed_params, profile=profile, queue=queue, nocache=nocache ) if log: Printer.print_success("Polyaxonfile valid") return plx_file except Exception as e: handle_cli_error(e, message="Polyaxonfile is not valid.") sys.exit(1)
def whoami(): """Show current logged Polyaxon user.""" try: polyaxon_client = PolyaxonClient() user = polyaxon_client.users_v1.get_user() except ApiException as e: if e.status == 403: session_expired() sys.exit(1) handle_cli_error(e, message="Could not get the user info.") sys.exit(1) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not load user info.") sys.exit(1) response = dict_to_tabulate(user.to_dict(), exclude_attrs=["role"]) Printer.print_header("User info:") dict_tabulate(response)
def run( ctx, name: str, owner: str, project_name: str, description: str, tags: List[str], compiled_operation: V1CompiledOperation, log: bool, ): try: _run(ctx, name, owner, project_name, description, tags, compiled_operation, log) except (PolyaxonHTTPError, PolyaxonShouldExitError, PolyaxonClientException) as e: handle_cli_error(e, message="Could start local run.") sys.exit(1) except Exception as e: Printer.print_error("Could start local run.") Printer.print_error("Unexpected Error: `{}`.".format(e)) sys.exit(1)
def teardown(config_file, manager_path): """Teardown a polyaxon deployment given a config file.""" config = read_deployment_config(config_file) manager = DeployManager(config=config, filepath=config_file, manager_path=manager_path) exception = None try: if click.confirm("Would you like to execute pre-delete hooks?", default=True): manager.teardown(hooks=True) else: manager.teardown(hooks=False) except Exception as e: Printer.print_error("Polyaxon could not teardown the deployment.") exception = e if exception: Printer.print_error("Error message: {}.".format(exception))
def create_run(): click.echo("Creating a run.") body = V1OperationBody( name=name, description=description, tags=tags, content=op_spec.to_dict(dump=True), ) try: polyaxon_client = PolyaxonClient() response = polyaxon_client.runs_v1.create_run( owner, project_name, body) config = polyaxon_client.sanitize_for_serialization(response) cache.cache(config_manager=RunManager, config=config) Printer.print_success("A new run `{}` was created".format( response.uuid)) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not create a run.") sys.exit(1)
def delete(ctx): """Delete a run. Uses [Caching](/references/polyaxon-cli/#caching) Example: \b ```bash $ polyaxon runs delete ``` \b ```bash $ polyaxon runs --uid=8aac02e3a62a4f0aaa257c59da5eab80 delete # project is cached ``` \b ```bash $ polyaxon runs --project=cats-vs-dogs -id 8aac02e3a62a4f0aaa257c59da5eab80 delete ``` """ owner, project_name, run_uuid = get_project_run_or_local( ctx.obj.get("project"), ctx.obj.get("run_uuid"), is_cli=True) if not click.confirm( "Are sure you want to delete run `{}`".format(run_uuid)): click.echo("Existing without deleting the run.") sys.exit(1) try: polyaxon_client = RunClient(owner=owner, project=project_name, run_uuid=run_uuid) polyaxon_client.delete() # Purge caching RunManager.purge() except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not delete run `{}`.".format(run_uuid)) sys.exit(1) Printer.print_success("Run `{}` was delete successfully".format(run_uuid))
def dashboard(component, version, yes, url): """Open this operation's dashboard details in browser.""" owner, component_hub, component_version, is_version = get_info(component, version) subpath = ( "{}/hub/{}/versions?version={}".format(owner, component_hub, component_version) if is_version else "{}/hub/{}".format(owner, component_hub) ) hub_url = get_dashboard_url(subpath=subpath, use_cloud=settings.CLI_CONFIG.is_ce) if url: Printer.print_header("The dashboard is available at: {}".format(hub_url)) sys.exit(0) if not yes: click.confirm( "Dashboard page will now open in your browser. Continue?", abort=True, default=True, ) click.launch(hub_url)
def whoami(): """Show current logged Polyaxon Cloud or Polyaxon EE user.""" if not settings.CLI_CONFIG or settings.CLI_CONFIG.is_ce: handle_command_no_in_ce() try: polyaxon_client = PolyaxonClient() user = polyaxon_client.users_v1.get_user() except ApiException as e: if e.status == 403: session_expired() handle_cli_error(e, message="Could not get the user info.", sys_exit=True) except (ApiException, HTTPError) as e: handle_cli_error(e, message="Could not load user info.", sys_exit=True) response = dict_to_tabulate(user.to_dict(), exclude_attrs=["role"]) Printer.print_header("User info:") dict_tabulate(response)
def delete(username): """Delete a user. Example: \b ```bash $ polyaxon user delete david ``` """ try: PolyaxonClient().user.delete_user(username) except (PolyaxonHTTPError, PolyaxonShouldExitError, PolyaxonClientException) as e: handle_cli_error( e, message="Could not delete user `{}`.".format(username)) sys.exit(1) Printer.print_success( "User `{}` was deleted successfully.".format(username))
def _sync(run_uuid: str): Printer.print_header(f"Syncing offline run {uid} ...") client = RunClient(run_uuid=run_uuid, is_offline=True) try: client.sync_offline_run( load_offline_run=True, artifacts_path=offline_path_format.format(run_uuid), upload_artifacts=not no_artifacts, clean=clean, ) except ( ApiException, HTTPError, PolyaxonHTTPError, PolyaxonShouldExitError, PolyaxonClientException, ) as e: handle_cli_error( e, message="Could not sync offline run `{}`.".format(run_uuid)) sys.exit(1)
def handle_timestamp(log_line): log_search = TIMESTAMP_REGEX.search(log_line) if not log_search: return log_line if not show_timestamp: return re.sub(TIMESTAMP_REGEX, "", log_line) timestamp_info = log_search.group() return re.sub(TIMESTAMP_REGEX, Printer.add_color(timestamp_info, "white"), log_line)
def get_eager_matrix_operations( content: str, compiled_operation: V1CompiledOperation, is_cli: bool = False, ) -> List[V1Operation]: is_supported_in_eager_mode(compiled_operation) try: import numpy as np except ImportError as e: if is_cli: Printer.print_error( "numpy is required for the eager mode, " "please run 'pip install polyaxon[numpy]'", sys_exit=True, ) raise e from polyaxon.polytune.search_managers.grid_search.manager import GridSearchManager from polyaxon.polytune.search_managers.mapping.manager import MappingManager from polyaxon.polytune.search_managers.random_search.manager import ( RandomSearchManager, ) if compiled_operation.has_random_search_matrix: suggestions = RandomSearchManager( compiled_operation.matrix).get_suggestions() elif compiled_operation.has_grid_search_matrix: suggestions = GridSearchManager( compiled_operation.matrix).get_suggestions() elif compiled_operation.has_mapping_matrix: suggestions = MappingManager( compiled_operation.matrix).get_suggestions() else: raise PolyaxonSchemaError( "Received a bad configuration, eager mode not supported, " "I should not be here!") if is_cli: Printer.print_header("Creating {} operations".format(len(suggestions))) return get_ops_from_suggestions(content=content, compiled_operation=compiled_operation, suggestions=suggestions)
def handle_status(last_status: str = None): if not last_status: return {"status": None} click.echo( "{}".format( Printer.add_status_color({"status": last_status}, status_key="status")[ "status" ] ) ) return last_status
def get_project_or_local(project=None): if not project and not ProjectManager.is_initialized(): Printer.print_error( "Please provide a valid project, or init a new project. " " {}".format(constants.INIT_COMMAND) ) sys.exit(1) if project: user, project_name = get_project_info(project) else: project = ProjectManager.get_config() user, project_name = project.user, project.name if not all([user, project_name]): Printer.print_error( "Please provide a valid project, or init a new project." " {}".format(constants.INIT_COMMAND) ) sys.exit(1) return user, project_name