Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 119 additions & 64 deletions vast.py
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,72 @@ def validate_portal_config(json_blob):
else:
json_blob['env']['PORTAL_CONFIG'] = "|".join(filtered_config)

def create_instance(id, args):
if args.onstart:
with open(args.onstart, "r") as reader:
args.onstart_cmd = reader.read()
if args.onstart_cmd is None:
args.onstart_cmd = args.entrypoint

runtype = None
json_blob ={
"client_id": "me",
"image": args.image,
"env" : parse_env(args.env),
"price": args.bid_price,
"disk": args.disk,
"label": args.label,
"extra": args.extra,
"onstart": args.onstart_cmd,
"image_login": args.login,
"python_utf8": args.python_utf8,
"lang_utf8": args.lang_utf8,
"use_jupyter_lab": args.jupyter_lab,
"jupyter_dir": args.jupyter_dir,
"force": args.force,
"cancel_unavail": args.cancel_unavail,
"template_hash_id" : args.template_hash,
"user": args.user
}

if args.create_volume or args.link_volume:
volume_info = validate_volume_params(args)
json_blob["volume_info"] = volume_info

if args.template_hash is None:
runtype = get_runtype(args)
if runtype == 1:
return 1
json_blob["runtype"] = runtype

if (args.args != None):
json_blob["args"] = args.args

if "PORTAL_CONFIG" in json_blob["env"]:
validate_portal_config(json_blob)

r = None
if isinstance(id, list):
url = apiurl(args, "/asks/bulk/")
json_blob["ids"] = id
r = http_post(args, url, headers=headers,json=json_blob)
else:
url = apiurl(args, "/asks/{id}/".format(id=id))
r = http_put(args, url, headers=headers,json=json_blob)

if (args.explain):
print("request json: ")
print(json_blob)
r.raise_for_status()
if args.raw:
return r
else:
try:
print("Started. {}".format(r.json()))
except requests.exceptions.JSONDecodeError:
print("Started. (status {})".format(r.status_code))
return True

@parser.command(
argument("id", help="id of instance type to launch (returned from search offers)", type=int),
argument("--template_hash", help="Create instance from template info", type=str),
Expand Down Expand Up @@ -2413,26 +2479,26 @@ def validate_portal_config(json_blob):
argument("--volume-size", help="Size of the volume to create in GB. Only usable with --create-volume (default 15GB)", type=int),
argument("--mount-path", help="The path to the volume from within the new instance container. e.g. /root/volume", type=str),
argument("--volume-label", help="(optional) A name to give the new volume. Only usable with --create-volume", type=str),

usage="vastai create instance ID [OPTIONS] [--args ...]",
help="Create a new instance",
epilog=deindent("""
Performs the same action as pressing the "RENT" button on the website at https://console.vast.ai/create/
Performs the same action as pressing the "RENT" button on the website at https://console.vast.ai/create/
Creates an instance from an offer ID (which is returned from "search offers"). Each offer ID can only be used to create one instance.
Besides the offer ID, you must pass in an '--image' argument as a minimum.

If you use args/entrypoint launch mode, we create a container from your image as is, without attempting to inject ssh and or jupyter.
If you use the args launch mode, you can override the entrypoint with --entrypoint, and pass arguments to the entrypoint with --args.
If you use --args, that must be the last argument, as any following tokens are consumed into the args string.
For ssh/jupyter launch types, use --onstart-cmd to pass in startup script, instead of --entrypoint and --args.

Examples:

# create an on-demand instance with the PyTorch (cuDNN Devel) template and 64GB of disk
vastai create instance 384826 --template_hash 661d064bbda1f2a133816b6d55da07c3 --disk 64

# create an on-demand instance with the pytorch/pytorch image, 40GB of disk, open 8081 udp, direct ssh, set hostname to billybob, and a small onstart script
vastai create instance 6995713 --image pytorch/pytorch --disk 40 --env '-p 8081:8081/udp -h billybob' --ssh --direct --onstart-cmd "env | grep _ >> /etc/environment; echo 'starting up'";
vastai create instance 6995713 --image pytorch/pytorch --disk 40 --env '-p 8081:8081/udp -h billybob' --ssh --direct --onstart-cmd "env | grep _ >> /etc/environment; echo 'starting up'";

# create an on-demand instance with the bobsrepo/pytorch:latest image, 20GB of disk, open 22, 8080, jupyter ssh, and set some env variables
vastai create instance 384827 --image bobsrepo/pytorch:latest --login '-u bob -p 9d8df!fd89ufZ docker.io' --jupyter --direct --env '-e TZ=PDT -e XNAME=XX4 -p 22:22 -p 8080:8080' --disk 20
Expand All @@ -2445,71 +2511,54 @@ def validate_portal_config(json_blob):

Return value:
Returns a json reporting the instance ID of the newly created instance:
{'success': True, 'new_contract': 7835610}
{'success': True, 'new_contract': 7835610}
"""),
)
def create__instance(args: argparse.Namespace):
"""Performs the same action as pressing the "RENT" button on the website at https://console.vast.ai/create/.

:param argparse.Namespace args: Namespace with many fields relevant to the endpoint.
"""
create_instance(args.id, args)

if args.onstart:
with open(args.onstart, "r") as reader:
args.onstart_cmd = reader.read()
if args.onstart_cmd is None:
args.onstart_cmd = args.entrypoint

runtype = None
json_blob ={
"client_id": "me",
"image": args.image,
"env" : parse_env(args.env),
"price": args.bid_price,
"disk": args.disk,
"label": args.label,
"extra": args.extra,
"onstart": args.onstart_cmd,
"image_login": args.login,
"python_utf8": args.python_utf8,
"lang_utf8": args.lang_utf8,
"use_jupyter_lab": args.jupyter_lab,
"jupyter_dir": args.jupyter_dir,
#"create_from": args.create_from,
"force": args.force,
"cancel_unavail": args.cancel_unavail,
"template_hash_id" : args.template_hash,
"user": args.user
}

if args.create_volume or args.link_volume:
volume_info = validate_volume_params(args)
json_blob["volume_info"] = volume_info

if args.template_hash is None:
runtype = get_runtype(args)
if runtype == 1:
return 1
json_blob["runtype"] = runtype

if (args.args != None):
json_blob["args"] = args.args

if "PORTAL_CONFIG" in json_blob["env"]:
validate_portal_config(json_blob)

#print(f"put asks/{args.id}/ runtype:{runtype}")
url = apiurl(args, "/asks/{id}/".format(id=args.id))
@parser.command(
argument("ids", help="ids of instance types to launch (returned from search offers)", type=int, nargs='+'),
argument("--template_hash", help="Create instance from template info", type=str),
argument("--user", help="User to use with docker create. This breaks some images, so only use this if you are certain you need it.", type=str),
argument("--disk", help="size of local disk partition in GB", type=float, default=10),
argument("--image", help="docker container image to launch", type=str),
argument("--login", help="docker login arguments for private repo authentication, surround with '' ", type=str),
argument("--label", help="label to set on the instance", type=str),
argument("--onstart", help="filename to use as onstart script", type=str),
argument("--onstart-cmd", help="contents of onstart script as single argument", type=str),
argument("--entrypoint", help="override entrypoint for args launch instance", type=str),
argument("--ssh", help="Launch as an ssh instance type", action="store_true"),
argument("--jupyter", help="Launch as a jupyter instance instead of an ssh instance", action="store_true"),
argument("--direct", help="Use (faster) direct connections for jupyter & ssh", action="store_true"),
argument("--jupyter-dir", help="For runtype 'jupyter', directory in instance to use to launch jupyter. Defaults to image's working directory", type=str),
argument("--jupyter-lab", help="For runtype 'jupyter', Launch instance with jupyter lab", action="store_true"),
argument("--lang-utf8", help="Workaround for images with locale problems: install and generate locales before instance launch, and set locale to C.UTF-8", action="store_true"),
argument("--python-utf8", help="Workaround for images with locale problems: set python's locale to C.UTF-8", action="store_true"),
argument("--extra", help=argparse.SUPPRESS),
argument("--env", help="env variables and port mapping options, surround with '' ", type=str),
argument("--args", nargs=argparse.REMAINDER, help="list of arguments passed to container ENTRYPOINT. Onstart is recommended for this purpose. (must be last argument)"),
argument("--force", help="Skip sanity checks when creating from an existing instance", action="store_true"),
argument("--cancel-unavail", help="Return error if scheduling fails (rather than creating a stopped instance)", action="store_true"),
argument("--bid_price", help="(OPTIONAL) create an INTERRUPTIBLE instance with per machine bid price in $/hour", type=float),
argument("--create-volume", metavar="VOLUME_ASK_ID", help="Create a new local volume using an ID returned from the \"search volumes\" command and link it to the new instance", type=int),
argument("--link-volume", metavar="EXISTING_VOLUME_ID", help="ID of an existing rented volume to link to the instance during creation. (returned from \"show volumes\" cmd)", type=int),
argument("--volume-size", help="Size of the volume to create in GB. Only usable with --create-volume (default 15GB)", type=int),
argument("--mount-path", help="The path to the volume from within the new instance container. e.g. /root/volume", type=str),
argument("--volume-label", help="(optional) A name to give the new volume. Only usable with --create-volume", type=str),

if (args.explain):
print("request json: ")
print(json_blob)
r = http_put(args, url, headers=headers,json=json_blob)
r.raise_for_status()
if args.raw:
return r
else:
print("Started. {}".format(r.json()))
usage="vastai create instances [OPTIONS] ID0 ID1 ID2... [--args ...]",
help="Create instances from a list of offers",
)
def create__instances(args):
"""
"""
idlist = split_list(args.ids, 64)
exec_with_threads(lambda ids : create_instance(ids, args), idlist, nt=8)

@parser.command(
argument("--email", help="email address to use for login", type=str),
Expand Down Expand Up @@ -3027,8 +3076,14 @@ def delete__volume(args: argparse.Namespace):


def destroy_instance(id,args):
url = apiurl(args, "/instances/{id}/".format(id=id))
r = http_del(args, url, headers=headers,json={})
json_blob = {}
if isinstance(id,list):
url = apiurl(args, "/instances/")
json_blob["instance_ids"] = id
else:
url = apiurl(args, "/instances/{id}/".format(id=id))

r = http_del(args, url, headers=headers,json=json_blob)
r.raise_for_status()
if args.raw:
return r
Expand Down Expand Up @@ -3067,8 +3122,8 @@ def destroy__instance(args):
def destroy__instances(args):
"""
"""
for id in args.ids:
destroy_instance(id, args)
idlist = split_list(args.ids, 64)
exec_with_threads(lambda ids : destroy_instance(ids, args), idlist, nt=8)

@parser.command(
usage="vastai destroy team",
Expand Down