Sensors: per-service and container sensors, pattern-limited tokens, fleet query, steady sampler
- service.<unit>.active|state for services that are enabled, up or failed - containers.* and container.<name>.running|state|health|mem|cpu (cgroup reads, no docker stats) - sensors:read tokens can be limited to ID patterns, enforced on every endpoint and, through the hub's filter header, on managed machines; the header can only narrow - /api/fleet/sensors/query: one shaped query, every machine, one request - the sampler waits what's left of the interval, so 250 ms means 4 a second - Monitors asks for the families it draws instead of * - unpowered hwmon sentinels (-93 °C) are not temperatures Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
4ddf10be51
commit
4c2eb57ea6
@@ -31,7 +31,7 @@ function Preview({ vars }: { vars: Record<string, string> }) {
|
||||
export default function Settings({ me }: { me: Me }) {
|
||||
const [theme, setTheme] = useState(currentThemeId())
|
||||
const [refresh, setRefresh] = useState(getRefreshMs())
|
||||
const [tokens, setTokens] = useState<{ name: string; created: string; scope?: string }[] | null>(null)
|
||||
const [tokens, setTokens] = useState<{ name: string; created: string; scope?: string; sensors?: string[] }[] | null>(null)
|
||||
const [fresh, setFresh] = useState<{ name: string; token: string } | null>(null)
|
||||
const [cur, setCur] = useState('')
|
||||
const [pw1, setPw1] = useState('')
|
||||
@@ -104,7 +104,7 @@ export default function Settings({ me }: { me: Me }) {
|
||||
{tokens && tokens.map((t) => (
|
||||
<div className="row" key={t.name}>
|
||||
<span className="k mono">{t.name}</span>
|
||||
<span className="badge" style={{ marginLeft: 0 }}>{t.scope ? 'read-only' : 'full'}</span>
|
||||
<span className="badge" style={{ marginLeft: 0 }} title={t.sensors?.length ? t.sensors.join(', ') : undefined}>{t.scope ? (t.sensors?.length ? `read-only · ${t.sensors.join(' ')}` : 'read-only') : 'full'}</span>
|
||||
<span className="muted small">issued {new Date(t.created).toLocaleString()}</span>
|
||||
<Btn className="btn danger" onClick={() => revoke(t.name)}>Revoke</Btn>
|
||||
</div>
|
||||
@@ -121,7 +121,9 @@ export default function Settings({ me }: { me: Me }) {
|
||||
<Btn className="btn" onClick={async () => {
|
||||
const name = window.prompt('Name for the read-only token (what will use it)', 'glance')?.trim()
|
||||
if (!name) return
|
||||
try { setFresh(await api.createReadToken(name)); loadTokens() } catch (err) { toast(err instanceof Error ? err.message : 'failed', 'err') }
|
||||
const pats = window.prompt('Limit it to sensor patterns? Comma-separated, e.g. cpu.*, temp.*, zfs.tank.* — leave empty for every sensor', '')
|
||||
if (pats === null) return
|
||||
try { setFresh(await api.createReadToken(name, pats.split(',').map((x) => x.trim()).filter(Boolean))); loadTokens() } catch (err) { toast(err instanceof Error ? err.message : 'failed', 'err') }
|
||||
}}>+ Read-only sensor token</Btn>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user