Skip to content

Commit a109448

Browse files
committed
Add plugin example
1 parent b226519 commit a109448

5 files changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.11
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
## Overview
2+
3+
This is a basic `dstack` plugin example.
4+
You can use it as a reference point when implementing new `dstack` plugins.
5+
6+
## Steps
7+
8+
1. Init the plugin package:
9+
10+
```
11+
uv init --library
12+
```
13+
14+
2. Define `ApplyPolicy` and `Plugin` subclasses:
15+
16+
```python
17+
from dstack.plugins import ApplyPolicy, Plugin, RunSpec, get_plugin_logger
18+
19+
20+
logger = get_plugin_logger(__name__)
21+
22+
23+
class ExamplePolicy(ApplyPolicy):
24+
25+
def on_run_apply(self, user: str, project: str, spec: RunSpec) -> RunSpec:
26+
# ...
27+
return spec
28+
29+
30+
class ExamplePlugin(Plugin):
31+
32+
def get_apply_policies(self) -> list[ApplyPolicy]:
33+
return [ExamplePolicy()]
34+
35+
```
36+
37+
3. Specify a "dstack.plugins" entry point in `pyproject.toml`:
38+
39+
```toml
40+
[project.entry-points."dstack.plugins"]
41+
example_plugin = "example_plugin:ExamplePlugin"
42+
```
43+
44+
4. Make sure to install the plugin and enable it in the `server/config.yml`:
45+
46+
```yaml
47+
plugins:
48+
- example_plugin
49+
projects:
50+
- name: main
51+
# ...
52+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[project]
2+
name = "example-plugin"
3+
version = "0.1.0"
4+
description = "A dstack plugin example"
5+
readme = "README.md"
6+
authors = [
7+
{ name = "Victor Skvortsov", email = "victor@dstack.ai" }
8+
]
9+
requires-python = ">=3.9"
10+
dependencies = []
11+
12+
[build-system]
13+
requires = ["hatchling"]
14+
build-backend = "hatchling.build"
15+
16+
[project.entry-points."dstack.plugins"]
17+
example_plugin = "example_plugin:ExamplePlugin"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from dstack.plugins import ApplyPolicy, GatewaySpec, Plugin, RunSpec, get_plugin_logger
2+
3+
logger = get_plugin_logger(__name__)
4+
5+
6+
class ExamplePolicy(ApplyPolicy):
7+
def on_run_apply(self, user: str, project: str, spec: RunSpec) -> RunSpec:
8+
# Forcing some limits
9+
spec.configuration.max_price = 2.0
10+
spec.configuration.max_duration = "1d"
11+
# Setting some extra tags
12+
if spec.configuration.tags is None:
13+
spec.configuration.tags = {}
14+
spec.configuration.tags |= {
15+
"team": "my_team",
16+
}
17+
# Forbid something
18+
if spec.configuration.privileged:
19+
logger.warning("User %s tries to run privileged containers", user)
20+
raise ValueError("Running privileged containers is forbidden")
21+
return spec
22+
23+
def on_gateway_apply(self, user: str, project: str, spec: GatewaySpec) -> GatewaySpec:
24+
# Forbid creating new gateways altogether
25+
raise ValueError("Creating gateways is forbidden")
26+
27+
28+
class ExamplePlugin(Plugin):
29+
def get_apply_policies(self) -> list[ApplyPolicy]:
30+
return [ExamplePolicy()]

examples/plugins/example_plugin/src/example_plugin/py.typed

Whitespace-only changes.

0 commit comments

Comments
 (0)