Skip to content
This repository was archived by the owner on Aug 11, 2020. It is now read-only.

Commit e211ed7

Browse files
committed
Update machines help messages and functional tests
1 parent f5871d1 commit e211ed7

File tree

4 files changed

+698
-30
lines changed

4 files changed

+698
-30
lines changed

paperspace/cli.py

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import click
77

88
from paperspace import constants, client, config
9-
from paperspace.commands import experiments as experiments_commands, deployments as deployments_commands, machines as machines_commands
9+
from paperspace.commands import experiments as experiments_commands, deployments as deployments_commands, \
10+
machines as machines_commands
1011

1112

1213
class ChoiceType(click.Choice):
@@ -425,6 +426,7 @@ def create_deployment(api_key=None, **kwargs):
425426
"api_key",
426427
)
427428
def get_deployments_list(api_key=None, **kwargs):
429+
del_if_value_is_none(kwargs)
428430
deployments_api = client.API(config.CONFIG_HOST, api_key=api_key)
429431
command = deployments_commands.ListDeploymentsCommand(api=deployments_api)
430432
command.execute(kwargs)
@@ -498,6 +500,7 @@ def delete_deployment(id, api_key=None):
498500
command = deployments_commands.DeleteDeploymentCommand(api=deployments_api)
499501
command.execute(id)
500502

503+
501504
REGIONS_MAP = collections.OrderedDict(
502505
(
503506
("CA1", constants.Region.CA1),
@@ -512,7 +515,12 @@ def machines_group():
512515
pass
513516

514517

515-
@machines_group.command("availability")
518+
check_machine_availability_help = "Get machine availability for the given region and machine type. " \
519+
"Note: availability is only provided for the dedicated GPU machine types. " \
520+
"Also, not all machine types are available in all regions"
521+
522+
523+
@machines_group.command("availability", help=check_machine_availability_help)
516524
@click.option(
517525
"--region",
518526
"region",
@@ -534,7 +542,14 @@ def check_machine_availability(region, machine_type, api_key):
534542
command.execute(region, machine_type)
535543

536544

537-
@machines_group.command("create")
545+
create_machine_help = "Create a new Paperspace virtual machine. If you are using an individual account, you will " \
546+
"be assigned as the owner of the machine. If you are a team administrator, you must specify " \
547+
"the user that should be assigned to the machine, either by specifing a user id, or by " \
548+
"providing an email address, password, first name and last name for the creation of a new " \
549+
"user on the team."
550+
551+
552+
@machines_group.command("create", help=create_machine_help)
538553
@click.option(
539554
"--region",
540555
"region",
@@ -660,7 +675,15 @@ def create_machine(api_key, **kwargs):
660675
command.execute(kwargs)
661676

662677

663-
@machines_group.command("destroy")
678+
destroy_machine_help = "Destroy the machine with the given id. When this action is performed, the machine is " \
679+
"immediately shut down and marked for deletion from the datacenter. Any snapshots that " \
680+
"were derived from the machine are also deleted. Access to the machine is terminated " \
681+
"immediately and billing for the machine is prorated to the hour. This action can only " \
682+
"be performed by the user who owns the machine, or in the case of a team, the team " \
683+
"administrator."
684+
685+
686+
@machines_group.command("destroy", help=destroy_machine_help)
664687
@click.option(
665688
"--machineId",
666689
"machine_id",
@@ -680,7 +703,12 @@ def destroy_machine(machine_id, release_public_ip, api_key):
680703
command.execute(machine_id, release_public_ip)
681704

682705

683-
@machines_group.command("list")
706+
list_machines_help = "List information about all machines available to either the current authenticated user or " \
707+
"the team, if the user belongs to a team. The list method takes an optional first argument " \
708+
"to limit the returned machine objects."
709+
710+
711+
@machines_group.command("list", help=list_machines_help)
684712
@click.option(
685713
"--params",
686714
"params",
@@ -827,10 +855,16 @@ def list_machines(api_key, params, **kwargs):
827855
command.execute(params or kwargs)
828856

829857

830-
@machines_group.command("restart")
858+
restart_machine_help = "Restart an individual machine. If the machine is already restarting, this action will " \
859+
"request the machine be restarted again. This action can only be performed by the user " \
860+
"who owns the machine"
861+
862+
863+
@machines_group.command("restart", help=restart_machine_help)
831864
@click.option(
832865
"--machineId",
833866
"machine_id",
867+
help="Id of the machine to restart",
834868
required=True,
835869
)
836870
@api_key_option
@@ -844,6 +878,7 @@ def restart_machine(machine_id, api_key):
844878
@click.option(
845879
"--machineId",
846880
"machine_id",
881+
help="Id of the machine to show",
847882
required=True,
848883
)
849884
@api_key_option
@@ -853,60 +888,75 @@ def show_machine_details(machine_id, api_key):
853888
command.execute(machine_id)
854889

855890

856-
@machines_group.command("update")
891+
update_machine_help = "Update attributes of a machine"
892+
893+
894+
@machines_group.command("update", help=update_machine_help)
857895
@click.option(
858896
"--machineId",
859897
"machine_id",
898+
help="Id of the machine to update",
860899
required=True,
861900
)
862901
@click.option(
863902
"--machineName",
864903
"machineName",
904+
help="New name for the machine",
865905
)
866906
@click.option(
867907
"--shutdownTimeoutInHours",
868908
"shutdownTimeoutInHours",
909+
help="Number of hours before machine is shutdown if no one is logged in via the Paperspace client",
869910
type=int,
870911
)
871912
@click.option(
872913
"--shutdownTimeoutForces",
873914
"shutdownTimeoutForces",
874-
is_flag=True,
875-
default=None, # None is used so it can be filtered with `del_if_value_is_none` when flag was not set
915+
help="Force shutdown at shutdown timeout, even if there is a Paperspace client connection",
916+
type=bool,
876917
)
877918
@click.option(
878919
"--performAutoSnapshot",
879920
"performAutoSnapshot",
880-
is_flag=True,
881-
default=None, # None is used so it can be filtered with `del_if_value_is_none` when flag was not set
921+
help="Perform auto snapshots",
922+
type=bool,
882923
)
883924
@click.option(
884925
"--autoSnapshotFrequency",
885926
"autoSnapshotFrequency",
927+
help="One of 'hour', 'day', 'week', or null",
886928
type=click.Choice(["hour", "day", "week"], case_sensitive=False),
887929
)
888930
@click.option(
889931
"--autoSnapshotSaveCount",
890932
"autoSnapshotSaveCount",
933+
help="Number of snapshots to save",
891934
type=int,
892935
)
893936
@click.option(
894937
"--dynamicPublicIp",
895938
"dynamicPublicIp",
896-
is_flag=True,
897-
default=None, # None is used so it can be filtered with `del_if_value_is_none` when flag was not set
939+
help="If true, assigns a new public ip address on machine start and releases it from the account on machine stop",
940+
type=bool,
898941
)
899942
@api_key_option
900-
def update_machine(api_key, **kwargs):
943+
def update_machine(machine_id, api_key, **kwargs):
944+
del_if_value_is_none(kwargs)
901945
machines_api = client.API(config.CONFIG_HOST, api_key=api_key)
902946
command = machines_commands.UpdateMachineCommand(api=machines_api)
903-
command.execute(kwargs)
947+
command.execute(machine_id, kwargs)
904948

905949

906-
@machines_group.command("start")
950+
start_machine_help = "Start up an individual machine. If the machine is already started, this action is a no-op. " \
951+
"If the machine is off, it will be booted up. This action can only be performed by the user " \
952+
"who owns the machine"
953+
954+
955+
@machines_group.command("start", help=start_machine_help)
907956
@click.option(
908957
"--machineId",
909958
"machine_id",
959+
help="Id of the machine to start",
910960
required=True,
911961
)
912962
@api_key_option
@@ -916,10 +966,16 @@ def start_machine(machine_id, api_key):
916966
command.execute(machine_id)
917967

918968

919-
@machines_group.command("stop")
969+
stop_machine_help = "Stop an individual machine. If the machine is already stopped or has been shut down, this " \
970+
"action is a no-op. If the machine is running, it will be stopped and any users logged in " \
971+
"will be immediately kicked out. This action can only be performed by the user who owns the machine"
972+
973+
974+
@machines_group.command("stop", help=stop_machine_help)
920975
@click.option(
921976
"--machineId",
922977
"machine_id",
978+
help="Id of the machine to start",
923979
required=True,
924980
)
925981
@api_key_option
@@ -929,10 +985,15 @@ def stop_machine(machine_id, api_key):
929985
command.execute(machine_id)
930986

931987

932-
@machines_group.command("utilization")
988+
show_machine_utilization_help = "Get machine utilization data for the machine with the given id. Machine upgrades " \
989+
"are not represented in utilization data"
990+
991+
992+
@machines_group.command("utilization", help=show_machine_utilization_help)
933993
@click.option(
934994
"--machineId",
935995
"machine_id",
996+
help="Id of the machine to start",
936997
required=True,
937998
)
938999
@click.option(
@@ -948,15 +1009,22 @@ def show_machine_utilization(machine_id, billing_month, api_key):
9481009
command.execute(machine_id, billing_month)
9491010

9501011

951-
@machines_group.command("waitfor")
1012+
wait_for_machine_state_help = "Wait for the machine with the given id to enter a certain machine state. " \
1013+
"This action polls the server and returns only when we detect that the machine " \
1014+
"has transitioned into the given state."
1015+
1016+
1017+
@machines_group.command("waitfor", help=wait_for_machine_state_help)
9521018
@click.option(
9531019
"--machineId",
9541020
"machine_id",
1021+
help="Id of the machine to start",
9551022
required=True,
9561023
)
9571024
@click.option(
9581025
"--state",
9591026
"state",
1027+
help="Name of the state to wait for",
9601028
type=click.Choice(["off", "serviceready", "ready"], case_sensitive=False),
9611029
required=True,
9621030
)

paperspace/commands/machines.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@ def execute(self, kwargs):
4949

5050

5151
class UpdateMachineCommand(CommandBase):
52-
def execute(self, kwargs):
53-
response = self.api.post("/machines/updateMachinePublic/", json=kwargs)
52+
def execute(self, machine_id, kwargs):
53+
url = "/machines/{}/updateMachinePublic/".format(machine_id)
54+
response = self.api.post(url, json=kwargs)
5455
self._log_message(response,
55-
"Machine updates with",
56-
"Unknown error while updated machine")
56+
"Machine updated",
57+
"Unknown error while updating machine")
5758

5859

5960
class StartMachineCommand(CommandBase):
@@ -201,17 +202,21 @@ def execute(self, machine_id, billing_month):
201202
"billingMonth": billing_month}
202203
response = self.api.get("machines/getUtilization/", params=params)
203204

204-
if response.ok:
205-
machine = response.json()
206-
table = self.make_details_table(machine)
207-
self.logger.log(table)
205+
try:
206+
data = response.json()
207+
if not response.ok:
208+
self.logger.log_error_response(data)
209+
return
210+
except (ValueError, KeyError) as e:
211+
self.logger.log("Error while parsing response data: {}".format(e))
208212
else:
209-
self.logger.log_error_response(response.json())
213+
table = self.make_details_table(data)
214+
self.logger.log(table)
210215

211216
@staticmethod
212217
def make_details_table(machine):
213218
data = (
214-
("ID", machine.get("id")),
219+
("ID", machine.get("machineId")),
215220
("Machine Seconds used", machine["utilization"].get("secondsUsed")),
216221
("Machine Hourly rate", machine["utilization"].get("hourlyRate")),
217222
("Storage Seconds Used", machine["storageUtilization"].get("secondsUsed")),
@@ -229,6 +234,7 @@ def execute(self, machine_id, state, interval=5):
229234
current_state = self._get_machine_state(machine_id)
230235
except BadResponse as e:
231236
self.logger.log(e)
237+
return
232238
else:
233239
if current_state == state:
234240
break
@@ -242,6 +248,9 @@ def _get_machine_state(self, machine_id):
242248
response = self.api.get("/machines/getMachinePublic/", params=params)
243249
try:
244250
json_ = response.json()
251+
if not response.ok:
252+
self.logger.log_error_response(json_)
253+
raise BadResponse("Error while reading machine state")
245254
state = json_.get("state")
246255
except (ValueError, AttributeError):
247256
raise BadResponse("Unknown error while reading machine state")

tests/example_responses.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,3 +1257,19 @@
12571257
}
12581258
]
12591259
}
1260+
1261+
SHOW_MACHINE_UTILIZATION_RESPONSE = {
1262+
"machineId": "psbtuwfvt",
1263+
"utilization": {
1264+
"machineId": "psbtuwfvt",
1265+
"secondsUsed": 0,
1266+
"billingMonth": "2019-04",
1267+
"hourlyRate": 0,
1268+
},
1269+
"storageUtilization": {
1270+
"machineId": "psbtuwfvt",
1271+
"secondsUsed": 256798.902394,
1272+
"monthlyRate": "5.00",
1273+
"billingMonth": "2019-04",
1274+
},
1275+
}

0 commit comments

Comments
 (0)