Add fabric session smoke CLI

This commit is contained in:
2026-05-16 00:24:21 +03:00
parent 4881b5e702
commit 85c61a474f
2 changed files with 67 additions and 0 deletions
@@ -14,7 +14,9 @@ import (
"time" "time"
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/agent" "github.com/example/remote-access-platform/agents/rap-node-agent/internal/agent"
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/fabricproto"
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/hostagent" "github.com/example/remote-access-platform/agents/rap-node-agent/internal/hostagent"
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/mesh"
) )
type installCommandConfig struct { type installCommandConfig struct {
@@ -79,6 +81,10 @@ func main() {
if err := runUpdateHostAgentLoop(ctx, os.Args[2:]); err != nil { if err := runUpdateHostAgentLoop(ctx, os.Args[2:]); err != nil {
log.Fatalf("update-host-agent-loop failed: %v", err) log.Fatalf("update-host-agent-loop failed: %v", err)
} }
case "fabric-session-smoke":
if err := runFabricSessionSmoke(ctx, os.Args[2:]); err != nil {
log.Fatalf("fabric-session-smoke failed: %v", err)
}
default: default:
usage() usage()
os.Exit(2) os.Exit(2)
@@ -110,6 +116,65 @@ func applyStagedSelfUpdate() {
_ = os.Remove(backup) _ = os.Remove(backup)
} }
func runFabricSessionSmoke(ctx context.Context, args []string) error {
fs := flag.NewFlagSet("fabric-session-smoke", flag.ContinueOnError)
var meshURL string
var token string
var timeoutSeconds int
var payload string
fs.StringVar(&meshURL, "mesh-url", getenv("RAP_MESH_SMOKE_URL", ""), "Mesh base URL, for example http://node:19131.")
fs.StringVar(&token, "token", getenv("RAP_FABRIC_SESSION_TOKEN", ""), "Fabric session token starting with rap_fsn_.")
fs.IntVar(&timeoutSeconds, "timeout-seconds", getenvInt("RAP_FABRIC_SESSION_SMOKE_TIMEOUT_SECONDS", 5), "Smoke timeout in seconds.")
fs.StringVar(&payload, "payload", getenv("RAP_FABRIC_SESSION_SMOKE_PAYLOAD", "rap-fabric-session-smoke"), "Ping payload.")
if err := fs.Parse(args); err != nil {
return err
}
if strings.TrimSpace(meshURL) == "" {
return fmt.Errorf("mesh-url is required")
}
if strings.TrimSpace(token) == "" {
return fmt.Errorf("token is required")
}
if timeoutSeconds <= 0 {
timeoutSeconds = 5
}
smokeCtx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second)
defer cancel()
startedAt := time.Now()
response, err := mesh.NewClient(meshURL).SendFabricSessionFrame(smokeCtx, mesh.FabricSessionDialOptions{
Token: token,
Timeout: time.Duration(timeoutSeconds) * time.Second,
}, fabricproto.Frame{
Type: fabricproto.FramePing,
Sequence: uint64(startedAt.UnixNano()),
Payload: []byte(payload),
})
duration := time.Since(startedAt)
result := map[string]any{
"schema_version": "rap.fabric_session_smoke_result.v1",
"mesh_url": strings.TrimSpace(meshURL),
"ok": err == nil && response.Type == fabricproto.FramePong && string(response.Payload) == payload,
"latency_ms": duration.Milliseconds(),
"response_type": response.Type,
"sequence": response.Sequence,
}
if err != nil {
result["error"] = err.Error()
}
encoded, marshalErr := json.MarshalIndent(result, "", " ")
if marshalErr != nil {
return marshalErr
}
fmt.Println(string(encoded))
if err != nil {
return err
}
if response.Type != fabricproto.FramePong || string(response.Payload) != payload {
return fmt.Errorf("fabric session smoke returned unexpected response type=%d payload=%q", response.Type, string(response.Payload))
}
return nil
}
func runInstallLinux(ctx context.Context, args []string) error { func runInstallLinux(ctx context.Context, args []string) error {
fs := flag.NewFlagSet("install-linux", flag.ContinueOnError) fs := flag.NewFlagSet("install-linux", flag.ContinueOnError)
cfg := hostagent.LinuxInstallConfig{} cfg := hostagent.LinuxInstallConfig{}
@@ -846,6 +911,7 @@ func usage() {
rap-host-agent update-host-agent-loop -backend-url URL -cluster-id ID -state-dir DIR rap-host-agent update-host-agent-loop -backend-url URL -cluster-id ID -state-dir DIR
rap-host-agent monitor-loop -backend-url URL -cluster-id ID -state-dir DIR --watch-container NAME rap-host-agent monitor-loop -backend-url URL -cluster-id ID -state-dir DIR --watch-container NAME
rap-host-agent monitor-once -backend-url URL -cluster-id ID -state-dir DIR --watch-container NAME rap-host-agent monitor-once -backend-url URL -cluster-id ID -state-dir DIR --watch-container NAME
rap-host-agent fabric-session-smoke -mesh-url URL -token rap_fsn_TOKEN
rap-host-agent update -backend-url URL -cluster-id ID -node-id ID [-container-name NAME] rap-host-agent update -backend-url URL -cluster-id ID -node-id ID [-container-name NAME]
rap-host-agent update-loop -backend-url URL -cluster-id ID -node-id ID [-container-name NAME] rap-host-agent update-loop -backend-url URL -cluster-id ID -node-id ID [-container-name NAME]
rap-host-agent status [-container-name NAME]`) rap-host-agent status [-container-name NAME]`)
@@ -259,6 +259,7 @@ Deliverables:
Status: started with a transport-neutral `io.Reader`/`io.Writer` frame loop, Status: started with a transport-neutral `io.Reader`/`io.Writer` frame loop,
WebSocket frame adapter in `agents/rap-node-agent/internal/fabricproto`, and a WebSocket frame adapter in `agents/rap-node-agent/internal/fabricproto`, and a
gated/authenticated mesh smoke endpoint/client at `/mesh/v1/fabric/session/ws`. gated/authenticated mesh smoke endpoint/client at `/mesh/v1/fabric/session/ws`.
`rap-host-agent fabric-session-smoke` provides the first operator smoke command.
Deliverables: Deliverables: