swarm: grant the controller STREAM.MSG.GET; list subagents concurrently
GET /api/agents/{name}/subagents reads each subagent's newest row with
get_last_raw_message_by_subject, which publishes
$JS.API.STREAM.MSG.GET.term-sub-<agent>. The controller's NATS grant had
no STREAM.MSG.GET, so every lookup was refused and waited the 10s request
timeout, one subagent after another; six subagents passed nginx's 60s.
Grant `$JS.API.STREAM.MSG.GET.*`. A wildcard matches a whole subject
token only, so a `term-sub-*` spelling would name one stream literally;
`*` is the narrowest grant that covers the per-agent streams, the same
width as the controller's STREAM.INFO.* grant.
The lookups now run concurrently (16 at a time) with a 2s timeout each.
A lookup that fails or times out lists its subagent with a null
last_row_unix, and one warn per request names how many failed and the
first error.
This commit is contained in:
parent
6ce01ff38d
commit
d81fb2236f
3 changed files with 76 additions and 26 deletions
|
|
@ -540,6 +540,14 @@ impl Policy {
|
|||
"$JS.API.STREAM.INFO.*".to_owned(),
|
||||
"$JS.API.STREAM.CREATE.*".to_owned(),
|
||||
"$JS.API.DIRECT.GET.*.>".to_owned(),
|
||||
// The newest row of one subagent in `term-sub-<agent>`, which the
|
||||
// subagent list reads by subject. Those streams do not allow
|
||||
// direct get, so `DIRECT.GET` above does not reach them. `*` is a
|
||||
// whole token: `term-sub-*` would name one stream literally, and
|
||||
// the agent is not known here. Also reaches every other stream's
|
||||
// `MSG.GET`, the same width as `STREAM.INFO.*` above. A refused
|
||||
// publish reaches the client as a timeout.
|
||||
"$JS.API.STREAM.MSG.GET.*".to_owned(),
|
||||
"$KV.*.>".to_owned(),
|
||||
]);
|
||||
// The per-agent status bucket, read-side only. Same five subjects as
|
||||
|
|
@ -1171,6 +1179,25 @@ mod tests {
|
|||
assert!(p.publish.contains(&"$JS.API.STREAM.CREATE.*".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_controller_may_read_a_subagents_newest_row() {
|
||||
let p = policy()
|
||||
.permissions("swarm-controller")
|
||||
.expect("a reader is admitted");
|
||||
assert!(p.publish.contains(&"$JS.API.STREAM.MSG.GET.*".to_owned()));
|
||||
// `*` only matches a whole token, so a prefix spelling grants one
|
||||
// stream literally named that and reads nothing.
|
||||
assert!(!p.publish.iter().any(|s| s.contains("term-sub-*")));
|
||||
// Control: a hive's grant holds no `MSG.GET`, so the subject above is
|
||||
// the controller's alone.
|
||||
assert!(
|
||||
!policy()
|
||||
.hive_subjects("alpha")
|
||||
.iter()
|
||||
.any(|s| s.starts_with("$JS.API.STREAM.MSG.GET"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_notices_stream_grant_is_identical_across_hives() {
|
||||
// Unlike `$KV.<bucket>.<hive>` or an `extra_hive_subjects`
|
||||
|
|
|
|||
Loading…
Reference in a new issue