diff --git a/agents/rap-node-agent/cmd/rap-node-agent/main.go b/agents/rap-node-agent/cmd/rap-node-agent/main.go index 8d123b9..2efc567 100644 --- a/agents/rap-node-agent/cmd/rap-node-agent/main.go +++ b/agents/rap-node-agent/cmd/rap-node-agent/main.go @@ -1115,6 +1115,7 @@ func meshListenerConfigKey(cfg config.Config) string { strings.TrimSpace(cfg.MeshNATType), strings.TrimSpace(cfg.MeshRegion), fmt.Sprintf("%t", cfg.MeshProductionForwardingEnabled), + fmt.Sprintf("%t", cfg.VPNFabricSessionTransportEnabled), }, "|") } @@ -2480,6 +2481,18 @@ func heartbeatPayload(cfg config.Config, identity state.Identity, meshState *syn payload.Capabilities["fabric_session_websocket_endpoint"] = true payload.Capabilities["fabric_data_session_v1"] = true } + if cfg.VPNFabricSessionTransportEnabled { + payload.Metadata["vpn_fabric_session_transport_report"] = map[string]any{ + "schema_version": "rap.vpn_fabric_session_transport_report.v1", + "enabled": true, + "transport": "fabric_session_websocket_binary_frames", + "packet_payload": "rap.vpn_packet_batch.fabric.v1", + "gated": true, + "observed_at": observedAt.UTC().Format(time.RFC3339Nano), + } + payload.Capabilities["vpn_fabric_session_transport"] = true + payload.Capabilities["vpn_packet_batch_binary_frames"] = true + } if meshState != nil && meshState.ConfigLoadError != "" { payload.HealthStatus = "warning" } @@ -3724,6 +3737,7 @@ func advertisedEndpointCandidates(cfg config.Config, identity state.Identity, me "runtime": "c17z7", "synthetic_runtime": cfg.MeshSyntheticRuntimeEnabled, "production_forwarding": cfg.MeshProductionForwardingEnabled, + "vpn_fabric_session": cfg.VPNFabricSessionTransportEnabled, }) if err != nil { return nil, err diff --git a/agents/rap-node-agent/cmd/rap-node-agent/main_test.go b/agents/rap-node-agent/cmd/rap-node-agent/main_test.go index 5fddc99..937afcd 100644 --- a/agents/rap-node-agent/cmd/rap-node-agent/main_test.go +++ b/agents/rap-node-agent/cmd/rap-node-agent/main_test.go @@ -627,14 +627,15 @@ func TestProductionEnvelopeObservationSinkFromConfigIsDisabledByDefault(t *testi func TestHeartbeatPayloadIncludesMeshEndpointReport(t *testing.T) { payload := heartbeatPayload(config.Config{ - MeshAdvertiseEndpoint: "https://node-a.example.test:443", - MeshAdvertiseTransport: "wss", - MeshConnectivityMode: "outbound_only", - MeshNATType: "symmetric", - MeshRegion: "eu", - MeshSyntheticRuntimeEnabled: true, - MeshProductionForwardingEnabled: true, - MeshFabricSessionEnabled: true, + MeshAdvertiseEndpoint: "https://node-a.example.test:443", + MeshAdvertiseTransport: "wss", + MeshConnectivityMode: "outbound_only", + MeshNATType: "symmetric", + MeshRegion: "eu", + MeshSyntheticRuntimeEnabled: true, + MeshProductionForwardingEnabled: true, + MeshFabricSessionEnabled: true, + VPNFabricSessionTransportEnabled: true, }, state.Identity{ ClusterID: "cluster-1", NodeID: "node-a", @@ -659,6 +660,12 @@ func TestHeartbeatPayloadIncludesMeshEndpointReport(t *testing.T) { if report, ok := payload.Metadata["fabric_session_endpoint_report"].(map[string]any); !ok || report["path"] != "/mesh/v1/fabric/session/ws" { t.Fatalf("fabric session endpoint report missing: %+v", payload.Metadata) } + if payload.Capabilities["vpn_fabric_session_transport"] != true || payload.Capabilities["vpn_packet_batch_binary_frames"] != true { + t.Fatalf("vpn fabric session capabilities missing: %+v", payload.Capabilities) + } + if report, ok := payload.Metadata["vpn_fabric_session_transport_report"].(map[string]any); !ok || report["packet_payload"] != "rap.vpn_packet_batch.fabric.v1" { + t.Fatalf("vpn fabric session report missing: %+v", payload.Metadata) + } } func TestHeartbeatPayloadReportsMeshListenerFailureWithoutKillingHeartbeat(t *testing.T) { diff --git a/agents/rap-node-agent/internal/config/config.go b/agents/rap-node-agent/internal/config/config.go index 20fb744..4b1a06e 100644 --- a/agents/rap-node-agent/internal/config/config.go +++ b/agents/rap-node-agent/internal/config/config.go @@ -27,6 +27,7 @@ type Config struct { MeshSyntheticRuntimeEnabled bool MeshProductionForwardingEnabled bool MeshFabricSessionEnabled bool + VPNFabricSessionTransportEnabled bool MeshProductionObservationSinkCapacity int MeshListenAddr string MeshListenPortMode string @@ -65,6 +66,7 @@ func Load(args []string, env map[string]string) (Config, error) { fs.BoolVar(&cfg.MeshSyntheticRuntimeEnabled, "mesh-synthetic-runtime-enabled", getEnvBool(env, "RAP_MESH_SYNTHETIC_RUNTIME_ENABLED", false), "Enable C17A synthetic fabric probe runtime. Disabled by default.") fs.BoolVar(&cfg.MeshProductionForwardingEnabled, "mesh-production-forwarding-enabled", getEnvBool(env, "RAP_MESH_PRODUCTION_FORWARDING_ENABLED", false), "Enable production fabric-control direct next-hop forwarding gate. Disabled by default.") fs.BoolVar(&cfg.MeshFabricSessionEnabled, "mesh-fabric-session-enabled", getEnvBool(env, "RAP_MESH_FABRIC_SESSION_ENABLED", false), "Enable authenticated fabric session WebSocket endpoint. Disabled by default.") + fs.BoolVar(&cfg.VPNFabricSessionTransportEnabled, "vpn-fabric-session-transport-enabled", getEnvBool(env, "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED", false), "Route VPN packet transport over persistent fabric session when explicitly enabled. Disabled by default.") fs.IntVar(&cfg.MeshProductionObservationSinkCapacity, "mesh-production-observation-sink-capacity", getEnvSignedInt(env, "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY", 0), "Bounded local metadata-only production envelope observation sink capacity. Disabled when 0.") fs.StringVar(&cfg.MeshListenAddr, "mesh-listen-addr", getEnv(env, "RAP_MESH_LISTEN_ADDR", ""), "Listen address for disabled-by-default C17E synthetic mesh HTTP endpoint.") fs.StringVar(&cfg.MeshListenPortMode, "mesh-listen-port-mode", getEnv(env, "RAP_MESH_LISTEN_PORT_MODE", "manual"), "Mesh listen port behavior: manual, auto, or disabled.") diff --git a/agents/rap-node-agent/internal/config/config_test.go b/agents/rap-node-agent/internal/config/config_test.go index 7d2864b..dfd6a72 100644 --- a/agents/rap-node-agent/internal/config/config_test.go +++ b/agents/rap-node-agent/internal/config/config_test.go @@ -21,6 +21,7 @@ func TestLoadConfigFromEnvAndArgs(t *testing.T) { "RAP_MESH_SYNTHETIC_RUNTIME_ENABLED": "true", "RAP_MESH_PRODUCTION_FORWARDING_ENABLED": "true", "RAP_MESH_FABRIC_SESSION_ENABLED": "true", + "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED": "true", "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY": "5", "RAP_MESH_LISTEN_ADDR": "127.0.0.1:19001", "RAP_MESH_LISTEN_PORT_MODE": "auto", @@ -70,6 +71,9 @@ func TestLoadConfigFromEnvAndArgs(t *testing.T) { if !cfg.MeshFabricSessionEnabled { t.Fatal("MeshFabricSessionEnabled = false, want true") } + if !cfg.VPNFabricSessionTransportEnabled { + t.Fatal("VPNFabricSessionTransportEnabled = false, want true") + } if cfg.MeshProductionObservationSinkCapacity != 5 { t.Fatalf("MeshProductionObservationSinkCapacity = %d, want 5", cfg.MeshProductionObservationSinkCapacity) } diff --git a/agents/rap-node-agent/internal/hostagent/config.go b/agents/rap-node-agent/internal/hostagent/config.go index 0429561..2c5e5f6 100644 --- a/agents/rap-node-agent/internal/hostagent/config.go +++ b/agents/rap-node-agent/internal/hostagent/config.go @@ -14,41 +14,42 @@ const ( ) type RuntimeConfig struct { - BackendURL string - ClusterID string - JoinToken string - NodeName string - Image string - ContainerName string - StateDir string - Network string - RestartPolicy string - PullImage bool - Replace bool - DockerVPNGatewayEnabled bool - WorkloadSupervisionEnabled bool - MeshSyntheticRuntimeEnabled bool - MeshProductionForwardingEnabled bool - MeshFabricSessionEnabled bool - MeshListenAddr string - MeshListenPortMode string - MeshListenAutoPortStart int - MeshListenAutoPortEnd int - MeshAdvertiseEndpoint string - MeshAdvertiseEndpointsJSON string - MeshAdvertiseTransport string - MeshConnectivityMode string - MeshNATType string - MeshRegion string - HeartbeatIntervalSeconds int - EnrollmentPollIntervalSeconds int - EnrollmentPollTimeoutSeconds int - ExtraEnv []string - AdditionalDockerRunArgs []string - ProductionObservationSinkCap int - ImageArtifactURLs []string - ImageArtifactSHA256 string - ImageArtifactSizeBytes int64 + BackendURL string + ClusterID string + JoinToken string + NodeName string + Image string + ContainerName string + StateDir string + Network string + RestartPolicy string + PullImage bool + Replace bool + DockerVPNGatewayEnabled bool + WorkloadSupervisionEnabled bool + MeshSyntheticRuntimeEnabled bool + MeshProductionForwardingEnabled bool + MeshFabricSessionEnabled bool + VPNFabricSessionTransportEnabled bool + MeshListenAddr string + MeshListenPortMode string + MeshListenAutoPortStart int + MeshListenAutoPortEnd int + MeshAdvertiseEndpoint string + MeshAdvertiseEndpointsJSON string + MeshAdvertiseTransport string + MeshConnectivityMode string + MeshNATType string + MeshRegion string + HeartbeatIntervalSeconds int + EnrollmentPollIntervalSeconds int + EnrollmentPollTimeoutSeconds int + ExtraEnv []string + AdditionalDockerRunArgs []string + ProductionObservationSinkCap int + ImageArtifactURLs []string + ImageArtifactSHA256 string + ImageArtifactSizeBytes int64 } func (cfg RuntimeConfig) Normalize() RuntimeConfig { diff --git a/agents/rap-node-agent/internal/hostagent/docker.go b/agents/rap-node-agent/internal/hostagent/docker.go index 70ea9f0..0141559 100644 --- a/agents/rap-node-agent/internal/hostagent/docker.go +++ b/agents/rap-node-agent/internal/hostagent/docker.go @@ -265,6 +265,7 @@ func NodeAgentEnvWithStateDir(cfg RuntimeConfig, stateDir string) []string { "RAP_MESH_SYNTHETIC_RUNTIME_ENABLED=" + boolString(cfg.MeshSyntheticRuntimeEnabled), "RAP_MESH_PRODUCTION_FORWARDING_ENABLED=" + boolString(cfg.MeshProductionForwardingEnabled), "RAP_MESH_FABRIC_SESSION_ENABLED=" + boolString(cfg.MeshFabricSessionEnabled), + "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED=" + boolString(cfg.VPNFabricSessionTransportEnabled), } if cfg.JoinToken != "" { env = append(env, "RAP_JOIN_TOKEN="+cfg.JoinToken) diff --git a/agents/rap-node-agent/internal/hostagent/linux.go b/agents/rap-node-agent/internal/hostagent/linux.go index 4430432..ce3fb47 100644 --- a/agents/rap-node-agent/internal/hostagent/linux.go +++ b/agents/rap-node-agent/internal/hostagent/linux.go @@ -64,29 +64,30 @@ func LinuxInstallConfigFromProfile(profile LinuxInstallProfile) LinuxInstallConf installDir := firstNonEmpty(profile.InstallDir, filepath.Join(DefaultLinuxInstallRoot, safeUnitSlug(profile.NodeName))) return LinuxInstallConfig{ RuntimeConfig: RuntimeConfig{ - BackendURL: profile.BackendURL, - ClusterID: profile.ClusterID, - JoinToken: profile.JoinToken, - NodeName: profile.NodeName, - StateDir: stateDir, - WorkloadSupervisionEnabled: profile.WorkloadSupervisionEnabled, - MeshSyntheticRuntimeEnabled: profile.MeshSyntheticRuntimeEnabled, - MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled, - MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled, - MeshListenAddr: profile.MeshListenAddr, - MeshListenPortMode: profile.MeshListenPortMode, - MeshListenAutoPortStart: profile.MeshListenAutoPortStart, - MeshListenAutoPortEnd: profile.MeshListenAutoPortEnd, - MeshAdvertiseEndpoint: profile.MeshAdvertiseEndpoint, - MeshAdvertiseEndpointsJSON: string(profile.MeshAdvertiseEndpointsJSON), - MeshAdvertiseTransport: profile.MeshAdvertiseTransport, - MeshConnectivityMode: profile.MeshConnectivityMode, - MeshNATType: profile.MeshNATType, - MeshRegion: profile.MeshRegion, - HeartbeatIntervalSeconds: profile.HeartbeatIntervalSeconds, - EnrollmentPollIntervalSeconds: profile.EnrollmentPollIntervalSeconds, - EnrollmentPollTimeoutSeconds: profile.EnrollmentPollTimeoutSeconds, - ProductionObservationSinkCap: profile.ProductionObservationSinkCapacity, + BackendURL: profile.BackendURL, + ClusterID: profile.ClusterID, + JoinToken: profile.JoinToken, + NodeName: profile.NodeName, + StateDir: stateDir, + WorkloadSupervisionEnabled: profile.WorkloadSupervisionEnabled, + MeshSyntheticRuntimeEnabled: profile.MeshSyntheticRuntimeEnabled, + MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled, + MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled, + VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled, + MeshListenAddr: profile.MeshListenAddr, + MeshListenPortMode: profile.MeshListenPortMode, + MeshListenAutoPortStart: profile.MeshListenAutoPortStart, + MeshListenAutoPortEnd: profile.MeshListenAutoPortEnd, + MeshAdvertiseEndpoint: profile.MeshAdvertiseEndpoint, + MeshAdvertiseEndpointsJSON: string(profile.MeshAdvertiseEndpointsJSON), + MeshAdvertiseTransport: profile.MeshAdvertiseTransport, + MeshConnectivityMode: profile.MeshConnectivityMode, + MeshNATType: profile.MeshNATType, + MeshRegion: profile.MeshRegion, + HeartbeatIntervalSeconds: profile.HeartbeatIntervalSeconds, + EnrollmentPollIntervalSeconds: profile.EnrollmentPollIntervalSeconds, + EnrollmentPollTimeoutSeconds: profile.EnrollmentPollTimeoutSeconds, + ProductionObservationSinkCap: profile.ProductionObservationSinkCapacity, }, InstallDir: installDir, StateDir: stateDir, diff --git a/agents/rap-node-agent/internal/hostagent/profile.go b/agents/rap-node-agent/internal/hostagent/profile.go index 5233ff5..c6ffd19 100644 --- a/agents/rap-node-agent/internal/hostagent/profile.go +++ b/agents/rap-node-agent/internal/hostagent/profile.go @@ -31,6 +31,7 @@ type DockerInstallProfile struct { MeshSyntheticRuntimeEnabled bool `json:"mesh_synthetic_runtime_enabled"` MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"` MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"` + VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"` MeshListenAddr string `json:"mesh_listen_addr"` MeshListenPortMode string `json:"mesh_listen_port_mode"` MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"` @@ -74,6 +75,7 @@ type WindowsInstallProfile struct { MeshSyntheticRuntimeEnabled bool `json:"mesh_synthetic_runtime_enabled"` MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"` MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"` + VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"` MeshListenAddr string `json:"mesh_listen_addr"` MeshListenPortMode string `json:"mesh_listen_port_mode"` MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"` @@ -107,6 +109,7 @@ type LinuxInstallProfile struct { MeshSyntheticRuntimeEnabled bool `json:"mesh_synthetic_runtime_enabled"` MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"` MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"` + VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"` MeshListenAddr string `json:"mesh_listen_addr"` MeshListenPortMode string `json:"mesh_listen_port_mode"` MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"` @@ -269,39 +272,40 @@ func FetchLinuxInstallProfile(ctx context.Context, req ProfileRequest) (LinuxIns func RuntimeConfigFromProfile(profile DockerInstallProfile) RuntimeConfig { return RuntimeConfig{ - BackendURL: profile.BackendURL, - ClusterID: profile.ClusterID, - JoinToken: profile.JoinToken, - NodeName: profile.NodeName, - Image: profile.Image, - ContainerName: profile.ContainerName, - StateDir: profile.StateDir, - Network: profile.Network, - RestartPolicy: profile.RestartPolicy, - PullImage: profile.PullImage, - Replace: profile.Replace, - DockerVPNGatewayEnabled: profile.DockerVPNGatewayEnabled, - WorkloadSupervisionEnabled: profile.WorkloadSupervisionEnabled, - MeshSyntheticRuntimeEnabled: profile.MeshSyntheticRuntimeEnabled, - MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled, - MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled, - MeshListenAddr: profile.MeshListenAddr, - MeshListenPortMode: profile.MeshListenPortMode, - MeshListenAutoPortStart: profile.MeshListenAutoPortStart, - MeshListenAutoPortEnd: profile.MeshListenAutoPortEnd, - MeshAdvertiseEndpoint: profile.MeshAdvertiseEndpoint, - MeshAdvertiseEndpointsJSON: string(profile.MeshAdvertiseEndpointsJSON), - MeshAdvertiseTransport: profile.MeshAdvertiseTransport, - MeshConnectivityMode: profile.MeshConnectivityMode, - MeshNATType: profile.MeshNATType, - MeshRegion: profile.MeshRegion, - HeartbeatIntervalSeconds: profile.HeartbeatIntervalSeconds, - EnrollmentPollIntervalSeconds: profile.EnrollmentPollIntervalSeconds, - EnrollmentPollTimeoutSeconds: profile.EnrollmentPollTimeoutSeconds, - ProductionObservationSinkCap: profile.ProductionObservationSinkCapacity, - ImageArtifactURLs: dockerArtifactURLs(profile), - ImageArtifactSHA256: dockerArtifactSHA256(profile), - ImageArtifactSizeBytes: dockerArtifactSizeBytes(profile), + BackendURL: profile.BackendURL, + ClusterID: profile.ClusterID, + JoinToken: profile.JoinToken, + NodeName: profile.NodeName, + Image: profile.Image, + ContainerName: profile.ContainerName, + StateDir: profile.StateDir, + Network: profile.Network, + RestartPolicy: profile.RestartPolicy, + PullImage: profile.PullImage, + Replace: profile.Replace, + DockerVPNGatewayEnabled: profile.DockerVPNGatewayEnabled, + WorkloadSupervisionEnabled: profile.WorkloadSupervisionEnabled, + MeshSyntheticRuntimeEnabled: profile.MeshSyntheticRuntimeEnabled, + MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled, + MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled, + VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled, + MeshListenAddr: profile.MeshListenAddr, + MeshListenPortMode: profile.MeshListenPortMode, + MeshListenAutoPortStart: profile.MeshListenAutoPortStart, + MeshListenAutoPortEnd: profile.MeshListenAutoPortEnd, + MeshAdvertiseEndpoint: profile.MeshAdvertiseEndpoint, + MeshAdvertiseEndpointsJSON: string(profile.MeshAdvertiseEndpointsJSON), + MeshAdvertiseTransport: profile.MeshAdvertiseTransport, + MeshConnectivityMode: profile.MeshConnectivityMode, + MeshNATType: profile.MeshNATType, + MeshRegion: profile.MeshRegion, + HeartbeatIntervalSeconds: profile.HeartbeatIntervalSeconds, + EnrollmentPollIntervalSeconds: profile.EnrollmentPollIntervalSeconds, + EnrollmentPollTimeoutSeconds: profile.EnrollmentPollTimeoutSeconds, + ProductionObservationSinkCap: profile.ProductionObservationSinkCapacity, + ImageArtifactURLs: dockerArtifactURLs(profile), + ImageArtifactSHA256: dockerArtifactSHA256(profile), + ImageArtifactSizeBytes: dockerArtifactSizeBytes(profile), } } diff --git a/agents/rap-node-agent/internal/hostagent/update.go b/agents/rap-node-agent/internal/hostagent/update.go index ee896da..152e4f0 100644 --- a/agents/rap-node-agent/internal/hostagent/update.go +++ b/agents/rap-node-agent/internal/hostagent/update.go @@ -583,33 +583,34 @@ func (m DockerManager) runtimeConfigFromContainer(ctx context.Context, runner Co } env := envMap(inspected[0].Config.Env) cfg := RuntimeConfig{ - BackendURL: env["RAP_BACKEND_URL"], - ClusterID: env["RAP_CLUSTER_ID"], - NodeName: firstNonEmpty(env["RAP_NODE_NAME"], containerName), - Image: inspected[0].Config.Image, - ContainerName: containerName, - StateDir: hostStateDir(inspected[0]), - Network: firstNonEmpty(inspected[0].HostConfig.NetworkMode, DefaultNetwork), - RestartPolicy: firstNonEmpty(inspected[0].HostConfig.RestartPolicy.Name, "unless-stopped"), - WorkloadSupervisionEnabled: parseBool(env["RAP_WORKLOAD_SUPERVISION_ENABLED"]), - MeshSyntheticRuntimeEnabled: true, - MeshProductionForwardingEnabled: parseBool(env["RAP_MESH_PRODUCTION_FORWARDING_ENABLED"]), - MeshFabricSessionEnabled: parseBool(env["RAP_MESH_FABRIC_SESSION_ENABLED"]), - MeshListenAddr: env["RAP_MESH_LISTEN_ADDR"], - MeshListenPortMode: env["RAP_MESH_LISTEN_PORT_MODE"], - MeshListenAutoPortStart: parseInt(env["RAP_MESH_LISTEN_AUTO_PORT_START"]), - MeshListenAutoPortEnd: parseInt(env["RAP_MESH_LISTEN_AUTO_PORT_END"]), - MeshAdvertiseEndpoint: env["RAP_MESH_ADVERTISE_ENDPOINT"], - MeshAdvertiseEndpointsJSON: env["RAP_MESH_ADVERTISE_ENDPOINTS_JSON"], - MeshAdvertiseTransport: env["RAP_MESH_ADVERTISE_TRANSPORT"], - MeshConnectivityMode: env["RAP_MESH_CONNECTIVITY_MODE"], - MeshNATType: env["RAP_MESH_NAT_TYPE"], - MeshRegion: env["RAP_MESH_REGION"], - HeartbeatIntervalSeconds: parseInt(env["RAP_HEARTBEAT_INTERVAL_SECONDS"]), - EnrollmentPollIntervalSeconds: parseInt(env["RAP_ENROLLMENT_POLL_INTERVAL_SECONDS"]), - EnrollmentPollTimeoutSeconds: parseInt(env["RAP_ENROLLMENT_POLL_TIMEOUT_SECONDS"]), - ProductionObservationSinkCap: parseInt(env["RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY"]), - DockerVPNGatewayEnabled: dockerInspectHasVPNGatewayRuntime(inspected[0]), + BackendURL: env["RAP_BACKEND_URL"], + ClusterID: env["RAP_CLUSTER_ID"], + NodeName: firstNonEmpty(env["RAP_NODE_NAME"], containerName), + Image: inspected[0].Config.Image, + ContainerName: containerName, + StateDir: hostStateDir(inspected[0]), + Network: firstNonEmpty(inspected[0].HostConfig.NetworkMode, DefaultNetwork), + RestartPolicy: firstNonEmpty(inspected[0].HostConfig.RestartPolicy.Name, "unless-stopped"), + WorkloadSupervisionEnabled: parseBool(env["RAP_WORKLOAD_SUPERVISION_ENABLED"]), + MeshSyntheticRuntimeEnabled: true, + MeshProductionForwardingEnabled: parseBool(env["RAP_MESH_PRODUCTION_FORWARDING_ENABLED"]), + MeshFabricSessionEnabled: parseBool(env["RAP_MESH_FABRIC_SESSION_ENABLED"]), + VPNFabricSessionTransportEnabled: parseBool(env["RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED"]), + MeshListenAddr: env["RAP_MESH_LISTEN_ADDR"], + MeshListenPortMode: env["RAP_MESH_LISTEN_PORT_MODE"], + MeshListenAutoPortStart: parseInt(env["RAP_MESH_LISTEN_AUTO_PORT_START"]), + MeshListenAutoPortEnd: parseInt(env["RAP_MESH_LISTEN_AUTO_PORT_END"]), + MeshAdvertiseEndpoint: env["RAP_MESH_ADVERTISE_ENDPOINT"], + MeshAdvertiseEndpointsJSON: env["RAP_MESH_ADVERTISE_ENDPOINTS_JSON"], + MeshAdvertiseTransport: env["RAP_MESH_ADVERTISE_TRANSPORT"], + MeshConnectivityMode: env["RAP_MESH_CONNECTIVITY_MODE"], + MeshNATType: env["RAP_MESH_NAT_TYPE"], + MeshRegion: env["RAP_MESH_REGION"], + HeartbeatIntervalSeconds: parseInt(env["RAP_HEARTBEAT_INTERVAL_SECONDS"]), + EnrollmentPollIntervalSeconds: parseInt(env["RAP_ENROLLMENT_POLL_INTERVAL_SECONDS"]), + EnrollmentPollTimeoutSeconds: parseInt(env["RAP_ENROLLMENT_POLL_TIMEOUT_SECONDS"]), + ProductionObservationSinkCap: parseInt(env["RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY"]), + DockerVPNGatewayEnabled: dockerInspectHasVPNGatewayRuntime(inspected[0]), } return inspected[0], cfg.Normalize(), nil } diff --git a/agents/rap-node-agent/internal/hostagent/windows.go b/agents/rap-node-agent/internal/hostagent/windows.go index d5a70f3..582ccd4 100644 --- a/agents/rap-node-agent/internal/hostagent/windows.go +++ b/agents/rap-node-agent/internal/hostagent/windows.go @@ -58,29 +58,30 @@ func WindowsInstallConfigFromProfile(profile WindowsInstallProfile) WindowsInsta stateDir := firstNonEmpty(profile.StateDir, filepath.Join(DefaultWindowsStateRoot, safeUnitSlug(profile.NodeName))) return WindowsInstallConfig{ RuntimeConfig: RuntimeConfig{ - BackendURL: profile.BackendURL, - ClusterID: profile.ClusterID, - JoinToken: profile.JoinToken, - NodeName: profile.NodeName, - StateDir: stateDir, - WorkloadSupervisionEnabled: profile.WorkloadSupervisionEnabled, - MeshSyntheticRuntimeEnabled: profile.MeshSyntheticRuntimeEnabled, - MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled, - MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled, - MeshListenAddr: profile.MeshListenAddr, - MeshListenPortMode: profile.MeshListenPortMode, - MeshListenAutoPortStart: profile.MeshListenAutoPortStart, - MeshListenAutoPortEnd: profile.MeshListenAutoPortEnd, - MeshAdvertiseEndpoint: profile.MeshAdvertiseEndpoint, - MeshAdvertiseEndpointsJSON: string(profile.MeshAdvertiseEndpointsJSON), - MeshAdvertiseTransport: profile.MeshAdvertiseTransport, - MeshConnectivityMode: profile.MeshConnectivityMode, - MeshNATType: profile.MeshNATType, - MeshRegion: profile.MeshRegion, - HeartbeatIntervalSeconds: profile.HeartbeatIntervalSeconds, - EnrollmentPollIntervalSeconds: profile.EnrollmentPollIntervalSeconds, - EnrollmentPollTimeoutSeconds: profile.EnrollmentPollTimeoutSeconds, - ProductionObservationSinkCap: profile.ProductionObservationSinkCapacity, + BackendURL: profile.BackendURL, + ClusterID: profile.ClusterID, + JoinToken: profile.JoinToken, + NodeName: profile.NodeName, + StateDir: stateDir, + WorkloadSupervisionEnabled: profile.WorkloadSupervisionEnabled, + MeshSyntheticRuntimeEnabled: profile.MeshSyntheticRuntimeEnabled, + MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled, + MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled, + VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled, + MeshListenAddr: profile.MeshListenAddr, + MeshListenPortMode: profile.MeshListenPortMode, + MeshListenAutoPortStart: profile.MeshListenAutoPortStart, + MeshListenAutoPortEnd: profile.MeshListenAutoPortEnd, + MeshAdvertiseEndpoint: profile.MeshAdvertiseEndpoint, + MeshAdvertiseEndpointsJSON: string(profile.MeshAdvertiseEndpointsJSON), + MeshAdvertiseTransport: profile.MeshAdvertiseTransport, + MeshConnectivityMode: profile.MeshConnectivityMode, + MeshNATType: profile.MeshNATType, + MeshRegion: profile.MeshRegion, + HeartbeatIntervalSeconds: profile.HeartbeatIntervalSeconds, + EnrollmentPollIntervalSeconds: profile.EnrollmentPollIntervalSeconds, + EnrollmentPollTimeoutSeconds: profile.EnrollmentPollTimeoutSeconds, + ProductionObservationSinkCap: profile.ProductionObservationSinkCapacity, }, InstallDir: firstNonEmpty(profile.InstallDir, filepath.Join(DefaultWindowsInstallDir, safeUnitSlug(profile.NodeName))), StartupMode: firstNonEmpty(profile.StartupMode, "auto"), diff --git a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md index 000809e..51d408b 100644 --- a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md +++ b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md @@ -280,6 +280,10 @@ VPN packet inbox by stream id. stream ACK from the remote node. Mesh has a peer session manager that reuses one pump per peer endpoint, giving VPN transport selection a stable place to acquire long-lived fabric sessions. +Node config now carries a separate gated +`RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED` switch and heartbeat report for the +binary VPN packet transport, keeping endpoint exposure and VPN dataplane +rollout independently controllable. Deliverables: