def config_func(args: Namespace): try: dstack_config = get_config() # TODO: Support non-default profiles profile = dstack_config.get_profile("default") user_info = get_user_info(profile) data = { "aws_access_key_id": get_or_ask(args, None, "aws_access_key_id", "AWS Access Key ID: ", secure=True), "aws_secret_access_key": get_or_ask(args, None, "aws_secret_access_key", "AWS Secret Access Key: ", secure=True), "aws_region": get_or_ask(args, None, "aws_region", f"Region name [{user_info['default_configuration']['aws_region']}]: ", secure=False, required=False), "artifacts_s3_bucket": get_or_ask(args, None, "artifacts_s3_bucket", "Artifacts S3 bucket [None]: ", secure=False, required=False) } response = do_post("users/aws/info") if response.status_code == 200: response_json = response.json() if response_json.get("aws_access_key_id") is None \ and response_json.get("aws_secret_access_key") is None \ and response_json.get("aws_region") is None \ and response_json.get("artifacts_s3_bucket") is None: send_aws_config_request(data) else: if args.force or confirm(f"Do you want to override the previous configuration?"): send_aws_config_request(data) else: print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")
def limit_func(args: Namespace): if args.delete: if args.force or confirm(f"Are you sure you want to delete the limit?"): try: data = { "region_name": args.region, "instance_type": args.instance_type, "purchase_type": "spot" if args.spot else "on-demand" } response = do_post("on-demand/limits/delete", data) if response.status_code == 200: print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}") if response.status_code == 400 and response.json().get("message") == "aws is not configured": sys.exit(f"Call 'dstack aws config' first") if response.status_code == 404 and response.json().get("message") == "limit not found": sys.exit(f"Limit doesn't exist") if response.status_code == 404 and response.json().get("message") == "region not found": sys.exit(f"Region is not supported") if response.status_code == 404 and response.json().get("message") == "instance type not found": sys.exit(f"Instance type is not supported") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first") else: print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}") else: try: data = { "region_name": args.region, "instance_type": args.instance_type, "purchase_type": "spot" if args.spot else "on-demand", "maximum": args.max, } response = do_post("on-demand/limits/set", data) if response.status_code == 200: print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}") if response.status_code == 400 and response.json().get("message") == "aws is not configured": sys.exit(f"Call 'dstack aws config' first") if response.status_code == 404 and response.json().get("message") == "region not found": sys.exit(f"Region is not supported") if response.status_code == 404 and response.json().get("message") == "instance type not found": sys.exit(f"Instance type is not supported") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")
def do_clear_request(): response = do_post("users/aws/clear") if response.status_code == 200: print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}") elif response.status_code == 400 and response.json().get("message") == "non-cancelled requests": sys.exit(f"Call 'dstack autoscale clear' first") else: response.raise_for_status()
def status_func(_: Namespace): try: response = do_post("on-demand/settings") if response.status_code == 200: response_json = response.json() print(f"{colorama.Fore.LIGHTMAGENTA_EX}Enabled{colorama.Fore.RESET}: " + ( f"{colorama.Fore.LIGHTRED_EX}No{colorama.Fore.RESET}" if response_json.get( "enabled") is False else f"{colorama.Fore.LIGHTGREEN_EX}Yes{colorama.Fore.RESET}")) else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")
def enable_func(_: Namespace): try: data = { "enabled": True } response = do_post("on-demand/settings/update", data) if response.status_code == 200: print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")
def disable_func(args: Namespace): if args.force or confirm(f"Are you sure you want to disable on-demand runners?"): try: data = { "enabled": False } response = do_post("on-demand/settings/update", data) if response.status_code == 200: print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first") else: print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}")
def limits_func(args: Namespace): if args.delete_all: if args.force or confirm(f"Are you sure you want to delete all limits?"): try: response = do_post("on-demand/limits/clear") if response.status_code == 200: print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first") else: print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}") else: try: response = do_get("on-demand/limits/query") if response.status_code == 200: table_headers = [ f"{colorama.Fore.LIGHTMAGENTA_EX}REGION{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}INSTANCE TYPE{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}CPU{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}MEMORY{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}GPU{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}PURCHASE TYPE{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}MAXIMUM{colorama.Fore.RESET}", f"{colorama.Fore.LIGHTMAGENTA_EX}STATUS{colorama.Fore.RESET}" ] table_rows = [] for limit in response.json()["limits"]: availability_issues_at = pretty_date( round(limit["availability_issues_at"] / 1000)) if limit.get("availability_issues_at") else "" table_rows.append([ limit["region_name"], limit["instance_type"], limit["resources"]["cpu"]["count"] if limit.get("resources") else "", str(int(limit["resources"]["memory_mib"] / 1024)) + "GiB" if limit.get("resources") else "", __pretty_print_gpu_resources(limit["resources"]) if limit.get("resources") else "", limit["purchase_type"], limit["maximum"], f"{colorama.Fore.RED}{'No capacity ' + availability_issues_at}{colorama.Fore.RESET}" if limit.get( "availability_issues_message") else f"{colorama.Fore.GREEN}OK{colorama.Fore.RESET}" ]) print(tabulate(table_rows, headers=table_headers, tablefmt="plain")) else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")
def info_func(_: Namespace): try: response = do_post("users/aws/info") if response.status_code == 200: response_json = response.json() print(f"{colorama.Fore.LIGHTMAGENTA_EX}AWS Access Key ID{colorama.Fore.RESET}: " + ( sensitive(response_json.get("aws_access_key_id")) or "None")) print(f"{colorama.Fore.LIGHTMAGENTA_EX}AWS Secret Access Key{colorama.Fore.RESET}: " + ( sensitive(response_json.get("aws_secret_access_key")) or "None")) print(f"{colorama.Fore.LIGHTMAGENTA_EX}Region name{colorama.Fore.RESET}: " + ( response_json.get("aws_region") or "None")) print(f"{colorama.Fore.LIGHTMAGENTA_EX}Artifacts S3 bucket{colorama.Fore.RESET}: " + ( response_json.get("artifacts_s3_bucket") or "<none>")) else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")
def clear_func(args: Namespace): try: response = do_post("users/aws/info") if response.status_code == 200: response_json = response.json() if response_json.get("aws_access_key_id") is None \ and response_json.get("aws_secret_access_key") is None \ and response_json.get("aws_region") is None \ and response_json.get("artifacts_s3_bucket") is None: do_clear_request() else: if args.force or confirm(f"Do you want to override the previous configuration?"): do_clear_request() else: print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}") else: response.raise_for_status() except ConfigurationError: sys.exit(f"Call 'dstack config' first")