Skip to content

Commit

Permalink
Deprecate docker registry (conda-incubator#1016)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
soapy1 and pre-commit-ci[bot] authored Jan 28, 2025
1 parent f6c3ed4 commit 014449a
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 43 deletions.
6 changes: 4 additions & 2 deletions conda-store-server/conda_store_server/_internal/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ class CondaStoreServer(Application):
)

enable_registry = Bool(
True, help="enable the docker registry for conda-store", config=True
False,
help="(deprecated) enable the docker registry for conda-store",
config=True,
)

enable_metrics = Bool(
Expand All @@ -101,7 +103,7 @@ class CondaStoreServer(Application):

registry_external_url = Unicode(
"localhost:8080",
help='external hostname and port to access docker registry cannot contain "http://" or "https://"',
help='(deprecated) external hostname and port to access docker registry cannot contain "http://" or "https://"',
config=True,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# license that can be found in the LICENSE file.

import datetime
from typing import Any, Dict, List, Optional
from functools import wraps
from typing import Any, Callable, Dict, List, Optional

import pydantic
import yaml
Expand Down Expand Up @@ -105,6 +106,37 @@ def paginated_api_response(
}


def deprecated(sunset_date: datetime.date) -> Callable:
"""Decorator to add deprecation headers to a HTTP response. These will include:
{
Deprecation: True
Sunset: <sunset_date>
}
See the conda-store backwards compatibility policy for appropriate use of
deprecations https://conda.store/community/policies/backwards-compatibility.
Parameters
----------
sunset_date : datetime.date
the date that the endpoint will have it's functionality removed
"""

def decorator(func):
@wraps(func)
def add_deprecated_headers(*args, **kwargs):
response = func(*args, **kwargs)
response.headers["Deprecation"] = "True"
response.headers["Sunset"] = sunset_date.strftime(
"%a, %d %b %Y 00:00:00 UTC"
)
return response

return add_deprecated_headers

return decorator


@router_api.get(
"/",
response_model=schema.APIGetStatus,
Expand Down Expand Up @@ -1327,14 +1359,14 @@ async def api_get_build_archive(


@router_api.get("/build/{build_id}/docker/", deprecated=True)
@deprecated(sunset_date=datetime.date(2025, 3, 17))
async def api_get_build_docker_image_url(
build_id: int,
request: Request,
conda_store=Depends(dependencies.get_conda_store),
server=Depends(dependencies.get_server),
auth=Depends(dependencies.get_auth),
):
response_headers = {"Deprecation": "True"}
with conda_store.get_db() as db:
build = api.get_build(db, build_id)
auth.authorize_request(
Expand All @@ -1346,15 +1378,16 @@ async def api_get_build_docker_image_url(

if build.has_docker_manifest:
url = f"{server.registry_external_url}/{build.environment.namespace.name}/{build.environment.name}:{build.build_key}"
return PlainTextResponse(url, headers=response_headers)
return PlainTextResponse(url)

else:
content = {
"status": "error",
"message": f"Build {build_id} doesn't have a docker manifest",
}
return JSONResponse(
status_code=400, content=content, headers=response_headers
status_code=400,
content=content,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

import datetime
import json
import time

Expand All @@ -11,6 +12,7 @@
from conda_store_server import api
from conda_store_server._internal import orm, schema
from conda_store_server._internal.server import dependencies
from conda_store_server._internal.server.views.api import deprecated
from conda_store_server.server.schema import Permissions

router_registry = APIRouter(tags=["registry"])
Expand Down Expand Up @@ -77,6 +79,7 @@ def replace_words(s, words):
return environment_name


@deprecated(sunset_date=datetime.date(2025, 3, 17))
def get_docker_image_manifest(conda_store, image, tag, timeout=10 * 60):
namespace, *image_name = image.split("/")

Expand Down Expand Up @@ -127,12 +130,14 @@ def get_docker_image_manifest(conda_store, image, tag, timeout=10 * 60):
return RedirectResponse(conda_store.storage.get_url(manifests_key))


@deprecated(sunset_date=datetime.date(2025, 3, 17))
def get_docker_image_blob(conda_store, image, blobsum):
blob_key = f"docker/blobs/{blobsum}"
return RedirectResponse(conda_store.storage.get_url(blob_key))


@router_registry.get("/v2/")
@router_registry.get("/v2/", deprecated=True)
@deprecated(sunset_date=datetime.date(2025, 3, 17))
def v2(
request: Request,
entity=Depends(dependencies.get_entity),
Expand All @@ -143,9 +148,8 @@ def v2(
return _json_response({})


@router_registry.get(
"/v2/{rest:path}",
)
@router_registry.get("/v2/{rest:path}", deprecated=True)
@deprecated(sunset_date=datetime.date(2025, 3, 17))
def list_tags(
rest: str,
request: Request,
Expand Down
18 changes: 18 additions & 0 deletions conda-store-server/tests/_internal/server/views/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# license that can be found in the LICENSE file.

import contextlib
import datetime
import json
import os
import sys
Expand Down Expand Up @@ -46,6 +47,23 @@ def mock_get_entity():
testclient.app.dependency_overrides = {}


def test_deprecation_warning():
from fastapi.responses import JSONResponse

from conda_store_server._internal.server.views.api import deprecated

@deprecated(datetime.date(2024, 12, 17))
def api_status():
return JSONResponse(
status_code=400,
content={"ok": "ok"},
)

result = api_status()
assert result.headers.get("Deprecation") == "True"
assert result.headers.get("Sunset") == "Tue, 17 Dec 2024 00:00:00 UTC"


def test_api_version_unauth(testclient):
response = testclient.get("/api/v1/")
response.raise_for_status()
Expand Down
7 changes: 4 additions & 3 deletions docusaurus-docs/conda-store/explanations/artifacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ Click **"Download archive"** button to download the archive of your conda enviro

To install the tarball, follow the [instructions for the target machine in the conda-pack documentation][conda-pack-usage].

## Docker images
## Docker images (deprecated)

:::warning
Docker image creation is currently not supported.
:::warning[Deprecation notice]
Docker image creation is currently not supported. This feature is scheduled to be
removed March 17, 2025.
:::

### Authentication
Expand Down
56 changes: 31 additions & 25 deletions docusaurus-docs/conda-store/references/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: conda-store configuration options

# Configuration options

### Traitlets
## Traitlets

:::warning
This page is in active development, content may be inaccurate and incomplete.
Expand All @@ -24,7 +24,7 @@ conda-store-server --config <path-to-conda-store-config.py>
conda-store-worker --config <path-to-conda-store-config.py>
```

### Data directory
## Data directory

The `CONDA_STORE_DIR` Python variable specifies the conda-store data directory,
which is used by some of the configuration options mentioned below, like
Expand All @@ -49,7 +49,7 @@ Please use the conda-store configuration options mentioned below instead.

[platformdirs]: https://github.com/platformdirs/platformdirs

### `conda_store_server._internal.app.CondaStore`
## `conda_store_server._internal.app.CondaStore`

`CondaStore.storage_class` configures the storage backend to use for
storing build artifacts from
Expand Down Expand Up @@ -210,15 +210,17 @@ setting is useful if you want to protect environments from
modification from certain users and groups. Note: this configuration
option is not supported on Windows.

`CondaStore.serialize_builds` DEPRECATED no longer has any effect

`CondaStore.post_update_environment_build_hook` is an optional configurable to
allow for custom behavior that will run after an environment's current build changes.

`CondaStore.lock_backend` is the name of the default lock plugin to use
when locking a conda environment. By default, conda-store uses [conda-lock](https://github.com/conda/conda-lock).

### `conda_store_server.storage.S3Storage`
### Deprecated configuration options for `conda_store_server._internal.app.CondaStore`

`CondaStore.serialize_builds` no longer has any effect

## `conda_store_server.storage.S3Storage`

conda-store uses [minio-py](https://github.com/minio/minio-py) as a
client to connect to S3 "like" object stores.
Expand Down Expand Up @@ -264,7 +266,7 @@ credentials class.
`S3Storage.credentials_kwargs` keyword arguments to pass for creation
of credentials class.

### `conda_store_server.storage.LocalStorage`
## `conda_store_server.storage.LocalStorage`

`LocalStorage.storage_path` is the base directory to use for storing
build artifacts.
Expand All @@ -273,7 +275,7 @@ build artifacts.
artifacts. This url assumes that the base will be a static server
serving `LocalStorage.storage_path`.

### `conda_store_server.server.auth.AuthenticationBackend`
## `conda_store_server.server.auth.AuthenticationBackend`

`AuthenticationBackend.secret` is the symmetric secret to use for
encrypting tokens.
Expand All @@ -287,7 +289,7 @@ in a similar manner to how things are done with jupyterhub. Format for
the values is a dictionary with keys being the tokens and values being
the `schema.AuthenticaitonToken` all fields are optional.

### `conda_store_server.server.auth.AuthorizationBackend`
## `conda_store_server.server.auth.AuthorizationBackend`

`AuthorizationBackend.role_mappings` is a dictionary that maps `roles`
to application `permissions`. There are three default roles at the
Expand All @@ -300,12 +302,14 @@ bindings that an unauthenticated user assumes.
`AuthorizationBackend.authenticated_role_bindings` are the base role
bindings that an authenticated user assumes.

### `conda_store_server.server.auth.Authentication`
## `conda_store_server.server.auth.Authentication`

`Authentication.cookie_name` is the name for the browser cookie used
to authenticate users.

`Authentication.cookie_domain` use when wanting to set a subdomain wide cookie. For example setting this to `example.com` would allow the cookie to be valid for `example.com` along with `*.example.com`.
`Authentication.cookie_domain` use when wanting to set a subdomain wide
cookie. For example setting this to `example.com` would allow the cookie
to be valid for `example.com` along with `*.example.com`.

`Authentication.authentication_backend` is the class to use for
authentication logic. The default is `AuthenticationBackend` and will
Expand All @@ -318,7 +322,7 @@ likely not need to change.
`Authentication.login_html` is the HTML to display for a given user as
the login form.

### `conda_store_server.server.auth.DummyAuthentication`
## `conda_store_server.server.auth.DummyAuthentication`

Has all the configuration settings of `Authetication`. This class is
modeled after the [JupyterHub DummyAuthentication
Expand All @@ -328,7 +332,7 @@ class](https://github.com/jupyterhub/jupyterhub/blob/9f3663769e96d2e4f665fd6ef48
login with. Effectively a static password. This rarely if ever should
be used outside of testing.

### `conda_store_server.server.auth.GenericOAuthAuthentication`
## `conda_store_server.server.auth.GenericOAuthAuthentication`

A provider-agnostic OAuth authentication provider. Configure
endpoints, secrets and other parameters to enable any OAuth-compatible
Expand Down Expand Up @@ -365,7 +369,7 @@ especially useful when web service is behind a proxy.
`GenericOAuthAuthentication.tls_verify` to optionally turn of TLS
verification useful for custom signed certificates.

### `conda_store_server.server.auth.GithubOAuthAuthentication`
## `conda_store_server.server.auth.GithubOAuthAuthentication`

Inherits from `Authentication` and `GenericOAuthAuthentication` so
should be fully configurable from those options.
Expand All @@ -376,15 +380,15 @@ is `https://github.com`.
`GithubOAuthAuthentication.github_api` is the REST API url for
GitHub. Default is `https://api.github.com`.

### `conda_store_server.server.auth.JupyterHubOAuthAuthentication`
## `conda_store_server.server.auth.JupyterHubOAuthAuthentication`

Inherits from `Authentication` and `GenericOAuthAuthentication` so
should be fully configurable from those options.

`GithubOAuthAuthentication.jupyterhub_url` is the url for connecting
to JupyterHub. The URL should not include the `/hub/`.

### `conda_store_server.server.auth.RBACAuthorizationBackend`
## `conda_store_server.server.auth.RBACAuthorizationBackend`

`RBACAuthorizationBackend.role_mappings_version` specifies the role mappings
version to use: 1 (default, legacy), 2 (new, recommended).
Expand Down Expand Up @@ -429,7 +433,7 @@ metadata and set the roles:
PUT /api/v1/namespace/{namespace}/
```

### `conda_store_server._internal.server.app.CondaStoreServer`
## `conda_store_server._internal.server.app.CondaStoreServer`

`CondaStoreServer.log_level` is the level for all server
logging. Default is `INFO`. Common options are `DEBUG`, `INFO`,
Expand All @@ -441,9 +445,6 @@ endpoints. Default True.
`CondaStoreServer.enable_api` a Boolean on whether to expose the API
endpoints. Default True.

`CondaStoreServer.enable_registry` a Boolean on whether to expose the
registry endpoints. Default True.

`CondaStoreServer.enable_metrics` a Boolean on whether to expose the
metrics endpoints. Default True.

Expand All @@ -453,9 +454,6 @@ to. The default is all IP addresses `0.0.0.0`.
`CondaStoreServer.port` is the port for conda-store server to
use. Default is `8080`.

`CondaStoreServer.registry_external_url` is the external hostname and
port to access docker registry cannot contain `http://` or `https://`.

`CondaStoreServer.url_prefix` is the prefix URL (subdirectory) for the
entire application. All but the registry routes obey this. This is due
to the docker registry API specification not supporting url prefixes.
Expand Down Expand Up @@ -486,7 +484,15 @@ to serve in form `[(path, method, function), ...]`. `path` is a
string, `method` is `get`, `post`, `put`, `delete` etc. and function
is a regular python fastapi function.

### `conda_store_server.._internal.worker.app.CondaStoreWorker`
### Deprecated configuration options for `conda_store_server._internal.server.app.CondaStoreServer`

`CondaStoreServer.enable_registry` (deprecated) a Boolean on whether to
expose the registry endpoints. Default False.

`CondaStoreServer.registry_external_url` (deprecated) is the external hostname
and port to access docker registry cannot contain `http://` or `https://`.

## `conda_store_server._internal.worker.app.CondaStoreWorker`

`CondaStoreWorker.log_level` is the level for all server
logging. Default is `INFO`. Common options are `DEBUG`, `INFO`,
Expand All @@ -500,6 +506,6 @@ single filename to watch.
the number of threads on your given machine. If set will limit the
number of concurrent celery tasks to the integer.

### (deprecated) `conda_store_server.registry.ContainerRegistry`
## (deprecated) `conda_store_server.registry.ContainerRegistry`

`ContainerRegistry.container_registries` (deprecated) dictionary of registries_url to upload built container images with callable function to configure registry instance with credentials.
Loading

0 comments on commit 014449a

Please sign in to comment.