Skip to content

Commit a7e6c43

Browse files
Nadine-Hr4victor
andauthored
Generate REST plugin API docs (#2696)
* Generate rest plugin api docs * Fix REST Plugin OpenAPI generation * Add DSTACK_REST_PLUGIN_SERVER_PORT and minor fixes * Make example_plugin_server an installable package --------- Co-authored-by: Victor Skvortsov <vds003@gmail.com>
1 parent cdf0a4f commit a7e6c43

File tree

13 files changed

+101
-14
lines changed

13 files changed

+101
-14
lines changed

.github/workflows/docs.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ jobs:
1616
python-version: 3.11
1717
- name: Install dstack
1818
run: |
19+
uv pip install examples/plugins/example_plugin_server
1920
if [ -n "${{ inputs.release_tag }}" ]; then
2021
uv pip install "dstack[server]==${{ inputs.release_tag }}"
2122
else
22-
uv sync --extra server
23+
uv pip install -e '.[server]'
2324
fi
2425
- name: Build
2526
run: |

docs/docs/guides/plugins.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,13 @@ class ExamplePolicy(ApplyPolicy):
116116
## Built-in Plugins
117117

118118
### REST Plugin
119+
119120
`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.
120121

121122
Plugins implemented as API servers have advantages over plugins implemented as Python packages in some cases:
123+
122124
* No dependency conflicts with `dstack`.
123125
* You can use any programming language.
124126
* 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.
125127

126-
To get started, check out the [plugin server example](/examples/plugins/example_plugin_server/README.md).
128+
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).
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
title: REST PLUGIN API
3+
---
4+
5+
`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.
6+
7+
<style>
8+
.swagger-ui .info {
9+
margin: 0 !important;
10+
}
11+
12+
.swagger-ui .info h1, .swagger-ui .info h2, .swagger-ui .info h3, .swagger-ui .info h4, .swagger-ui .info h5 {
13+
font-weight: 800 !important;
14+
letter-spacing: -1px !important;
15+
color: rgb(0, 0, 0) !important;
16+
text-transform: none !important;
17+
font-family: var(--md-text-font-family) !important;
18+
}
19+
20+
.swagger-ui .info .title {
21+
padding: 0 !important;
22+
}
23+
24+
.swagger-ui .info li, .swagger-ui .info p, .swagger-ui .info table {
25+
line-height: 1.3rem !important;
26+
font-size: 0.8rem !important;
27+
font-family: var(--md-text-font-family) !important;
28+
}
29+
</style>
30+
31+
<br></br>
32+
33+
!!swagger rest_plugin_openapi.json!!

examples/plugins/example_plugin_server/app/__init__.py renamed to examples/__init__.py

File renamed without changes.

examples/plugins/__init__.py

Whitespace-only changes.

examples/plugins/example_plugin_server/README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,26 @@ If you wish to hook up your own plugin server through `dstack` builtin `rest_plu
44

55
## Steps
66

7-
8-
1. Install required dependencies for the plugin server:
7+
1. Install the plugin server:
98

109
```bash
11-
uv sync
10+
uv pip install examples/plugins/example_plugin_server
1211
```
1312

14-
1. Start the plugin server locally:
13+
2. Start the plugin server:
1514

1615
```bash
17-
fastapi dev app/main.py
16+
python -m example_plugin_server.main
1817
```
1918

20-
1. Enable `rest_plugin` in `server/config.yaml`:
19+
3. Enable `rest_plugin` in `server/config.yaml`:
2120

2221
```yaml
2322
plugins:
2423
- rest_plugin
2524
```
2625

27-
1. Point the `dstack` server to your plugin server:
26+
4. Point the `dstack` server to your plugin server:
2827
```bash
2928
export DSTACK_PLUGIN_SERVICE_URI=http://127.0.0.1:8000
3029
```

examples/plugins/example_plugin_server/__init__.py

Whitespace-only changes.

examples/plugins/example_plugin_server/pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,12 @@ readme = "README.md"
66
requires-python = ">=3.11"
77
dependencies = [
88
"fastapi[standard]>=0.115.12",
9-
"dstack>=0.19.8"
9+
"dstack",
1010
]
11+
12+
[build-system]
13+
requires = ["hatchling"]
14+
build-backend = "hatchling.build"
15+
16+
[tool.hatch.build.targets.wheel]
17+
packages = ["src/example_plugin_server"]

examples/plugins/example_plugin_server/src/example_plugin_server/__init__.py

Whitespace-only changes.

examples/plugins/example_plugin_server/app/main.py renamed to examples/plugins/example_plugin_server/src/example_plugin_server/main.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import logging
2+
import os
23

4+
import uvicorn
35
from fastapi import FastAPI
46

5-
from app.utils import configure_logging
67
from dstack.plugins.builtin.rest_plugin import (
78
FleetSpecRequest,
89
FleetSpecResponse,
@@ -13,6 +14,7 @@
1314
VolumeSpecRequest,
1415
VolumeSpecResponse,
1516
)
17+
from example_plugin_server.utils import configure_logging
1618

1719
configure_logging()
1820
logger = logging.getLogger(__name__)
@@ -34,7 +36,7 @@ async def on_fleet_apply(request: FleetSpecRequest) -> FleetSpecResponse:
3436
logger.info(
3537
f"Received fleet spec request from user {request.user} and project {request.project}"
3638
)
37-
response = FleetSpecResponse(request.spec, error=None)
39+
response = FleetSpecResponse(spec=request.spec, error=None)
3840
return response
3941

4042

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

4951

@@ -52,5 +54,13 @@ async def on_gateway_apply(request: GatewaySpecRequest) -> GatewaySpecResponse:
5254
logger.info(
5355
f"Received gateway spec request from user {request.user} and project {request.project}"
5456
)
55-
response = GatewaySpecResponse(request.spec, error=None)
57+
response = GatewaySpecResponse(spec=request.spec, error=None)
5658
return response
59+
60+
61+
if __name__ == "__main__":
62+
uvicorn.run(
63+
app,
64+
host="127.0.0.1",
65+
port=int(os.getenv("DSTACK_REST_PLUGIN_SERVER_PORT", 8000)),
66+
)

0 commit comments

Comments
 (0)