Skip to content

Commit 8162556

Browse files
Merge pull request #188 from runpod/1.3.1-changelog
1.3.1 changelog
2 parents 08ffdcf + d5739cf commit 8162556

File tree

21 files changed

+567
-22
lines changed

21 files changed

+567
-22
lines changed

CHANGELOG.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
# Change Log
22

3-
## Release 1.3.1 (TBD)
3+
## Release 1.3.1 (10/29/23)
44

55
### Added
66

77
- `test_output` can be passed in as an arg to compare the results of `test_input`
88
- Generator/Streaming handlers supported with local testing
99
- [BETA] CLI DevEx functionality to create development projects.
1010

11+
---
12+
1113
## Release 1.3.0 (10/12/23)
1214

13-
### Changes
15+
### Changed
1416

1517
- Backwards compatibility with Python >= 3.8
1618
- Consolidated install dependencies to `requirements.txt`
@@ -23,7 +25,7 @@
2325

2426
## Release 1.2.6 (10/6/23)
2527

26-
### Changes
28+
### Changed
2729

2830
- Force `urllib3` logging to `WARNING` level to avoid spamming the console if global logging level is set to `DEBUG`.
2931

@@ -40,7 +42,7 @@
4042

4143
## ~~Release (Patch) 1.2.3 (10/4/23)~~ Replaced by 1.2.5
4244

43-
### Bug Fix
45+
### Fixed
4446

4547
- Job outputs that were not dictionaries, bool, or str were swallowed by the serverless worker. This has been fixed.
4648

@@ -55,7 +57,7 @@
5557
- `network_volume_id` can now be passed in when creating new pods, correct data center is automatically selected.
5658
- `template_id` can now be passed in when creating new pods.
5759

58-
### Changes
60+
### Changed
5961

6062
- Dependencies updated to latest versions.
6163
- Reduced circular imports for version reference.
@@ -91,7 +93,7 @@
9193
- Can generate a credentials file from the CLI to store your API key.
9294
- `get_gpu` now supports `gpu_quantity` as a parameter.
9395

94-
### Changes
96+
### Changed
9597

9698
- Minimized the use of pytests in favor of unittests.
9799
- Re-named `api_wrapper` to `api` for consistency.

docs/cli/demos/config.gif

0 Bytes
Loading

docs/cli/demos/help.gif

-114 Bytes
Loading

docs/cli/demos/ssh.gif

-353 Bytes
Loading

examples/api/create_endpoint.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
""" Example of creating an endpoint with the Runpod API. """
2+
3+
import runpod
4+
5+
# Set your global API key with `runpod config` or uncomment the line below:
6+
# runpod.api_key = "YOUR_RUNPOD_API_KEY"
7+
8+
try:
9+
10+
new_template = runpod.create_template(
11+
name="test",
12+
image_name="runpod/base:0.1.0",
13+
is_serverless=True
14+
)
15+
16+
print(new_template)
17+
18+
new_endpoint = runpod.create_endpoint(
19+
name="test",
20+
template_id=new_template["id"],
21+
gpu_ids="AMPERE_16",
22+
workers_min=0,
23+
workers_max=1
24+
)
25+
26+
print(new_endpoint)
27+
28+
except runpod.error.QueryError as err:
29+
print(err)
30+
print(err.query)

examples/api/create_template.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
""" Example of creating a template with the Runpod API. """
2+
3+
import runpod
4+
5+
# Set your global API key with `runpod config` or uncomment the line below:
6+
# runpod.api_key = "YOUR_RUNPOD_API_KEY"
7+
8+
try:
9+
10+
new_template = runpod.create_template(
11+
name="test",
12+
image_name="runpod/base:0.1.0"
13+
)
14+
15+
print(new_template)
16+
17+
except runpod.error.QueryError as err:
18+
print(err)
19+
print(err.query)

runpod/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
from .version import __version__
1010
from .api.ctl_commands import(
1111
get_user, update_user_settings,
12-
get_gpus, get_gpu,
13-
get_pods, get_pod,
14-
create_pod, stop_pod, resume_pod, terminate_pod
12+
get_gpu, get_gpus,
13+
get_pod, get_pods, create_pod, stop_pod, resume_pod, terminate_pod,
14+
create_template,
15+
create_endpoint
1516
)
1617
from .cli.groups.config.functions import set_credentials, check_credentials, get_credentials
1718

runpod/api/ctl_commands.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
from .queries import pods as pod_queries
1212
from .graphql import run_graphql_query
1313
from .mutations import pods as pod_mutations
14+
from .mutations import endpoints as endpoint_mutations
15+
16+
# Templates
17+
from .mutations import templates as template_mutations
1418

1519
def get_user() -> dict:
1620
'''
@@ -188,3 +192,73 @@ def terminate_pod(pod_id: str):
188192
run_graphql_query(
189193
pod_mutations.generate_pod_terminate_mutation(pod_id)
190194
)
195+
196+
197+
def create_template(
198+
name:str, image_name:str, docker_start_cmd:str=None,
199+
container_disk_in_gb:int=10, volume_in_gb:int=None, volume_mount_path:str=None,
200+
ports:str=None, env:dict=None, is_serverless:bool=False
201+
):
202+
'''
203+
Create a template
204+
205+
:param name: the name of the template
206+
:param image_name: the name of the docker image to be used by the template
207+
:param docker_start_cmd: the command to start the docker container with
208+
:param container_disk_in_gb: how big should the container disk be
209+
:param volume_in_gb: how big should the volume be
210+
:param ports: the ports to open in the pod, example format - "8888/http,666/tcp"
211+
:param volume_mount_path: where to mount the volume?
212+
:param env: the environment variables to inject into the pod,
213+
for example {EXAMPLE_VAR:"example_value", EXAMPLE_VAR2:"example_value 2"}, will
214+
inject EXAMPLE_VAR and EXAMPLE_VAR2 into the pod with the mentioned values
215+
:param is_serverless: is the template serverless?
216+
217+
:example:
218+
219+
>>> template_id = runpod.create_template("test", "runpod/stack", "python3 main.py")
220+
'''
221+
raw_response = run_graphql_query(
222+
template_mutations.generate_pod_template(
223+
name, image_name, docker_start_cmd,
224+
container_disk_in_gb, volume_in_gb, volume_mount_path,
225+
ports, env, is_serverless
226+
)
227+
)
228+
229+
return raw_response["data"]["saveTemplate"]
230+
231+
def create_endpoint(
232+
name:str, template_id:str, gpu_ids:str="AMPERE_16",
233+
network_volume_id:str=None, locations:str=None,
234+
idle_timeout:int=5, scaler_type:str="QUEUE_DELAY", scaler_value:int=4,
235+
workers_min:int=0, workers_max:int=3
236+
):
237+
'''
238+
Create an endpoint
239+
240+
:param name: the name of the endpoint
241+
:param template_id: the id of the template to use for the endpoint
242+
:param gpu_ids: the ids of the GPUs to use for the endpoint
243+
:param network_volume_id: the id of the network volume to use for the endpoint
244+
:param locations: the locations to use for the endpoint
245+
:param idle_timeout: the idle timeout for the endpoint
246+
:param scaler_type: the scaler type for the endpoint
247+
:param scaler_value: the scaler value for the endpoint
248+
:param workers_min: the minimum number of workers for the endpoint
249+
:param workers_max: the maximum number of workers for the endpoint
250+
251+
:example:
252+
253+
>>> endpoint_id = runpod.create_endpoint("test", "template_id")
254+
'''
255+
raw_response = run_graphql_query(
256+
endpoint_mutations.generate_endpoint_mutation(
257+
name, template_id, gpu_ids,
258+
network_volume_id, locations,
259+
idle_timeout, scaler_type, scaler_value,
260+
workers_min, workers_max
261+
)
262+
)
263+
264+
return raw_response["data"]["saveEndpoint"]

runpod/api/graphql.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ def run_graphql_query(query: str) -> Dict[str, Any]:
2727
raise error.AuthenticationError("Unauthorized request, please check your API key.")
2828

2929
if "errors" in response.json():
30-
raise error.QueryError(response.json()["errors"][0]["message"])
30+
raise error.QueryError(
31+
response.json()["errors"][0]["message"],
32+
query
33+
)
3134

3235
return response.json()

runpod/api/mutations/endpoints.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
""" RunPod | API Wrapper | Mutations | Endpoints """
2+
3+
# pylint: disable=too-many-arguments
4+
5+
def generate_endpoint_mutation(
6+
name:str, template_id:str, gpu_ids:str="AMPERE_16",
7+
network_volume_id:str=None, locations:str=None,
8+
idle_timeout:int=5, scaler_type:str="QUEUE_DELAY", scaler_value:int=4,
9+
workers_min:int=0, workers_max:int=3
10+
):
11+
""" Generate a string for a GraphQL mutation to create a new endpoint. """
12+
input_fields = []
13+
14+
# ------------------------------ Required Fields ----------------------------- #
15+
input_fields.append(f'name: "{name}"')
16+
input_fields.append(f'templateId: "{template_id}"')
17+
input_fields.append(f'gpuIds: "{gpu_ids}"')
18+
19+
# ------------------------------ Optional Fields ----------------------------- #
20+
if network_volume_id is not None:
21+
input_fields.append(f'networkVolumeId: "{network_volume_id}"')
22+
else:
23+
input_fields.append('networkVolumeId: ""')
24+
25+
if locations is not None:
26+
input_fields.append(f'locations: "{locations}"')
27+
else:
28+
input_fields.append('locations: ""')
29+
30+
input_fields.append(f'idleTimeout: {idle_timeout}')
31+
input_fields.append(f'scalerType: "{scaler_type}"')
32+
input_fields.append(f'scalerValue: {scaler_value}')
33+
input_fields.append(f'workersMin: {workers_min}')
34+
input_fields.append(f'workersMax: {workers_max}')
35+
36+
# Format the input fields into a string
37+
input_fields_string = ", ".join(input_fields)
38+
39+
return f"""
40+
mutation {{
41+
saveEndpoint(
42+
input: {{
43+
{input_fields_string}
44+
}}
45+
) {{
46+
id
47+
name
48+
templateId
49+
gpuIds
50+
networkVolumeId
51+
locations
52+
idleTimeout
53+
scalerType
54+
scalerValue
55+
workersMin
56+
workersMax
57+
}}
58+
}}
59+
"""

0 commit comments

Comments
 (0)