Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ jobs:
python-version: 3.11
- name: Install dstack
run: |
uv pip install examples/plugins/example_plugin_server
if [ -n "${{ inputs.release_tag }}" ]; then
uv pip install "dstack[server]==${{ inputs.release_tag }}"
else
uv sync --extra server
uv pip install -e '.[server]'
fi
- name: Build
run: |
Expand Down
4 changes: 3 additions & 1 deletion docs/docs/guides/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ class ExamplePolicy(ApplyPolicy):
## Built-in Plugins

### REST Plugin

`rest_plugin` is a builtin `dstack` plugin that allows writing your custom plugins as API servers, so you don't need to install plugins as Python packages.

Plugins implemented as API servers have advantages over plugins implemented as Python packages in some cases:

* No dependency conflicts with `dstack`.
* You can use any programming language.
* If you run the `dstack` server via Docker, you don't need to extend the `dstack` server image with plugins or map them via volumes.

To get started, check out the [plugin server example](/examples/plugins/example_plugin_server/README.md).
To get started, check out the [plugin server example](https://github.com/dstackai/dstack/tree/master/examples/plugins/example_plugin_server). The `rest_plugin` server API is documented [here](../reference/plugins/rest_plugin/index.md).
33 changes: 33 additions & 0 deletions docs/docs/reference/plugins/rest_plugin/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: REST PLUGIN API
---

`rest_plugin` is a builtin `dstack` plugin that allows writing custom plugins as API servers. The following is an OpenAPI documentation for a `rest_plugin` API server.

<style>
.swagger-ui .info {
margin: 0 !important;
}

.swagger-ui .info h1, .swagger-ui .info h2, .swagger-ui .info h3, .swagger-ui .info h4, .swagger-ui .info h5 {
font-weight: 800 !important;
letter-spacing: -1px !important;
color: rgb(0, 0, 0) !important;
text-transform: none !important;
font-family: var(--md-text-font-family) !important;
}

.swagger-ui .info .title {
padding: 0 !important;
}

.swagger-ui .info li, .swagger-ui .info p, .swagger-ui .info table {
line-height: 1.3rem !important;
font-size: 0.8rem !important;
font-family: var(--md-text-font-family) !important;
}
</style>

<br></br>

!!swagger rest_plugin_openapi.json!!
File renamed without changes.
Empty file added examples/plugins/__init__.py
Empty file.
13 changes: 6 additions & 7 deletions examples/plugins/example_plugin_server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,26 @@ If you wish to hook up your own plugin server through `dstack` builtin `rest_plu

## Steps


1. Install required dependencies for the plugin server:
1. Install the plugin server:

```bash
uv sync
uv pip install examples/plugins/example_plugin_server
```

1. Start the plugin server locally:
2. Start the plugin server:

```bash
fastapi dev app/main.py
python -m example_plugin_server.main
```

1. Enable `rest_plugin` in `server/config.yaml`:
3. Enable `rest_plugin` in `server/config.yaml`:

```yaml
plugins:
- rest_plugin
```

1. Point the `dstack` server to your plugin server:
4. Point the `dstack` server to your plugin server:
```bash
export DSTACK_PLUGIN_SERVICE_URI=http://127.0.0.1:8000
```
Empty file.
9 changes: 8 additions & 1 deletion examples/plugins/example_plugin_server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@ readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"fastapi[standard]>=0.115.12",
"dstack>=0.19.8"
"dstack",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/example_plugin_server"]
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import logging
import os

import uvicorn
from fastapi import FastAPI

from app.utils import configure_logging
from dstack.plugins.builtin.rest_plugin import (
FleetSpecRequest,
FleetSpecResponse,
Expand All @@ -13,6 +14,7 @@
VolumeSpecRequest,
VolumeSpecResponse,
)
from example_plugin_server.utils import configure_logging

configure_logging()
logger = logging.getLogger(__name__)
Expand All @@ -34,7 +36,7 @@ async def on_fleet_apply(request: FleetSpecRequest) -> FleetSpecResponse:
logger.info(
f"Received fleet spec request from user {request.user} and project {request.project}"
)
response = FleetSpecResponse(request.spec, error=None)
response = FleetSpecResponse(spec=request.spec, error=None)
return response


Expand All @@ -43,7 +45,7 @@ async def on_volume_apply(request: VolumeSpecRequest) -> VolumeSpecResponse:
logger.info(
f"Received volume spec request from user {request.user} and project {request.project}"
)
response = VolumeSpecResponse(request.spec, error=None)
response = VolumeSpecResponse(spec=request.spec, error=None)
return response


Expand All @@ -52,5 +54,13 @@ async def on_gateway_apply(request: GatewaySpecRequest) -> GatewaySpecResponse:
logger.info(
f"Received gateway spec request from user {request.user} and project {request.project}"
)
response = GatewaySpecResponse(request.spec, error=None)
response = GatewaySpecResponse(spec=request.spec, error=None)
return response


if __name__ == "__main__":
uvicorn.run(
app,
host="127.0.0.1",
port=int(os.getenv("DSTACK_REST_PLUGIN_SERVER_PORT", 8000)),
)
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ plugins:
- scripts/docs/gen_cli_reference.py
- scripts/docs/gen_openapi_reference.py
- scripts/docs/gen_schema_reference.py
- scripts/docs/gen_rest_plugin_spec_reference.py
- mkdocstrings:
handlers:
python:
Expand Down Expand Up @@ -254,6 +255,8 @@ nav:
- Python API: docs/reference/api/python/index.md
- REST API: docs/reference/api/rest/index.md
- Environment variables: docs/reference/environment-variables.md
- Plugins:
- REST Plugin API: docs/reference/plugins/rest_plugin/index.md
- Examples:
- examples.md
- Fine-tuning:
Expand Down
32 changes: 32 additions & 0 deletions scripts/docs/gen_rest_plugin_spec_reference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Generates OpenAPI schema from an example REST plugin.
"""

import json
import logging

import mkdocs_gen_files

from dstack._internal.settings import DSTACK_VERSION

logger = logging.getLogger("mkdocs.plugins.dstack.rest_plugin_schema")

try:
from example_plugin_server.main import app
except ImportError:
logger.warning(
"No module named 'example_plugin_server'."
" The REST Plugin API won't be generated."
" Run 'uv pip install examples/plugins/example_plugin_server' to install 'example_plugin_server'."
)
exit(0)

app.title = "REST Plugin OpenAPI Spec"
app.servers = [
{"url": "http://localhost:8000", "description": "Local server"},
]
app.version = DSTACK_VERSION or "0.0.0"
with mkdocs_gen_files.open(
"docs/reference/plugins/rest_plugin/rest_plugin_openapi.json", "w"
) as f:
json.dump(app.openapi(), f)