Ejemplo n.º 1
0
def prune_func(args: Namespace):
    try:
        dstack_config = get_config()
        repo_url, _, _, _ = load_repo_data()
        # TODO: Support non-default profiles
        profile = dstack_config.get_profile("default")
        if args.force or confirm(
                f"WARNING! This will permanently delete all untagged finished runs.\n\n"
                f"Are you sure you want to continue?"):
            headers = {"Content-Type": f"application/json; charset=utf-8"}
            if profile.token is not None:
                headers["Authorization"] = f"Bearer {profile.token}"
            data = {"repo_url": repo_url}
            data_bytes = json.dumps(data).encode("utf-8")
            response = request(method="POST",
                               url=f"{profile.server}/runs/prune",
                               data=data_bytes,
                               headers=headers,
                               verify=profile.verify)
            if response.status_code == 200:
                print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}")
            elif response.status_code == 400:
                print(response.json()["message"])
            else:
                response.raise_for_status()
        else:
            print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}")
    except InvalidGitRepositoryError:
        sys.exit(f"{os.getcwd()} is not a Git repo")
    except ConfigurationError:
        sys.exit(f"Call 'dstack config' first")
Ejemplo n.º 2
0
def untag_func(args: Namespace):
    try:
        if args.force or confirm(
                f"Are you sure you want to remove the tag from the run?"):
            dstack_config = get_config()
            # TODO: Support non-default profiles
            profile = dstack_config.get_profile("default")
            headers = {"Content-Type": f"application/json; charset=utf-8"}
            if profile.token is not None:
                headers["Authorization"] = f"Bearer {profile.token}"
            data = {"run_name": args.run_name}
            response = requests.request(method="POST",
                                        url=f"{profile.server}/runs/untag",
                                        data=json.dumps(data).encode("utf-8"),
                                        headers=headers,
                                        verify=profile.verify)
            if response.status_code == 404:
                sys.exit(f"No run '{args.run_name_or_job_id}' is found")
            elif response.status_code != 200:
                response.raise_for_status()
            else:
                print(f"{colorama.Fore.LIGHTBLACK_EX}OK{colorama.Fore.RESET}")
        else:
            print(f"{colorama.Fore.RED}Cancelled{colorama.Fore.RESET}")
    except ConfigurationError:
        sys.exit(f"Call 'dstack config' first")
Ejemplo n.º 3
0
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")
Ejemplo n.º 4
0
def remove_profile(args: Namespace):
    conf = from_yaml_file(_get_config_path(args.file))

    if args.force or confirm(
            f"Do you want to delete profile '{args.profile}'"):
        conf.remove_profile(args.profile)

    conf.save()
Ejemplo n.º 5
0
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}")
Ejemplo n.º 6
0
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")
Ejemplo n.º 7
0
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")
Ejemplo n.º 8
0
def add_or_modify_profile(args: Namespace):
    file = Path(args.file) if args.file else None
    conf = from_yaml_file(_get_config_path(file))
    profile = conf.get_profile(args.profile)

    token = get_or_ask(args, profile, "token", "Token: ", secure=True)

    if profile is None:
        profile = Profile(args.profile, token, args.server, not args.no_verify)
    elif args.force or (token != profile.token and confirm(
            f"Do you want to replace the token for the profile '{args.profile}'"
    )):
        profile.token = token

    profile.server = args.server
    profile.verify = not args.no_verify

    conf.add_or_replace_profile(profile)
    conf.save()
Ejemplo n.º 9
0
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")