From 9c702613de5aa2b66cb18eff1920ac940f78ba4f Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 16 May 2026 12:22:34 +0300 Subject: [PATCH] Expose VPN fabric stream shard install flags --- .../rap-node-agent/cmd/rap-host-agent/main.go | 18 ++++++ .../internal/hostagent/docker_test.go | 62 ++++++++++++------- .../DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md | 3 + 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/agents/rap-node-agent/cmd/rap-host-agent/main.go b/agents/rap-node-agent/cmd/rap-host-agent/main.go index 1f75aaa..6f122e3 100644 --- a/agents/rap-node-agent/cmd/rap-host-agent/main.go +++ b/agents/rap-node-agent/cmd/rap-host-agent/main.go @@ -218,6 +218,12 @@ func runInstallLinux(ctx context.Context, args []string) error { fs.BoolVar(&cfg.RuntimeConfig.MeshSyntheticRuntimeEnabled, "mesh-synthetic-runtime-enabled", getenvBool("RAP_MESH_SYNTHETIC_RUNTIME_ENABLED", true), "Enable synthetic mesh runtime.") fs.BoolVar(&cfg.RuntimeConfig.MeshProductionForwardingEnabled, "mesh-production-forwarding-enabled", getenvBool("RAP_MESH_PRODUCTION_FORWARDING_ENABLED", false), "Enable production forwarding gate; runtime still fail-closed if unavailable.") fs.BoolVar(&cfg.RuntimeConfig.MeshFabricSessionEnabled, "mesh-fabric-session-enabled", getenvBool("RAP_MESH_FABRIC_SESSION_ENABLED", false), "Enable authenticated fabric session WebSocket endpoint.") + fs.BoolVar(&cfg.RuntimeConfig.VPNFabricSessionTransportEnabled, "vpn-fabric-session-transport-enabled", getenvBool("RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED", false), "Route VPN packet transport over persistent fabric sessions.") + fs.BoolVar(&cfg.RuntimeConfig.MeshQUICFabricEnabled, "mesh-quic-fabric-enabled", getenvBool("RAP_MESH_QUIC_FABRIC_ENABLED", false), "Enable QUIC/UDP fabric listener.") + fs.StringVar(&cfg.RuntimeConfig.MeshQUICFabricListenAddr, "mesh-quic-fabric-listen-addr", getenv("RAP_MESH_QUIC_FABRIC_LISTEN_ADDR", ""), "QUIC/UDP fabric listen address.") + fs.IntVar(&cfg.RuntimeConfig.VPNFabricSessionStreamShards, "vpn-fabric-session-stream-shards", getenvInt("RAP_VPN_FABRIC_SESSION_STREAM_SHARDS", 4), "VPN fabric-session stream shards per traffic class.") + fs.IntVar(&cfg.RuntimeConfig.VPNFabricQUICMaxStreamsPerConn, "vpn-fabric-quic-max-streams-per-conn", getenvInt("RAP_VPN_FABRIC_QUIC_MAX_STREAMS_PER_CONN", 64), "Maximum logical fabric-session streams per cached VPN QUIC carrier connection.") + fs.IntVar(&cfg.RuntimeConfig.VPNFabricQUICIdleTTLSeconds, "vpn-fabric-quic-idle-ttl-seconds", getenvInt("RAP_VPN_FABRIC_QUIC_IDLE_TTL_SECONDS", 300), "Idle TTL seconds for cached VPN QUIC carrier connections.") fs.StringVar(&cfg.RuntimeConfig.MeshListenAddr, "mesh-listen-addr", getenv("RAP_MESH_LISTEN_ADDR", ":19131"), "Synthetic mesh HTTP listen address.") fs.StringVar(&cfg.RuntimeConfig.MeshListenPortMode, "mesh-listen-port-mode", getenv("RAP_MESH_LISTEN_PORT_MODE", "auto"), "Mesh listen port behavior: manual, auto, or disabled.") fs.IntVar(&cfg.RuntimeConfig.MeshListenAutoPortStart, "mesh-listen-auto-port-start", getenvInt("RAP_MESH_LISTEN_AUTO_PORT_START", 19131), "First port used when mesh listen port mode is auto.") @@ -300,6 +306,12 @@ func runInstallWindows(ctx context.Context, args []string) error { fs.BoolVar(&cfg.RuntimeConfig.MeshSyntheticRuntimeEnabled, "mesh-synthetic-runtime-enabled", getenvBool("RAP_MESH_SYNTHETIC_RUNTIME_ENABLED", true), "Enable synthetic mesh runtime.") fs.BoolVar(&cfg.RuntimeConfig.MeshProductionForwardingEnabled, "mesh-production-forwarding-enabled", getenvBool("RAP_MESH_PRODUCTION_FORWARDING_ENABLED", false), "Enable production forwarding gate; runtime still fail-closed if unavailable.") fs.BoolVar(&cfg.RuntimeConfig.MeshFabricSessionEnabled, "mesh-fabric-session-enabled", getenvBool("RAP_MESH_FABRIC_SESSION_ENABLED", false), "Enable authenticated fabric session WebSocket endpoint.") + fs.BoolVar(&cfg.RuntimeConfig.VPNFabricSessionTransportEnabled, "vpn-fabric-session-transport-enabled", getenvBool("RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED", false), "Route VPN packet transport over persistent fabric sessions.") + fs.BoolVar(&cfg.RuntimeConfig.MeshQUICFabricEnabled, "mesh-quic-fabric-enabled", getenvBool("RAP_MESH_QUIC_FABRIC_ENABLED", false), "Enable QUIC/UDP fabric listener.") + fs.StringVar(&cfg.RuntimeConfig.MeshQUICFabricListenAddr, "mesh-quic-fabric-listen-addr", getenv("RAP_MESH_QUIC_FABRIC_LISTEN_ADDR", ""), "QUIC/UDP fabric listen address.") + fs.IntVar(&cfg.RuntimeConfig.VPNFabricSessionStreamShards, "vpn-fabric-session-stream-shards", getenvInt("RAP_VPN_FABRIC_SESSION_STREAM_SHARDS", 4), "VPN fabric-session stream shards per traffic class.") + fs.IntVar(&cfg.RuntimeConfig.VPNFabricQUICMaxStreamsPerConn, "vpn-fabric-quic-max-streams-per-conn", getenvInt("RAP_VPN_FABRIC_QUIC_MAX_STREAMS_PER_CONN", 64), "Maximum logical fabric-session streams per cached VPN QUIC carrier connection.") + fs.IntVar(&cfg.RuntimeConfig.VPNFabricQUICIdleTTLSeconds, "vpn-fabric-quic-idle-ttl-seconds", getenvInt("RAP_VPN_FABRIC_QUIC_IDLE_TTL_SECONDS", 300), "Idle TTL seconds for cached VPN QUIC carrier connections.") fs.StringVar(&cfg.RuntimeConfig.MeshListenAddr, "mesh-listen-addr", getenv("RAP_MESH_LISTEN_ADDR", ":19131"), "Synthetic mesh HTTP listen address.") fs.StringVar(&cfg.RuntimeConfig.MeshListenPortMode, "mesh-listen-port-mode", getenv("RAP_MESH_LISTEN_PORT_MODE", "auto"), "Mesh listen port behavior: manual, auto, or disabled.") fs.IntVar(&cfg.RuntimeConfig.MeshListenAutoPortStart, "mesh-listen-auto-port-start", getenvInt("RAP_MESH_LISTEN_AUTO_PORT_START", 19131), "First port used when mesh listen port mode is auto.") @@ -788,6 +800,12 @@ func parseInstall(args []string) (installCommandConfig, error) { fs.BoolVar(&cfg.MeshSyntheticRuntimeEnabled, "mesh-synthetic-runtime-enabled", getenvBool("RAP_MESH_SYNTHETIC_RUNTIME_ENABLED", false), "Enable synthetic mesh runtime.") fs.BoolVar(&cfg.MeshProductionForwardingEnabled, "mesh-production-forwarding-enabled", getenvBool("RAP_MESH_PRODUCTION_FORWARDING_ENABLED", false), "Enable production forwarding gate; runtime still fail-closed if unavailable.") fs.BoolVar(&cfg.MeshFabricSessionEnabled, "mesh-fabric-session-enabled", getenvBool("RAP_MESH_FABRIC_SESSION_ENABLED", false), "Enable authenticated fabric session WebSocket endpoint.") + fs.BoolVar(&cfg.VPNFabricSessionTransportEnabled, "vpn-fabric-session-transport-enabled", getenvBool("RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED", false), "Route VPN packet transport over persistent fabric sessions.") + fs.BoolVar(&cfg.MeshQUICFabricEnabled, "mesh-quic-fabric-enabled", getenvBool("RAP_MESH_QUIC_FABRIC_ENABLED", false), "Enable QUIC/UDP fabric listener.") + fs.StringVar(&cfg.MeshQUICFabricListenAddr, "mesh-quic-fabric-listen-addr", getenv("RAP_MESH_QUIC_FABRIC_LISTEN_ADDR", ""), "QUIC/UDP fabric listen address.") + fs.IntVar(&cfg.VPNFabricSessionStreamShards, "vpn-fabric-session-stream-shards", getenvInt("RAP_VPN_FABRIC_SESSION_STREAM_SHARDS", 4), "VPN fabric-session stream shards per traffic class.") + fs.IntVar(&cfg.VPNFabricQUICMaxStreamsPerConn, "vpn-fabric-quic-max-streams-per-conn", getenvInt("RAP_VPN_FABRIC_QUIC_MAX_STREAMS_PER_CONN", 64), "Maximum logical fabric-session streams per cached VPN QUIC carrier connection.") + fs.IntVar(&cfg.VPNFabricQUICIdleTTLSeconds, "vpn-fabric-quic-idle-ttl-seconds", getenvInt("RAP_VPN_FABRIC_QUIC_IDLE_TTL_SECONDS", 300), "Idle TTL seconds for cached VPN QUIC carrier connections.") fs.StringVar(&cfg.MeshListenAddr, "mesh-listen-addr", getenv("RAP_MESH_LISTEN_ADDR", ""), "Synthetic mesh HTTP listen address inside container.") fs.StringVar(&cfg.MeshListenPortMode, "mesh-listen-port-mode", getenv("RAP_MESH_LISTEN_PORT_MODE", ""), "Mesh listen port behavior: manual, auto, or disabled.") fs.IntVar(&cfg.MeshListenAutoPortStart, "mesh-listen-auto-port-start", getenvInt("RAP_MESH_LISTEN_AUTO_PORT_START", 0), "First port used when mesh listen port mode is auto.") diff --git a/agents/rap-node-agent/internal/hostagent/docker_test.go b/agents/rap-node-agent/internal/hostagent/docker_test.go index 4ee9185..a32b545 100644 --- a/agents/rap-node-agent/internal/hostagent/docker_test.go +++ b/agents/rap-node-agent/internal/hostagent/docker_test.go @@ -58,17 +58,23 @@ func (r *imagePresentRunner) Run(_ context.Context, name string, args ...string) func TestDockerRunArgsBuildNodeRuntimePlacement(t *testing.T) { args := DockerRunArgs(RuntimeConfig{ - BackendURL: "http://control/api/v1/", - ClusterID: "cluster-1", - JoinToken: "join-secret", - NodeName: "node-a", - Image: "rap-node-agent:test", - ContainerName: "rap-node-agent-node-a", - StateDir: "/srv/rap/node-a", - MeshSyntheticRuntimeEnabled: true, - MeshListenAddr: ":19131", - MeshAdvertiseEndpoint: "http://10.0.0.11:19131/", - MeshConnectivityMode: "private_lan", + BackendURL: "http://control/api/v1/", + ClusterID: "cluster-1", + JoinToken: "join-secret", + NodeName: "node-a", + Image: "rap-node-agent:test", + ContainerName: "rap-node-agent-node-a", + StateDir: "/srv/rap/node-a", + MeshSyntheticRuntimeEnabled: true, + VPNFabricSessionTransportEnabled: true, + MeshQUICFabricEnabled: true, + MeshQUICFabricListenAddr: ":19443", + VPNFabricSessionStreamShards: 6, + VPNFabricQUICMaxStreamsPerConn: 24, + VPNFabricQUICIdleTTLSeconds: 120, + MeshListenAddr: ":19131", + MeshAdvertiseEndpoint: "http://10.0.0.11:19131/", + MeshConnectivityMode: "private_lan", }) joined := strings.Join(args, "\x00") @@ -81,6 +87,12 @@ func TestDockerRunArgsBuildNodeRuntimePlacement(t *testing.T) { "RAP_NODE_STATE_DIR=/var/lib/rap-node-agent", "RAP_ENROLLMENT_POLL_TIMEOUT_SECONDS=0", "RAP_MESH_SYNTHETIC_RUNTIME_ENABLED=true", + "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED=true", + "RAP_MESH_QUIC_FABRIC_ENABLED=true", + "RAP_MESH_QUIC_FABRIC_LISTEN_ADDR=:19443", + "RAP_VPN_FABRIC_SESSION_STREAM_SHARDS=6", + "RAP_VPN_FABRIC_QUIC_MAX_STREAMS_PER_CONN=24", + "RAP_VPN_FABRIC_QUIC_IDLE_TTL_SECONDS=120", "RAP_MESH_LISTEN_ADDR=:19131", "RAP_MESH_ADVERTISE_ENDPOINT=http://10.0.0.11:19131", "RAP_MESH_CONNECTIVITY_MODE=private_lan", @@ -156,13 +168,17 @@ func TestFetchDockerInstallProfileBuildsRuntimeConfig(t *testing.T) { "file_name": "rap-node-agent-test.tar", "size_bytes": 21, }, - "container_name": "rap-node-agent-node-a", - "state_dir": "/var/lib/rap/nodes/node-a", - "network": "host", - "restart_policy": "unless-stopped", - "replace": true, - "mesh_synthetic_runtime_enabled": true, - "mesh_connectivity_mode": "outbound_only", + "container_name": "rap-node-agent-node-a", + "state_dir": "/var/lib/rap/nodes/node-a", + "network": "host", + "restart_policy": "unless-stopped", + "replace": true, + "mesh_synthetic_runtime_enabled": true, + "vpn_fabric_session_transport_enabled": true, + "mesh_quic_fabric_enabled": true, + "mesh_quic_fabric_listen_addr": ":19443", + "vpn_fabric_session_stream_shards": 6, + "mesh_connectivity_mode": "outbound_only", }, }) })) @@ -185,6 +201,10 @@ func TestFetchDockerInstallProfileBuildsRuntimeConfig(t *testing.T) { len(cfg.ImageArtifactURLs) != 1 || cfg.ImageArtifactSizeBytes != 21 || !cfg.MeshSyntheticRuntimeEnabled || + !cfg.VPNFabricSessionTransportEnabled || + !cfg.MeshQUICFabricEnabled || + cfg.MeshQUICFabricListenAddr != ":19443" || + cfg.VPNFabricSessionStreamShards != 6 || cfg.MeshConnectivityMode != "outbound_only" { t.Fatalf("unexpected cfg: %+v", cfg) } @@ -240,9 +260,9 @@ func TestInstallAcceptsSizeMismatchWhenChecksumMissing(t *testing.T) { ContainerName: "rap-node-agent-node-a", StateDir: "rap-node-state", Replace: true, - ImageArtifactURLs: []string{server.URL + "/rap-node-agent-test.tar"}, - ImageArtifactSHA256: "", // intentionally absent -> size mismatch should not block install - ImageArtifactSizeBytes: wrongSize, + ImageArtifactURLs: []string{server.URL + "/rap-node-agent-test.tar"}, + ImageArtifactSHA256: "", // intentionally absent -> size mismatch should not block install + ImageArtifactSizeBytes: wrongSize, }) if err != nil { t.Fatalf("install: %v", err) diff --git a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md index 27b1590..c1d6e69 100644 --- a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md +++ b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md @@ -383,6 +383,9 @@ declaring that carrier failed. VPN fabric-session transport now opens configurable per-class stream shards for interactive and bulk packet traffic, so heavy browser flows do not share a single logical stream with latency-sensitive RDP/control packets. +Host-agent install commands for Docker, Linux, and Windows expose the same +VPN fabric-session/QUIC tuning flags as install profiles, keeping manual and +profile-based rollout paths aligned. Gateway runtime snapshots include the fabric-session packet transport stream layout and send counters by traffic class/stream id for load-test diagnosis. Endpoint ranking treats `capacity_limited` observations as a soft pressure