Skip to content

Commit d92163c

Browse files
committed
WIP
Removed ContainerInfo class, Instantiate all Deployment instances with inference key, don't print key, Created InferenceResponse, WIP healthcheck method
1 parent fe32f8a commit d92163c

File tree

1 file changed

+54
-34
lines changed

1 file changed

+54
-34
lines changed

datacrunch/containers/containers.py

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import requests
2+
from requests.structures import CaseInsensitiveDict
23
from dataclasses import dataclass
34
from dataclasses_json import dataclass_json, Undefined # type: ignore
45
from typing import List, Optional, Dict, Any
@@ -101,40 +102,18 @@ class VolumeMount:
101102
@dataclass
102103
class Container:
103104
"""Container configuration for deployment creation and updates.
104-
This class omits the name field which is managed by the system.
105105
106106
:param image: Container image to use
107107
:param exposed_port: Port to expose from the container
108+
:param name: Name of the container (system-managed, read-only)
108109
:param healthcheck: Optional health check configuration
109110
:param entrypoint_overrides: Optional entrypoint override settings
110111
:param env: Optional list of environment variables
111112
:param volume_mounts: Optional list of volume mounts
112113
"""
113114
image: str
114115
exposed_port: int
115-
healthcheck: Optional[HealthcheckSettings] = None
116-
entrypoint_overrides: Optional[EntrypointOverridesSettings] = None
117-
env: Optional[List[EnvVar]] = None
118-
volume_mounts: Optional[List[VolumeMount]] = None
119-
120-
121-
@dataclass_json
122-
@dataclass
123-
class ContainerInfo:
124-
"""Container configuration for deployments.
125-
This class is read-only and includes the system-managed name field.
126-
127-
:param name: Name of the container (system-managed)
128-
:param image: Container image to use
129-
:param exposed_port: Port to expose from the container
130-
:param healthcheck: Optional health check configuration
131-
:param entrypoint_overrides: Optional entrypoint override settings
132-
:param env: Optional list of environment variables
133-
:param volume_mounts: Optional list of volume mounts
134-
"""
135-
name: str
136-
image: str
137-
exposed_port: int
116+
name: Optional[str] = None
138117
healthcheck: Optional[HealthcheckSettings] = None
139118
entrypoint_overrides: Optional[EntrypointOverridesSettings] = None
140119
env: Optional[List[EnvVar]] = None
@@ -250,7 +229,6 @@ class ScalingOptions:
250229
@dataclass
251230
class Deployment:
252231
"""Configuration for creating or updating a container deployment.
253-
This class uses Container instead of ContainerInfo to prevent name setting.
254232
255233
:param name: Name of the deployment
256234
:param container_registry_settings: Settings for accessing container registry
@@ -264,14 +242,27 @@ class Deployment:
264242
"""
265243
name: str
266244
container_registry_settings: ContainerRegistrySettings
267-
containers: List[Container] | List[ContainerInfo]
245+
containers: List[Container]
268246
compute: ComputeResource
269247
is_spot: bool = False
270248
endpoint_base_url: Optional[str] = None
271249
scaling: Optional[ScalingOptions] = None
272250
created_at: Optional[str] = None
273251

274-
inference_key: Optional[str] = None
252+
_inference_key: Optional[str] = None
253+
254+
def __str__(self):
255+
"""String representation of the deployment, excluding sensitive information."""
256+
# Get all attributes except _inference_key
257+
attrs = {k: v for k, v in self.__dict__.items() if k !=
258+
'_inference_key'}
259+
# Format each attribute
260+
attr_strs = [f"{k}={repr(v)}" for k, v in attrs.items()]
261+
return f"Deployment({', '.join(attr_strs)})"
262+
263+
def __repr__(self):
264+
"""Repr representation of the deployment, excluding sensitive information."""
265+
return self.__str__()
275266

276267
@classmethod
277268
def from_dict_with_inference_key(cls, data: Dict[str, Any], inference_key: str = None, **kwargs) -> 'Deployment':
@@ -282,22 +273,51 @@ def from_dict_with_inference_key(cls, data: Dict[str, Any], inference_key: str =
282273
:param **kwargs: Additional arguments to pass to from_dict
283274
:return: Deployment instance
284275
"""
285-
deployment = cls.from_dict(data, **kwargs)
276+
deployment = Deployment.from_dict(data, infer_missing=True)
286277
deployment._inference_key = inference_key
287278
return deployment
288279

289280
def run_sync(self, data: Dict[str, Any], path: str = "", timeout_seconds: int = 60 * 5):
290281
if self._inference_key is None:
291-
raise ValueError("Inference key is not set") # TODO: review this
282+
# TODO: do something better
283+
raise ValueError("Inference key is not set")
292284

293-
# TODO: create a request object
294-
return requests.post(
285+
response = requests.post(
295286
url=f"{self.endpoint_base_url}{path}",
296287
json=data,
297288
headers={"Authorization": f"Bearer {self._inference_key}"},
298289
timeout=timeout_seconds
299290
)
300291

292+
return InferenceResponse(
293+
body=response.json(),
294+
headers=response.headers,
295+
status_code=response.status_code,
296+
status_text=response.reason
297+
)
298+
299+
def health(self):
300+
healthcheck_path = "health"
301+
if self.containers and self.containers[0].healthcheck and self.containers[0].healthcheck.path:
302+
healthcheck_path = self.containers[0].healthcheck.path.lstrip('/')
303+
304+
response = requests.get(
305+
url=f"{self.endpoint_base_url}{healthcheck_path}",
306+
headers={"Authorization": f"Bearer {self._inference_key}"},
307+
)
308+
return response # TODO: agree on response format
309+
# Function alias
310+
healthcheck = health
311+
312+
313+
@dataclass_json(undefined=Undefined.EXCLUDE)
314+
@dataclass
315+
class InferenceResponse:
316+
body: Any
317+
headers: CaseInsensitiveDict[str]
318+
status_code: int
319+
status_text: str
320+
301321

302322
@dataclass_json
303323
@dataclass
@@ -421,7 +441,7 @@ def get_deployments(self) -> List[Deployment]:
421441
:rtype: List[Deployment]
422442
"""
423443
response = self.client.get(CONTAINER_DEPLOYMENTS_ENDPOINT)
424-
return [Deployment.from_dict(deployment, infer_missing=True) for deployment in response.json()]
444+
return [Deployment.from_dict_with_inference_key(deployment, self._inference_key) for deployment in response.json()]
425445

426446
def get_deployment_by_name(self, deployment_name: str) -> Deployment:
427447
"""Get a deployment by name
@@ -453,7 +473,7 @@ def create_deployment(
453473
CONTAINER_DEPLOYMENTS_ENDPOINT,
454474
deployment.to_dict()
455475
)
456-
return Deployment.from_dict(response.json(), infer_missing=True)
476+
return Deployment.from_dict_with_inference_key(response.json(), self._inference_key)
457477

458478
def update_deployment(self, deployment_name: str, deployment: Deployment) -> Deployment:
459479
"""Update an existing deployment
@@ -469,7 +489,7 @@ def update_deployment(self, deployment_name: str, deployment: Deployment) -> Dep
469489
f"{CONTAINER_DEPLOYMENTS_ENDPOINT}/{deployment_name}",
470490
deployment.to_dict()
471491
)
472-
return Deployment.from_dict(response.json(), infer_missing=True)
492+
return Deployment.from_dict_with_inference_key(response.json(), self._inference_key)
473493

474494
def delete_deployment(self, deployment_name: str) -> None:
475495
"""Delete a deployment

0 commit comments

Comments
 (0)