Skip to content

Commit b8f4c08

Browse files
committed
refactor, add patch to http client, add update scaling example
1 parent b96e592 commit b8f4c08

File tree

5 files changed

+193
-12
lines changed

5 files changed

+193
-12
lines changed

datacrunch/containers/containers.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -304,33 +304,33 @@ def restart(self, deployment_name: str) -> None:
304304
self.client.post(
305305
f"{CONTAINER_DEPLOYMENTS_ENDPOINT}/{deployment_name}/restart")
306306

307-
def get_scaling_options(self, deployment_name: str) -> Dict:
307+
def get_scaling_options(self, deployment_name: str) -> ScalingOptions:
308308
"""Get deployment scaling options
309309
310310
:param deployment_name: name of the deployment
311311
:type deployment_name: str
312312
:return: scaling options
313-
:rtype: Dict
313+
:rtype: ScalingOptions
314314
"""
315315
response = self.client.get(
316316
f"{CONTAINER_DEPLOYMENTS_ENDPOINT}/{deployment_name}/scaling")
317-
return response.json()
317+
return ScalingOptions.from_dict(response.json())
318318

319-
def update_scaling_options(self, deployment_name: str, scaling_options: Dict) -> Dict:
319+
def update_scaling_options(self, deployment_name: str, scaling_options: ScalingOptions) -> ScalingOptions:
320320
"""Update deployment scaling options
321321
322322
:param deployment_name: name of the deployment
323323
:type deployment_name: str
324324
:param scaling_options: new scaling options
325-
:type scaling_options: Dict
325+
:type scaling_options: ScalingOptions
326326
:return: updated scaling options
327-
:rtype: Dict
327+
:rtype: ScalingOptions
328328
"""
329329
response = self.client.patch(
330330
f"{CONTAINER_DEPLOYMENTS_ENDPOINT}/{deployment_name}/scaling",
331-
scaling_options
331+
scaling_options.to_dict()
332332
)
333-
return response.json()
333+
return ScalingOptions.from_dict(response.json())
334334

335335
def get_replicas(self, deployment_name: str) -> Dict:
336336
"""Get deployment replicas

datacrunch/http_client/http_client.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,36 @@ def get(self, url: str, params: dict = None, **kwargs) -> requests.Response:
119119

120120
return response
121121

122+
def patch(self, url: str, json: dict = None, params: dict = None, **kwargs) -> requests.Response:
123+
"""Sends a PATCH request.
124+
125+
A wrapper for the requests.patch method.
126+
127+
Builds the url, uses custom headers, refresh tokens if needed.
128+
129+
:param url: relative url of the API endpoint
130+
:type url: str
131+
:param json: A JSON serializable Python object to send in the body of the Request, defaults to None
132+
:type json: dict, optional
133+
:param params: Dictionary of querystring data to attach to the Request, defaults to None
134+
:type params: dict, optional
135+
136+
:raises APIException: an api exception with message and error type code
137+
138+
:return: Response object
139+
:rtype: requests.Response
140+
"""
141+
self._refresh_token_if_expired()
142+
143+
url = self._add_base_url(url)
144+
headers = self._generate_headers()
145+
146+
response = requests.patch(
147+
url, json=json, headers=headers, params=params, **kwargs)
148+
handle_error(response)
149+
150+
return response
151+
122152
def delete(self, url: str, json: dict = None, params: dict = None, **kwargs) -> requests.Response:
123153
"""Sends a DELETE request.
124154

examples/containers/container_deployments.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@
2828
# Configuration constants
2929
DEPLOYMENT_NAME = "my-deployment"
3030
CONTAINER_NAME = "my-app"
31+
IMAGE_NAME = "your-image-name:version"
32+
33+
# Environment variables
34+
DATACRUNCH_CLIENT_ID = os.environ.get('DATACRUNCH_CLIENT_ID')
35+
DATACRUNCH_CLIENT_SECRET = os.environ.get('DATACRUNCH_CLIENT_SECRET')
36+
37+
# DataCrunch client instance
38+
datacrunch = None
3139

3240

3341
def wait_for_deployment_health(client: DataCrunchClient, deployment_name: str, max_attempts: int = 10, delay: int = 30) -> bool:
@@ -72,15 +80,21 @@ def cleanup_resources(client: DataCrunchClient) -> None:
7280
def main() -> None:
7381
"""Main function demonstrating deployment lifecycle management."""
7482
try:
83+
# Check required environment variables
84+
if not DATACRUNCH_CLIENT_ID or not DATACRUNCH_CLIENT_SECRET:
85+
print(
86+
"Please set DATACRUNCH_CLIENT_ID and DATACRUNCH_CLIENT_SECRET environment variables")
87+
return
88+
7589
# Initialize client
76-
client_id = os.environ.get('DATACRUNCH_CLIENT_ID')
77-
client_secret = os.environ.get('DATACRUNCH_CLIENT_SECRET')
78-
datacrunch = DataCrunchClient(client_id, client_secret)
90+
global datacrunch
91+
datacrunch = DataCrunchClient(
92+
DATACRUNCH_CLIENT_ID, DATACRUNCH_CLIENT_SECRET)
7993

8094
# Create container configuration
8195
container = Container(
8296
name=CONTAINER_NAME,
83-
image='nginx:latest',
97+
image=IMAGE_NAME,
8498
exposed_port=80,
8599
healthcheck=HealthcheckSettings(
86100
enabled=True,
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"""Example script demonstrating how to update scaling options for a container deployment.
2+
3+
This script shows how to update scaling configurations for an existing container deployment on DataCrunch.
4+
"""
5+
6+
import os
7+
8+
from datacrunch import DataCrunchClient
9+
from datacrunch.exceptions import APIException
10+
from datacrunch.containers.containers import (
11+
ScalingOptions,
12+
ScalingPolicy,
13+
ScalingTriggers,
14+
QueueLoadScalingTrigger,
15+
UtilizationScalingTrigger
16+
)
17+
18+
# Configuration - replace with your deployment name
19+
DEPLOYMENT_NAME = "my-deployment"
20+
21+
# Environment variables
22+
DATACRUNCH_CLIENT_ID = os.environ.get('DATACRUNCH_CLIENT_ID')
23+
DATACRUNCH_CLIENT_SECRET = os.environ.get('DATACRUNCH_CLIENT_SECRET')
24+
25+
26+
def check_deployment_exists(client: DataCrunchClient, deployment_name: str) -> bool:
27+
"""Check if a deployment exists.
28+
29+
Args:
30+
client: DataCrunch API client
31+
deployment_name: Name of the deployment to check
32+
33+
Returns:
34+
bool: True if deployment exists, False otherwise
35+
"""
36+
try:
37+
client.containers.get_by_name(deployment_name)
38+
return True
39+
except APIException as e:
40+
print(f"Error: {e}")
41+
return False
42+
43+
44+
def update_deployment_scaling(client: DataCrunchClient, deployment_name: str) -> None:
45+
"""Update scaling options using the dedicated scaling options API.
46+
47+
Args:
48+
client: DataCrunch API client
49+
deployment_name: Name of the deployment to update
50+
"""
51+
try:
52+
# Create scaling options using ScalingOptions dataclass
53+
scaling_options = ScalingOptions(
54+
min_replica_count=1,
55+
max_replica_count=5,
56+
scale_down_policy=ScalingPolicy(
57+
delay_seconds=600), # Longer cooldown period
58+
scale_up_policy=ScalingPolicy(delay_seconds=60), # Quick scale-up
59+
queue_message_ttl_seconds=500,
60+
concurrent_requests_per_replica=1,
61+
scaling_triggers=ScalingTriggers(
62+
queue_load=QueueLoadScalingTrigger(threshold=1.0),
63+
cpu_utilization=UtilizationScalingTrigger(
64+
enabled=True,
65+
threshold=75
66+
),
67+
gpu_utilization=UtilizationScalingTrigger(
68+
enabled=False # Disable GPU utilization trigger
69+
)
70+
)
71+
)
72+
73+
# Update scaling options
74+
updated_options = client.containers.update_scaling_options(
75+
deployment_name, scaling_options)
76+
print(f"Updated deployment scaling options")
77+
print(f"New min replicas: {updated_options.min_replica_count}")
78+
print(f"New max replicas: {updated_options.max_replica_count}")
79+
print(
80+
f"CPU utilization trigger enabled: {updated_options.scaling_triggers.cpu_utilization.enabled}")
81+
print(
82+
f"CPU utilization threshold: {updated_options.scaling_triggers.cpu_utilization.threshold}%")
83+
except APIException as e:
84+
print(f"Error updating scaling options: {e}")
85+
86+
87+
def main() -> None:
88+
"""Main function demonstrating scaling updates."""
89+
try:
90+
# Check required environment variables
91+
if not DATACRUNCH_CLIENT_ID or not DATACRUNCH_CLIENT_SECRET:
92+
print(
93+
"Please set DATACRUNCH_CLIENT_ID and DATACRUNCH_CLIENT_SECRET environment variables")
94+
return
95+
96+
# Initialize client
97+
client = DataCrunchClient(
98+
DATACRUNCH_CLIENT_ID, DATACRUNCH_CLIENT_SECRET)
99+
100+
# Verify deployment exists
101+
if not check_deployment_exists(client, DEPLOYMENT_NAME):
102+
print(f"Deployment {DEPLOYMENT_NAME} does not exist.")
103+
return
104+
105+
# Update scaling options using the API
106+
update_deployment_scaling(client, DEPLOYMENT_NAME)
107+
108+
# Get current scaling options
109+
scaling_options = client.containers.get_scaling_options(
110+
DEPLOYMENT_NAME)
111+
print(f"\nCurrent scaling configuration:")
112+
print(f"Min replicas: {scaling_options.min_replica_count}")
113+
print(f"Max replicas: {scaling_options.max_replica_count}")
114+
print(
115+
f"Scale-up delay: {scaling_options.scale_up_policy.delay_seconds} seconds")
116+
print(
117+
f"Scale-down delay: {scaling_options.scale_down_policy.delay_seconds} seconds")
118+
119+
print("\nScaling update completed successfully.")
120+
121+
except Exception as e:
122+
print(f"Unexpected error: {e}")
123+
124+
125+
if __name__ == "__main__":
126+
main()

requirements.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
certifi==2025.1.31
2+
charset-normalizer==3.4.1
3+
dataclasses-json==0.6.7
4+
idna==3.10
5+
marshmallow==3.26.1
6+
mypy-extensions==1.0.0
7+
packaging==24.2
8+
requests==2.32.3
9+
typing-inspect==0.9.0
10+
typing_extensions==4.12.2
11+
urllib3==2.3.0

0 commit comments

Comments
 (0)