test(mesh): step 7 — replace the boundary test with MeshGrpcBoundaryTests and sweep the comments
MeshGrpcBoundaryTests replaces the MeshClusterClientBoundaryTests deleted in step 1. Three
self-seeded single-member clusters sharing the ActorSystem name, joined ONLY by gRPC, driving
the REAL CentralCommunicationActor -> MeshGrpcCommandDialer -> Kestrel h2c ->
MeshCommandAuthInterceptor -> NodeCommandGrpcService -> NodeCommunicationActor -> EventStream:
1. No_cross_mesh_Akka_association_forms_between_central_and_either_site — the program's own
point, kept as a test rather than a live-gate note: each cluster stays single-member and
none ever holds another's address as a member.
2. One_dispatch_through_central_reaches_a_node_in_every_cluster_mesh — the fan, with each
site holding its OWN per-cluster PSK, so a dial that selected the wrong cluster's key
would be refused at the far side.
3. Falsifiability_control_a_dial_carrying_the_wrong_cluster_key_delivers_nothing — without
it, (2) cannot distinguish "the gRPC boundary carried it" from "something else in the
process did". The same node then accepts the right key, so the silence is the auth gate
and not a dead endpoint.
All three run fully offline — no Docker fixture — and pass.
Comment sweep across every remaining clusterclient|receptionist hit in src/ and tests/:
the program label becomes "mesh gRPC command plane", and every comment that described the
deleted transport as live now describes what actually runs (Dps = pair-local default,
Grpc = cross-mesh). mesh_transport.proto's header/service comments are reworded; no message,
field or enum is touched — the contract is locked. MeshCommActorPathTests is reshaped rather
than retired: the two paths still exist and still matter, but what a mismatch costs is now a
misleading Unavailable from the gRPC ingress rather than a silently dropped receptionist send.
The only surviving mentions of the old names are the ones that must survive: the fail-closed
rules that name "ClusterClient" as a retired value refused at boot, their tests, and this
test class's own account of what it replaces.
This commit is contained in:
@@ -527,20 +527,19 @@ if (hasAdmin)
|
||||
// hosted service has built the system).
|
||||
builder.Services.TryAddSingleton<Func<ActorSystem>>(sp => () => sp.GetRequiredService<ActorSystem>());
|
||||
builder.Services.AddSingleton<IManualFailoverService, ManualFailoverService>();
|
||||
// Per-cluster mesh PSKs (ClusterClient→gRPC). Admin-only, and singleton because its whole job is
|
||||
// Per-cluster mesh PSKs (mesh gRPC command plane). Admin-only, and singleton because its whole job is
|
||||
// to hold a cache: central talks to N clusters and would otherwise re-read the secret store on
|
||||
// every inbound ack. A node needs nothing of this — it holds exactly its own MeshTransport:GrpcPsk
|
||||
// — so registering it fleet-wide would give a driver-only node a lookup it can never use.
|
||||
// Depends on ISecretResolver, which AddOtOpcUaSecrets registers unconditionally below (DI
|
||||
// registration order is irrelevant; resolution order is not).
|
||||
builder.Services.AddSingleton<IMeshPskProvider, MeshPskProvider>();
|
||||
// Central's outbound command dial (ClusterClient→gRPC Phase 1A). Admin-only for the same reason
|
||||
// Central's outbound command dial (mesh gRPC command plane, Phase 1A). Admin-only for the same reason
|
||||
// as the provider above — a node never dials another node — and singleton because it owns a
|
||||
// GrpcChannel per node endpoint; per-call channels would leak sockets across a fleet-wide fan.
|
||||
// Registered in every mode: CentralCommunicationActor only reaches it under Mode=Grpc, and an
|
||||
// idle registration costs nothing, whereas gating it here would mean flipping the mode on a
|
||||
// running fleet needs a central restart before any command lands — the same reasoning that
|
||||
// registers the ClusterClient receptionist unconditionally.
|
||||
// running fleet needs a central restart before any command lands.
|
||||
builder.Services.AddSingleton<IMeshCommandDialer, MeshGrpcCommandDialer>();
|
||||
}
|
||||
|
||||
@@ -564,7 +563,7 @@ builder.Services.AddOtOpcUaObservability(builder.Configuration);
|
||||
// Registered whenever either role is present so an admin-only node still serves config and a
|
||||
// driver-only node still gates sync + telemetry.
|
||||
//
|
||||
// The two mesh-command interceptors (ClusterClient→gRPC migration) join on the same terms:
|
||||
// The two mesh-command interceptors (mesh gRPC command plane) join on the same terms:
|
||||
// MeshCommandAuthInterceptor gates the node-side NodeCommandService (driver-role, one key — this
|
||||
// node's own), CentralCommandAuthInterceptor gates the central-side CentralCommandService
|
||||
// (admin-role, one key per cluster via IMeshPskProvider). Both are registered NOW and are pure
|
||||
@@ -745,7 +744,7 @@ if (hasAdmin && configServeGrpcPort > 0)
|
||||
{
|
||||
app.MapGrpcService<DeploymentArtifactGrpcService>();
|
||||
|
||||
// Central command ingress (ClusterClient→gRPC migration): the node→central deployment ack. It
|
||||
// Central command ingress (mesh gRPC command plane): the node→central deployment ack. It
|
||||
// rides the SAME listener rather than claiming a port of its own — a second cleartext h2c port
|
||||
// would buy nothing but another firewall rule, and both endpoints are admin-role and dialled by
|
||||
// the same driver nodes. Deliberately NOT gated on MeshTransport:Mode: mapping it under Dps
|
||||
@@ -759,7 +758,7 @@ if (hasAdmin && configServeGrpcPort > 0)
|
||||
// Driver-node live-telemetry stream (per-cluster mesh Phase 5). Central dials in; gated by
|
||||
// TelemetryStreamAuthInterceptor (fail-closed on empty Telemetry:ApiKey).
|
||||
//
|
||||
// The node-side command endpoint (ClusterClient→gRPC migration Phase 1) rides the SAME driver-role
|
||||
// The node-side command endpoint (mesh gRPC command plane, Phase 1) rides the SAME driver-role
|
||||
// h2c listener rather than claiming a fourth port: central already dials this node here, both
|
||||
// directions are per-cluster-keyed, and a separate port would be one more thing to open on every
|
||||
// site firewall for no isolation gain. Mapping it is what makes MeshCommandAuthInterceptor live —
|
||||
|
||||
Reference in New Issue
Block a user