pixie-lab-dibs 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dibs/__init__.py +15 -0
- dibs/_sources.py +153 -0
- dibs/_sshsig.py +87 -0
- dibs/_store.py +327 -0
- dibs/_users.py +251 -0
- dibs/app.py +344 -0
- dibs/cli.py +727 -0
- pixie_lab_dibs-0.1.0.dist-info/METADATA +253 -0
- pixie_lab_dibs-0.1.0.dist-info/RECORD +12 -0
- pixie_lab_dibs-0.1.0.dist-info/WHEEL +4 -0
- pixie_lab_dibs-0.1.0.dist-info/entry_points.txt +2 -0
- pixie_lab_dibs-0.1.0.dist-info/licenses/LICENSE +28 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pixie-lab-dibs
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Call dibs on shared lab machines: see who is using what, claim it, release it
|
|
5
|
+
Project-URL: Homepage, https://github.com/safl/pixie-lab-dibs
|
|
6
|
+
Author-email: "Simon A. F. Lund" <os@safl.dk>
|
|
7
|
+
License: BSD-3-Clause
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: claims,coordination,lab,pixie,reservation
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: fastapi>=0.115
|
|
17
|
+
Requires-Dist: httpx>=0.27
|
|
18
|
+
Requires-Dist: pyyaml>=6
|
|
19
|
+
Requires-Dist: tomlkit>=0.12
|
|
20
|
+
Requires-Dist: uvicorn[standard]>=0.30
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
<!--
|
|
24
|
+
SPDX-FileCopyrightText: Simon A. F. Lund <os@safl.dk>
|
|
25
|
+
|
|
26
|
+
SPDX-License-Identifier: BSD-3-Clause
|
|
27
|
+
-->
|
|
28
|
+
|
|
29
|
+
# dibs
|
|
30
|
+
|
|
31
|
+
[](https://github.com/safl/pixie-lab-dibs/actions/workflows/test.yml)
|
|
32
|
+
[](https://github.com/safl/pixie-lab-dibs/actions/workflows/format.yml)
|
|
33
|
+
[](https://pypi.org/project/pixie-lab-dibs/)
|
|
34
|
+
[](https://pypi.org/project/pixie-lab-dibs/)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
[](https://api.reuse.software/info/github.com/safl/pixie-lab-dibs)
|
|
37
|
+
|
|
38
|
+
Call dibs on shared lab machines.
|
|
39
|
+
|
|
40
|
+
A lab machine is shared with people, ai-agents and automation-runners.
|
|
41
|
+
dibs lets each of them see who is on a machine before touching it, by
|
|
42
|
+
claiming it. A claim is a note, not a lock: SSH and the console stay
|
|
43
|
+
open to everyone. Everywhere a claim shows up, it reads as one sentence:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
'alice' has claimed 'node-01' for 'xnvme' expires in: 'never'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
dibs keeps a list of **things** to claim, mostly machines. It fills the
|
|
50
|
+
list from **sources**: a config file, and any number of
|
|
51
|
+
[pixie](https://github.com/safl/pixie) servers, whose machines show up
|
|
52
|
+
on their own, with their hardware inventory.
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
uv tool install pixie-lab-dibs
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That gives you the `dibs` command, for both the server and the client.
|
|
61
|
+
Signing in uses `ssh-keygen` from OpenSSH 8.1 or newer.
|
|
62
|
+
|
|
63
|
+
## Run the server
|
|
64
|
+
|
|
65
|
+
On the host that will run it, list the things in `/etc/dibs/dibs.toml`:
|
|
66
|
+
|
|
67
|
+
```toml
|
|
68
|
+
[[pixie]]
|
|
69
|
+
url = "http://pixie:8080" # every machine pixie knows becomes a thing
|
|
70
|
+
|
|
71
|
+
[[thing]]
|
|
72
|
+
name = "ryzen-01" # a machine pixie does not boot
|
|
73
|
+
mac = "aa:bb:cc:dd:ee:ff" # any other key is kept as an attribute
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then make it a service and start it:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
sudo dibs server install
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The command writes a systemd unit for the `dibs` you ran, enables it
|
|
83
|
+
and starts it. `dibs server start`, `stop`, `restart`, `status` and
|
|
84
|
+
`logs` manage it from then on. The service runs as a throwaway system
|
|
85
|
+
user that owns only `/var/lib/dibs`. Without root, `dibs server install --user` installs a per-user service instead. For a quick try,
|
|
86
|
+
`dibs serve` runs the server in the foreground.
|
|
87
|
+
|
|
88
|
+
The system service can only run a `dibs` installed outside your home
|
|
89
|
+
directory, for example with
|
|
90
|
+
`sudo UV_TOOL_DIR=/opt/uv UV_TOOL_BIN_DIR=/usr/local/bin uv tool install pixie-lab-dibs`.
|
|
91
|
+
|
|
92
|
+
## Sign in
|
|
93
|
+
|
|
94
|
+
Claiming needs a user. Register a name with your SSH public key:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
export DIBS_URL=http://dibs:8090
|
|
98
|
+
dibs register alice
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The admin approves it on the server host:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
sudo dibs admin approve alice
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Then you log in once. `dibs` signs a one-time challenge with your key,
|
|
108
|
+
through your ssh-agent if the key lives there, and keeps the token it
|
|
109
|
+
gets back:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
dibs login
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The token does not expire; `dibs logout` drops it, and
|
|
116
|
+
`dibs admin revoke alice` ends every login alice has. `-i` picks a key
|
|
117
|
+
other than `~/.ssh/id_ed25519.pub`.
|
|
118
|
+
|
|
119
|
+
Over plain HTTP, a token can be read off the network. dibs gives claims
|
|
120
|
+
an identity among people who share a lab in good faith; it is not
|
|
121
|
+
protection against someone on that network. Put HTTPS in front of it if
|
|
122
|
+
the network is not trusted.
|
|
123
|
+
|
|
124
|
+
## Claim
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
dibs list [--mine]
|
|
128
|
+
dibs info <thing>
|
|
129
|
+
dibs claim <thing>... --for <purpose> [--expires 2h] [--force]
|
|
130
|
+
dibs release <thing>... | --mine
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
A claim never expires unless given `--expires`, and an expired claim
|
|
134
|
+
counts as free. Claiming several things is all or nothing: if any of
|
|
135
|
+
them is claimed by someone else, you get none, and the refusal says who
|
|
136
|
+
holds it. `--force` takes or releases someone else's claim, and the
|
|
137
|
+
server's log records that it did.
|
|
138
|
+
|
|
139
|
+
`list` and `info` print for people. Add `--json`, `--yaml` or `--toml`
|
|
140
|
+
to get the answer as data instead; an agent or script should use one of
|
|
141
|
+
those rather than parse the text.
|
|
142
|
+
|
|
143
|
+
The exit status is 0 when done, 1 when refused because someone else
|
|
144
|
+
holds a thing, and 2 for anything else.
|
|
145
|
+
|
|
146
|
+
### AI-agents
|
|
147
|
+
|
|
148
|
+
Point your agent at this section. An agent claims as its human, and
|
|
149
|
+
names itself the way an `Assisted-by:` trailer does:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
export DIBS_ASSISTED_BY="Claude Code:claude-opus-5-5"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The claim then reads `'alice' assisted by 'Claude Code:claude-opus-5-5' has claimed ...`.
|
|
156
|
+
|
|
157
|
+
If you are an agent reading this: before you run anything on a lab
|
|
158
|
+
machine, run `dibs list` and claim the machine with
|
|
159
|
+
`dibs claim <machine> --for <purpose>`. Never use a machine someone else
|
|
160
|
+
has claimed, and never pass `--force`; ask your human instead. Release
|
|
161
|
+
what you claimed with `dibs release --mine` when the work is done, and
|
|
162
|
+
also when it fails or is abandoned. That releases only what you claimed,
|
|
163
|
+
not your human's own claims.
|
|
164
|
+
|
|
165
|
+
### Automation-runners
|
|
166
|
+
|
|
167
|
+
Give the runner a user of its own: register it with a key made for it,
|
|
168
|
+
approve it, log in once, and store the token as the runner's
|
|
169
|
+
`DIBS_TOKEN` secret. A refused claim exits 1, which a runner can wait
|
|
170
|
+
out; anything else exits 2 and should fail the job. In GitHub Actions:
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
env:
|
|
174
|
+
DIBS_URL: http://dibs:8090
|
|
175
|
+
DIBS_TOKEN: ${{ secrets.DIBS_TOKEN }}
|
|
176
|
+
steps:
|
|
177
|
+
- name: Claim the machine
|
|
178
|
+
run: |
|
|
179
|
+
until dibs claim node-01 --for "${{ github.workflow }}" --expires 3h; do
|
|
180
|
+
[ $? -eq 1 ] || exit 1
|
|
181
|
+
sleep 60
|
|
182
|
+
done
|
|
183
|
+
- name: Test
|
|
184
|
+
run: ...
|
|
185
|
+
- name: Release the machine
|
|
186
|
+
if: always()
|
|
187
|
+
run: dibs release --mine
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `--expires` is a safety net for a runner that dies before its
|
|
191
|
+
release step.
|
|
192
|
+
|
|
193
|
+
## See the claim when you log in
|
|
194
|
+
|
|
195
|
+
Install the login hook on each machine. At every interactive login it
|
|
196
|
+
asks dibs for the machine's claim and prints it. It stays silent when
|
|
197
|
+
dibs is unreachable, and does nothing for non-interactive SSH such as
|
|
198
|
+
`scp`. It finds the machine by its MAC addresses, or else its hostname.
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
curl -fsS http://dibs:8090/login.sh | sudo tee /etc/profile.d/dibs.sh
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Shell completion
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
eval "$(dibs completion bash)"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Add that line to `~/.bashrc`, or write the script to
|
|
211
|
+
`/etc/bash_completion.d/dibs`. It completes commands and options, and
|
|
212
|
+
thing names from the server.
|
|
213
|
+
|
|
214
|
+
## HTTP
|
|
215
|
+
|
|
216
|
+
Anything that can send JSON can use dibs without the client. Reads need
|
|
217
|
+
no login; claim and release take `Authorization: Bearer <token>`.
|
|
218
|
+
|
|
219
|
+
| Route | |
|
|
220
|
+
| -------------------------- | -------------------------------------------------------------------------------------------- |
|
|
221
|
+
| `GET /things` | every thing, with its `sentence` and, while claimed, its `claim` |
|
|
222
|
+
| `GET /things/<name>` | one thing, plus `pixie` when a pixie server knows it |
|
|
223
|
+
| `GET /things/<name>/claim` | the sentence as one line of text |
|
|
224
|
+
| `POST /claims` | `{"things": [...], "purpose": "...", "assisted_by": "", "expires_in": null, "force": false}` |
|
|
225
|
+
| `POST /claims/release` | `{"things": [...], "force": false}`, or `{"mine": true, "assisted_by": ""}` |
|
|
226
|
+
| `POST /auth/register` | `{"user": "...", "pubkey": "ssh-ed25519 ..."}` |
|
|
227
|
+
| `POST /auth/challenge` | `{"user": "..."}` gives a nonce and the message to sign |
|
|
228
|
+
| `POST /auth/login` | `{"user", "nonce", "signature"}` gives a token |
|
|
229
|
+
| `GET /login.sh` | the login hook |
|
|
230
|
+
|
|
231
|
+
A claim or release blocked by someone else's claim answers 409 with
|
|
232
|
+
the blocking claims' sentences in `detail.claimed`.
|
|
233
|
+
|
|
234
|
+
## Releasing
|
|
235
|
+
|
|
236
|
+
Set the version in `src/dibs/__init__.py`, move the changelog's
|
|
237
|
+
`Unreleased` entries under that version, commit, and push a tag named
|
|
238
|
+
after it:
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
git tag v0.1.0 && git push origin v0.1.0
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
The tag runs the publish workflow, which checks the tag matches the
|
|
245
|
+
version, runs the checks, and uploads `pixie-lab-dibs` to PyPI through trusted
|
|
246
|
+
publishing.
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
BSD-3-Clause. The repository follows [REUSE](https://reuse.software):
|
|
251
|
+
every file states its copyright and license, `LICENSES/` holds the
|
|
252
|
+
license text, and `REUSE.toml` covers the files that cannot carry a
|
|
253
|
+
header.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
dibs/__init__.py,sha256=wbV9LyP-QOvy3h8mxz52ZL-5MbR6hmThKhwFSJkYlaM,520
|
|
2
|
+
dibs/_sources.py,sha256=59gRIXksQUCkaR28MRxNC9yUJlTsZA_Vxn1wJJ6Ra5w,5654
|
|
3
|
+
dibs/_sshsig.py,sha256=pT78XDvA0Fl3fdel4JS8w9wd4VvruFcF4ucN-zbctN0,2811
|
|
4
|
+
dibs/_store.py,sha256=ii6mmkb6ho7knRaRfiWSJxNhJZGsubrjOvSzP5cmALk,12265
|
|
5
|
+
dibs/_users.py,sha256=2MX-lE0xpRv74aVWMQAfMjmb1MbYMDiqoqxZeuHBKSI,9297
|
|
6
|
+
dibs/app.py,sha256=GPhxZnFirO3Q9idhYpzWmQ53qm9cla4WQEW4KtPBonM,13389
|
|
7
|
+
dibs/cli.py,sha256=F3mdcmYXaNzWD4GhBqsaTryV2wHRinT_omdY7BsI0J4,26379
|
|
8
|
+
pixie_lab_dibs-0.1.0.dist-info/METADATA,sha256=5s-Ez8k_V01tIUKCmfRDV6OOl1svFXgrBxVTIzNK72o,9353
|
|
9
|
+
pixie_lab_dibs-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
10
|
+
pixie_lab_dibs-0.1.0.dist-info/entry_points.txt,sha256=_-5VulNYH6io4gEuRmH5Omge0nkBZiQbTO-gydfh3S8,39
|
|
11
|
+
pixie_lab_dibs-0.1.0.dist-info/licenses/LICENSE,sha256=k28p1vD0tdx5EqOG2L93SQ6EGqXDQTWn4RMptaUyFm0,1503
|
|
12
|
+
pixie_lab_dibs-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Simon A. F. Lund
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|