Skip to content

Commit

Permalink
[batch] warns the user if client or server is using deprecated functi…
Browse files Browse the repository at this point in the history
…onality (#14621)

Closes #14485.

Tested that this works by deploying the branch to my dev namespace and
pointing my dev config at it:

```bash
hailctl dev deploy -b iris-garden/hail:batch/deprecated-apis -s deploy_batch,add_developers
hailctl dev config set default_namespace irademac
```

And then running the following:

```python
from hailtop.batch import ServiceBackend
batch_client = await ServiceBackend(billing_project='test', remote_tmpdir='gs://irademac/test/')._batch_client()
# one of the deprecated endpoints
await batch_client._get("/api/v1alpha/batches/402/jobs/1/log")
```
  • Loading branch information
iris-garden authored Jul 31, 2024
1 parent ee6d17e commit 9cd2526
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
18 changes: 15 additions & 3 deletions batch/batch/front_end/front_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,18 @@ def cast_query_param_to_bool(param: Optional[str]) -> bool:
return True


def deprecated(fun):
@wraps(fun)
async def wrapped(request, *args, **kwargs):
response = await fun(request, *args, **kwargs)
response.headers["X-Hail-Deprecated"] = (
f'The endpoint "{request.url.path}" is deprecated. Please upgrade your Hail version to the latest release.'
)
return response

return wrapped


@routes.get('/healthcheck')
async def get_healthcheck(_) -> web.Response:
return web.Response()
Expand Down Expand Up @@ -651,10 +663,10 @@ async def _get_full_job_status(app, record):
raise


# deprecated
@routes.get('/api/v1alpha/batches/{batch_id}/jobs/{job_id}/log')
@billing_project_users_only()
@add_metadata_to_request
@deprecated
async def get_job_log(request: web.Request, _, batch_id: int) -> web.Response:
job_id = int(request.match_info['job_id'])
job_log_bytes = await _get_job_log(request.app, batch_id, job_id)
Expand Down Expand Up @@ -836,10 +848,10 @@ def check_service_account_permissions(user, sa):
raise web.HTTPBadRequest(reason=f'unauthorized service account {(sa["namespace"], sa["name"])} for user {user}')


# Deprecated. Use create_jobs_for_update instead
@routes.post('/api/v1alpha/batches/{batch_id}/jobs/create')
@auth.authenticated_users_only()
@add_metadata_to_request
@deprecated # Use create_jobs_for_update instead
async def create_jobs(request: web.Request, userdata: UserData) -> web.Response:
app = request.app
batch_id = int(request.match_info['batch_id'])
Expand Down Expand Up @@ -2055,10 +2067,10 @@ async def cancel_job_group(request: web.Request, _, batch_id: int) -> web.Respon
return web.Response()


# deprecated
@routes.patch('/api/v1alpha/batches/{batch_id}/close')
@auth.authenticated_users_only()
@add_metadata_to_request
@deprecated
async def close_batch(request, userdata):
batch_id = int(request.match_info['batch_id'])
user = userdata['username']
Expand Down
7 changes: 5 additions & 2 deletions gear/gear/http_server_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections.abc import Mapping
from typing import Any, Callable, Optional

import orjson
Expand All @@ -8,5 +9,7 @@ async def json_request(request: web.Request) -> Any:
return orjson.loads(await request.read())


def json_response(data: Any, fallback_serializer: Optional[Callable[[Any], Any]] = None) -> web.Response:
return web.json_response(body=orjson.dumps(data, default=fallback_serializer))
def json_response(
data: Any, fallback_serializer: Optional[Callable[[Any], Any]] = None, headers: Optional[Mapping] = None
) -> web.Response:
return web.json_response(body=orjson.dumps(data, default=fallback_serializer), headers=headers)
19 changes: 15 additions & 4 deletions hail/python/hailtop/batch_client/aioclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import math
import random
import secrets
import warnings
from enum import Enum
from typing import Any, AsyncIterator, Dict, List, Optional, Tuple, TypedDict, Union, cast

Expand Down Expand Up @@ -1303,17 +1304,27 @@ def __init__(self, billing_project: str, url: str, session: Session, headers: Di
self._session: Session = session
self._headers = headers

async def _warn_if_deprecated(self, response: aiohttp.ClientResponse) -> aiohttp.ClientResponse:
deprecation_message = response.headers.get("X-Hail-Deprecated")
if deprecation_message is not None:
warnings.warn(f"DEPRECATED: {deprecation_message}")
return response

async def _get(self, path, params=None) -> aiohttp.ClientResponse:
return await self._session.get(self.url + path, params=params, headers=self._headers)
return await self._warn_if_deprecated(
await self._session.get(self.url + path, params=params, headers=self._headers)
)

async def _post(self, path, data=None, json=None) -> aiohttp.ClientResponse:
return await self._session.post(self.url + path, data=data, json=json, headers=self._headers)
return await self._warn_if_deprecated(
await self._session.post(self.url + path, data=data, json=json, headers=self._headers)
)

async def _patch(self, path) -> aiohttp.ClientResponse:
return await self._session.patch(self.url + path, headers=self._headers)
return await self._warn_if_deprecated(await self._session.patch(self.url + path, headers=self._headers))

async def _delete(self, path) -> aiohttp.ClientResponse:
return await self._session.delete(self.url + path, headers=self._headers)
return await self._warn_if_deprecated(await self._session.delete(self.url + path, headers=self._headers))

def reset_billing_project(self, billing_project):
self.billing_project = billing_project
Expand Down

0 comments on commit 9cd2526

Please sign in to comment.