diff --git a/.golangci.yml b/.golangci.yml index 390a41d..9eb0ff7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,10 +1,8 @@ -version: "2" run: go: "1.23" tests: false allow-parallel-runners: true linters: - default: all disable: - contextcheck - cyclop @@ -25,21 +23,6 @@ linters: - varnamelen - wrapcheck - wsl - exclusions: - generated: lax - presets: - - comments - - common-false-positives - - legacy - - std-error-handling - paths: - - third_party$ - - builtin$ - - examples$ -formatters: - enable: - - gofmt - - goimports exclusions: generated: lax paths: diff --git a/IBRL_INTEGRATION_GUIDE.md b/IBRL_INTEGRATION_GUIDE.md new file mode 100644 index 0000000..95e5a0f --- /dev/null +++ b/IBRL_INTEGRATION_GUIDE.md @@ -0,0 +1,577 @@ +# IBRL Integration Checklist & Decision Points + +## 1. PROTO CHANGES REQUIRED + +### Add to `/home/user/hypercore/pkg/proto/cluster.proto` + +```protobuf +// Beacon module additions +message BeaconMetadata { + string beacon_node_id = 1; // Identity from beacon + bytes node_signature = 2; // Signature proof from beacon + int64 timestamp = 3; // When registered + string reputation_score = 4; // From beacon registry + repeated string node_capabilities = 5; // Advertise node features +} + +// Policy module additions +message PolicyContext { + string policy_id = 1; // Which policy applied + repeated string tags = 2; // Policy tags/labels + string enforcement_level = 3; // PERMISSIVE, ENFORCE, DENY +} + +// Proof module additions +message WorkloadProof { + string proof_hash = 1; // SHA256 of execution proof + bytes proof_signature = 2; // Signed proof + map metrics = 3; // CPU%, Memory%, Time, etc. + int64 proof_timestamp = 4; // When proof generated + string hypervisor_type = 5; // firecracker/cloudhypervisor +} + +// Extend existing messages +message WorkloadState { + string id = 1; + VmSpawnRequest source_request = 2; + WorkloadProof proof = 3; // NEW - proof of execution +} + +message NodeStateResponse { + Node node = 1; + repeated WorkloadState workloads = 2; + BeaconMetadata beacon = 3; // NEW - beacon registration + PolicyContext policy = 4; // NEW - policy context + string state_signature = 5; // NEW - sign whole response +} + +// New event types +enum ClusterEvent { + ERROR = 0; + SPAWN = 1; + STOP = 2; + BEACON_ATTEST = 3; // NEW + POLICY_QUERY = 4; // NEW + PROOF_VERIFY = 5; // NEW +} + +// Beacon attestation message +message BeaconAttestation { + string node_id = 1; + string attestation_type = 2; // "NODE_IDENTITY", "STATE_HASH" + bytes attestation_data = 3; // Beacon-signed data +} + +// Policy query message +message PolicyQuery { + string workload_id = 1; + string policy_type = 2; // "SCHEDULING", "PERMISSION", "NETWORK" + map context = 3; // Additional context +} + +// Proof verification message +message ProofVerification { + string workload_id = 1; + string proof_hash = 1; + string verification_result = 2; // "VALID", "INVALID", "UNKNOWN" + string beacon_registry_hash = 3; // Cross-check with registry +} +``` + +**Generation Command**: +```bash +cd /home/user/hypercore +protoc --go_out=. --go-grpc_out=. --proto_path=. pkg/proto/cluster.proto +``` + +--- + +## 2. PACKAGE STRUCTURE FOR IBRL + +### New Packages to Create + +``` +/home/user/hypercore/pkg/ +├── beacon/ # NEW - Beacon module +│ ├── client.go # Beacon node client wrapper +│ ├── registry.go # Registry interface +│ └── attestation.go # Attestation logic +│ +├── policy/ # NEW - Policy module +│ ├── engine.go # Policy evaluation engine +│ ├── scheduler.go # Policy-based scheduler +│ ├── store.go # Policy storage interface +│ └── evaluator.go # Policy evaluation logic +│ +└── proof/ # NEW - Proof module + ├── collector.go # Metrics collection + ├── generator.go # Proof generation + ├── verifier.go # Proof verification + └── aggregator.go # Cross-node verification +``` + +--- + +## 3. INTEGRATION POINTS IN EXISTING CODE + +### Point 1: Agent Initialization (serf.go - NewAgent) +**File**: `/home/user/hypercore/pkg/cluster/serf.go` + +```go +// CHANGE: Add IBRL components to Agent struct +type Agent struct { + // ... existing fields ... + + // IBRL Components + beaconClient beacon.Client // NEW + policyEngine policy.Engine // NEW + proofCollector proof.Collector // NEW + + // NEW metrics + ibrlBeaconConnectionStatus prometheus.Gauge + ibrlPolicyViolations prometheus.Counter + ibrlProofLatency prometheus.Histogram +} + +// CHANGE: In NewAgent() function, initialize IBRL components +func NewAgent(...) (*Agent, error) { + // ... existing serf initialization ... + + // NEW: Initialize IBRL + beaconClient, err := beacon.NewClient(logger, cfg.BeaconEndpoint) + if err != nil { + return nil, fmt.Errorf("failed to init beacon: %w", err) + } + + policyEngine, err := policy.NewEngine(logger, cfg.PolicyStore) + if err != nil { + return nil, fmt.Errorf("failed to init policy: %w", err) + } + + proofCollector, err := proof.NewCollector(logger, hypervisorType) + if err != nil { + return nil, fmt.Errorf("failed to init proof collector: %w", err) + } + + agent.beaconClient = beaconClient + agent.policyEngine = policyEngine + agent.proofCollector = proofCollector + + // NEW: Start IBRL goroutines + go agent.beaconHeartbeat() + go agent.proofGenerator() + + return agent, nil +} +``` + +### Point 2: Spawn Request Handling (serf.go - SpawnRequest) +**File**: `/home/user/hypercore/pkg/cluster/serf.go` + +```go +// CHANGE: Wrap scheduling logic with policy +func (a *Agent) SpawnRequest(req *pb.VmSpawnRequest) (*pb.VmSpawnResponse, error) { + // NEW: Policy validation FIRST + if allowed, reason := a.policyEngine.CanSpawn(req); !allowed { + return nil, fmt.Errorf("policy violation: %s", reason) + } + + // CHANGE: Use policy-based scheduling instead of first-fit + // OLD: dry-run query to all nodes, take first responder + // NEW: policy engine evaluates nodes based on policy rules + + nodes, err := a.policyEngine.SelectNodes(req, a.serf.Members()) + if err != nil { + return nil, err + } + + // NEW: Try policy-selected nodes in order + for _, nodeName := range nodes { + params := a.serf.DefaultQueryParams() + params.Timeout = time.Second * 90 + params.FilterNodes = []string{nodeName} + + query, err := a.serf.Query(QueryName, payload, params) + if err != nil { + continue + } + + // ... response handling ... + } + + return nil, errors.New("no suitable node found") +} +``` + +### Point 3: Handle Spawn Request (serf.go - handleSpawnRequest) +**File**: `/home/user/hypercore/pkg/cluster/serf.go` + +```go +// CHANGE: Add proof collection hook +func (a *Agent) handleSpawnRequest(payload *pb.VmSpawnRequest) (ret []byte, retErr error) { + // ... capacity check ... + + id, err := a.ctrRepo.CreateContainer(ctx, vcontainerd.CreateContainerOpts{ + // ... container config ... + }) + if err != nil { + return nil, err + } + + // NEW: Start proof collection for this workload + a.proofCollector.StartCollection(id, payload.GetImageRef()) + defer func() { + if retErr == nil { + proof, err := a.proofCollector.GenerateProof(id) + if err != nil { + a.logger.WithError(err).Warn("failed to generate proof") + } else { + // Store proof for later broadcast + a.storeProof(id, proof) + } + } + }() + + // ... rest of spawn logic ... +} +``` + +### Point 4: Monitor Workloads (serf.go - monitorWorkloads) +**File**: `/home/user/hypercore/pkg/cluster/serf.go` + +```go +// CHANGE: Add beacon attestation and proof signing to state broadcast +func (a *Agent) monitorWorkloads() { + ticker := time.NewTicker(WorkloadBroadcastPeriod) + for range ticker.C { + // ... existing workload gathering ... + + resp := pb.NodeStateResponse{ + Node: &pb.Node{ + Id: a.serf.LocalMember().Name, + }, + } + + for _, task := range tasks { + // ... existing workload state ... + + workloadState := &pb.WorkloadState{ + Id: container.ID(), + SourceRequest: &labelPayload, + } + + // NEW: Attach proof if available + if proof, ok := a.getStoredProof(container.ID()); ok { + workloadState.Proof = proof + } + + resp.Workloads = append(resp.Workloads, workloadState) + } + + // NEW: Get beacon attestation + if attestation, err := a.beaconClient.Attest(ctx, resp.Node.Id); err == nil { + resp.Beacon = &pb.BeaconMetadata{ + BeaconNodeId: attestation.NodeID, + NodeSignature: attestation.Signature, + Timestamp: time.Now().Unix(), + } + } + + // NEW: Sign entire response + signature := a.signNodeStateResponse(&resp) + resp.StateSignature = signature + + // ... rest of broadcast logic ... + } +} +``` + +### Point 5: Add New Serf Event Handlers (serf.go - Handler) +**File**: `/home/user/hypercore/pkg/cluster/serf.go` + +```go +// CHANGE: Add handlers for IBRL event types +func (a *Agent) Handler() { + for event := range a.eventCh { + switch event.EventType() { + // ... existing cases ... + + case serf.EventQuery: + query := event.(*serf.Query) + var baseMessage pb.ClusterMessage + if err := proto.Unmarshal(query.Payload, &baseMessage); err != nil { + continue + } + + var response []byte + var err error + + switch baseMessage.GetEvent() { + // ... existing SPAWN/STOP cases ... + + case pb.ClusterEvent_BEACON_ATTEST: // NEW + var payload pb.BeaconAttestation + if err := baseMessage.GetWrappedMessage().UnmarshalTo(&payload); err != nil { + continue + } + response, err = a.handleBeaconAttest(&payload) + + case pb.ClusterEvent_POLICY_QUERY: // NEW + var payload pb.PolicyQuery + if err := baseMessage.GetWrappedMessage().UnmarshalTo(&payload); err != nil { + continue + } + response, err = a.handlePolicyQuery(&payload) + + case pb.ClusterEvent_PROOF_VERIFY: // NEW + var payload pb.ProofVerification + if err := baseMessage.GetWrappedMessage().UnmarshalTo(&payload); err != nil { + continue + } + response, err = a.handleProofVerify(&payload) + } + + if err := query.Respond(response); err != nil { + a.logger.WithError(err).Error("failed to respond to query") + } + } + } +} +``` + +### Point 6: Add CLI Flags (flags.go) +**File**: `/home/user/hypercore/internal/hypercore/flags.go` + +```go +// ADD: New IBRL-related flags +const ( + // ... existing flags ... + beaconEndpointFlag = "beacon-endpoint" + policyStoreFlag = "policy-store" + proofKeyPathFlag = "proof-key-path" + policyModeFlag = "policy-mode" // permissive/enforce +) + +func AddIBRLFlags(cmd *cobra.Command, cfg *Config) { + cmd.Flags().StringVar(&cfg.BeaconEndpoint, + beaconEndpointFlag, + "", + "Beacon node endpoint (host:port)") + + cmd.Flags().StringVar(&cfg.PolicyStore, + policyStoreFlag, + "", + "Policy storage endpoint") + + cmd.Flags().StringVar(&cfg.ProofKeyPath, + proofKeyPathFlag, + "", + "Path to proof signing key") + + cmd.Flags().StringVar(&cfg.PolicyMode, + policyModeFlag, + "permissive", + "Policy enforcement mode: permissive/enforce") +} + +// CHANGE: Add to Config struct +type Config struct { + // ... existing fields ... + + // IBRL Configuration + BeaconEndpoint string + PolicyStore string + ProofKeyPath string + PolicyMode string +} +``` + +--- + +## 4. TESTING STRATEGY + +### Unit Tests to Add +``` +pkg/beacon/ +├── client_test.go # Test beacon client wrapper +└── attestation_test.go # Test attestation generation + +pkg/policy/ +├── engine_test.go # Test policy evaluation +├── scheduler_test.go # Test policy-based scheduling +└── store_test.go # Test policy retrieval + +pkg/proof/ +├── collector_test.go # Test metrics collection +├── generator_test.go # Test proof generation +└── verifier_test.go # Test proof verification +``` + +### Integration Tests +``` +tests/ +├── ibrl_integration_test.go # End-to-end IBRL test +├── policy_scheduling_test.go # Policy-based spawn +├── beacon_registration_test.go # Beacon node discovery +└── proof_verification_test.go # Proof validation across nodes +``` + +--- + +## 5. CONFIGURATION EXAMPLE + +### New Config File Format +```toml +# config.toml +[cluster] +bind-addr = "0.0.0.0:7946" +base-url = "example.com" + +[ibrl] +# Beacon configuration +beacon-endpoint = "beacon-node.example.com:8000" +beacon-attestation-interval = "30s" +beacon-retry-interval = "5s" + +# Policy configuration +policy-store = "distributed" # or "local", "remote" +policy-store-endpoint = "policy-server.example.com:8001" +policy-mode = "enforce" # or "permissive" +policy-refresh-interval = "60s" + +# Proof configuration +proof-key-path = "/etc/hypercore/proof.key" +proof-generation-enabled = true +proof-verification-enabled = true +proof-aggregation-enabled = true +``` + +--- + +## 6. DEPLOYMENT CHECKLIST + +### Pre-Deployment +- [ ] Extend proto definitions +- [ ] Regenerate protobuf code +- [ ] Create beacon client wrapper +- [ ] Create policy engine +- [ ] Create proof collector/generator +- [ ] Add new CLI flags +- [ ] Update Agent struct +- [ ] Implement Handler cases for new events + +### Testing +- [ ] Unit tests pass for beacon module +- [ ] Unit tests pass for policy module +- [ ] Unit tests pass for proof module +- [ ] Integration test: beacon registration +- [ ] Integration test: policy-based scheduling +- [ ] Integration test: proof generation & verification +- [ ] Multi-node cluster test + +### Deployment +- [ ] Beacon node running and accessible +- [ ] Policy store configured +- [ ] TLS certificates for proof signing +- [ ] Start first cluster node with IBRL +- [ ] Verify beacon registration +- [ ] Spawn workload with policy check +- [ ] Verify proof generation +- [ ] Join second node and verify cluster state + +--- + +## 7. ROLLBACK STRATEGY + +### If IBRL Integration Fails + +1. **Beacon Down**: + - Code should handle missing beacon gracefully + - Fall back to first-fit scheduling + - Log warnings but don't crash + +2. **Policy Engine Error**: + - If policy check fails, default to permissive mode + - Log violation but allow spawn + - Alert operator to investigate + +3. **Proof Generation Failure**: + - Non-critical, continue operation + - Log and metrics track failures + - Workload still runs without proof + +4. **Full Rollback**: + - Disable IBRL via config flag + - Revert proto changes in a new version + - Maintain backward compatibility + +--- + +## 8. MONITORING & OBSERVABILITY + +### New Prometheus Metrics + +```go +// Beacon metrics +ibrl_beacon_connected // 1 = connected, 0 = disconnected +ibrl_beacon_attestations_total // Total attestations generated +ibrl_beacon_attestation_latency_ms // Latency to get attestation + +// Policy metrics +ibrl_policy_violations_total // Workloads rejected by policy +ibrl_policy_evaluations_total // Total policy evaluations +ibrl_policy_evaluation_latency_ms // Time to evaluate policy + +// Proof metrics +ibrl_proof_generation_latency_ms // Time to generate proof +ibrl_proof_verifications_total // Total proof verifications +ibrl_proof_verification_failures // Failed verifications +ibrl_proof_aggregation_latency_ms // Time to aggregate proofs +``` + +### Logging Guidelines +- Beacon connection/disconnection events +- Policy violations (with details) +- Proof generation start/completion +- Cross-node verification results + +--- + +## 9. KNOWN ISSUES & MITIGATIONS + +| Issue | Impact | Mitigation | +|-------|--------|-----------| +| Beacon latency | Slow scheduling | Cache attestations, use timeouts | +| Policy store unavailable | Can't evaluate policies | Fall back to permissive mode | +| Proof generation slow | High latency | Generate async, store for later | +| Large cluster state | Broadcast failures | Already batching in monitorWorkloads | +| Signature verification | CPU overhead | Cache signatures, batch verification | + +--- + +## 10. PHASED ROLLOUT + +### Phase 1: Beacon Integration (Week 1-2) +- Create beacon client wrapper +- Add beacon metadata to proto +- Implement node attestation in monitorWorkloads() +- Test beacon registration + +### Phase 2: Policy Integration (Week 3-4) +- Create policy engine +- Implement policy-based scheduler +- Add policy event handler +- Test policy enforcement + +### Phase 3: Proof Integration (Week 5-6) +- Create proof collector/generator +- Implement proof signing +- Add proof verification handler +- Test proof generation & verification + +### Phase 4: Full Integration & Testing (Week 7-8) +- Multi-node cluster tests +- IBRL scenario testing +- Performance benchmarking +- Documentation & runbooks + diff --git a/examples/policies/balanced.json b/examples/policies/balanced.json new file mode 100644 index 0000000..c07c909 --- /dev/null +++ b/examples/policies/balanced.json @@ -0,0 +1,19 @@ +{ + "name": "balanced", + "description": "Balanced policy for general-purpose workloads", + "mode": "enforce", + "rules": { + "max_latency_ms": 200, + "max_price_per_gb": 0.02, + "min_reputation_score": 0.7, + "max_queue_depth": 100, + "max_packet_loss": 2.0, + "max_jitter_ms": 30 + }, + "scoring": { + "latency_weight": 0.25, + "price_weight": 0.25, + "reputation_weight": 0.25, + "queue_weight": 0.25 + } +} diff --git a/examples/policies/cost-optimized.json b/examples/policies/cost-optimized.json new file mode 100644 index 0000000..f3c6482 --- /dev/null +++ b/examples/policies/cost-optimized.json @@ -0,0 +1,17 @@ +{ + "name": "cost-optimized", + "description": "Minimize cost while maintaining acceptable quality", + "mode": "enforce", + "rules": { + "max_price_per_gb": 0.05, + "max_latency_ms": 500, + "min_reputation_score": 0.5, + "max_packet_loss": 5.0 + }, + "scoring": { + "latency_weight": 0.1, + "price_weight": 0.7, + "reputation_weight": 0.1, + "queue_weight": 0.1 + } +} diff --git a/examples/policies/high-trust.json b/examples/policies/high-trust.json new file mode 100644 index 0000000..ae3937b --- /dev/null +++ b/examples/policies/high-trust.json @@ -0,0 +1,17 @@ +{ + "name": "high-trust", + "description": "Only use highly trusted nodes with proven track record", + "mode": "enforce", + "rules": { + "min_reputation_score": 0.9, + "max_latency_ms": 300, + "max_price_per_gb": 0.1, + "max_packet_loss": 1.0 + }, + "scoring": { + "latency_weight": 0.2, + "price_weight": 0.1, + "reputation_weight": 0.6, + "queue_weight": 0.1 + } +} diff --git a/examples/policies/low-latency.json b/examples/policies/low-latency.json new file mode 100644 index 0000000..d3f2464 --- /dev/null +++ b/examples/policies/low-latency.json @@ -0,0 +1,16 @@ +{ + "name": "low-latency", + "description": "Prioritize nodes with lowest latency for latency-sensitive workloads", + "mode": "enforce", + "rules": { + "max_latency_ms": 100, + "max_jitter_ms": 20, + "max_packet_loss": 1.0 + }, + "scoring": { + "latency_weight": 0.6, + "price_weight": 0.1, + "reputation_weight": 0.2, + "queue_weight": 0.1 + } +} diff --git a/examples/policies/permissive.json b/examples/policies/permissive.json new file mode 100644 index 0000000..4924bf3 --- /dev/null +++ b/examples/policies/permissive.json @@ -0,0 +1,12 @@ +{ + "name": "permissive", + "description": "Permissive policy - accepts any available node", + "mode": "permissive", + "rules": {}, + "scoring": { + "latency_weight": 0.25, + "price_weight": 0.25, + "reputation_weight": 0.25, + "queue_weight": 0.25 + } +} diff --git a/internal/hypercore/commands.go b/internal/hypercore/commands.go index 899c38e..e2a501c 100644 --- a/internal/hypercore/commands.go +++ b/internal/hypercore/commands.go @@ -239,6 +239,62 @@ func ClusterListCommand(cfg *Config) *cobra.Command { return cmd } +func ClusterMetricsCommand(cfg *Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "metrics", + Short: "display IBRL metrics for cluster nodes", + PreRunE: func(c *cobra.Command, _ []string) error { + BindCommandToViper(c) + return nil + }, + RunE: func(_ *cobra.Command, _ []string) error { + conn, err := grpc.NewClient(cfg.GrpcBindAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return err + } + defer conn.Close() + + c := pb.NewClusterServiceClient(conn) + resp, err := c.List(context.Background(), &pb.VmQueryRequest{}) + if err != nil { + return err + } + + // Display metrics in a formatted table + log.Info("IBRL Cluster Metrics:") + log.Info("====================") + log.Info("") + + for _, nodeState := range resp.GetStates() { + node := nodeState.GetNode() + beacon := nodeState.GetBeacon() + + log.Infof("Node: %s", node.GetId()) + + if beacon != nil { + log.Infof(" Beacon ID: %s", beacon.GetBeaconNodeId()) + log.Infof(" Latency: %.2f ms", beacon.GetLatencyMs()) + log.Infof(" Jitter: %.2f ms", beacon.GetJitterMs()) + log.Infof(" Packet Loss: %.2f%%", beacon.GetPacketLoss()) + log.Infof(" Queue Depth: %d", beacon.GetQueueDepth()) + log.Infof(" Price/GB: $%.4f", beacon.GetPricePerGb()) + log.Infof(" Reputation: %s", beacon.GetReputationScore()) + log.Infof(" Capabilities: %v", beacon.GetNodeCapabilities()) + } else { + log.Info(" Beacon: Not available") + } + + log.Infof(" Workloads: %d", len(nodeState.GetWorkloads())) + log.Info("") + } + + return nil + }, + } + + return cmd +} + func ClusterCommand(cfg *Config) *cobra.Command { cmd := &cobra.Command{ Use: "cluster", @@ -254,7 +310,10 @@ func ClusterCommand(cfg *Config) *cobra.Command { repo, err := containerd.NewMicroVMRepository(containerdConfig(cfg)) if err != nil { - return err + // On Mac, containerd is not available - only allow metrics/list commands + logger.WithError(err).Warn("containerd not available - cluster node mode disabled") + logger.Info("Use 'hypercore cluster metrics' or 'hypercore cluster list' to query existing clusters") + return fmt.Errorf("containerd operations not supported on Mac: %w", err) } var tlsConfig *cluster.TLSConfig @@ -266,7 +325,7 @@ func ClusterCommand(cfg *Config) *cobra.Command { } } - agent, err := cluster.NewAgent(logger, cfg.ClusterBaseURL, cfg.ClusterBindAddr, cfg.RespawnOnNodeFailure, repo, tlsConfig) + agent, err := cluster.NewAgent(logger, cfg.ClusterBaseURL, cfg.ClusterBindAddr, cfg.RespawnOnNodeFailure, repo, tlsConfig, cfg.ClusterPolicyFile, cfg.BeaconEndpoint, cfg.BeaconPrice, cfg.BeaconReputation) if err != nil { return err } @@ -315,6 +374,7 @@ func ClusterCommand(cfg *Config) *cobra.Command { cmd.AddCommand(ClusterStopCommand(cfg)) cmd.AddCommand(ClusterLogsCommand(cfg)) cmd.AddCommand(ClusterListCommand(cfg)) + cmd.AddCommand(ClusterMetricsCommand(cfg)) // TODO remove hac/vmm flags AddCommonFlags(cmd, cfg) diff --git a/internal/hypercore/config.go b/internal/hypercore/config.go index a8feba5..4b3100f 100644 --- a/internal/hypercore/config.go +++ b/internal/hypercore/config.go @@ -10,14 +10,19 @@ type Config struct { ClusterBaseURL string ClusterTLSCert string ClusterTLSKey string + ClusterPolicyFile string GrpcBindAddr string HTTPBindAddr string + BeaconEndpoint string + BeaconPrice float64 + BeaconReputation string ClusterSpawn struct { - CPU int - Memory int - ImageRef string - Ports string - Env []string + CPU int + Memory int + ImageRef string + Ports string + Env []string + PolicyFile string } ClusterStop struct { ID string diff --git a/internal/hypercore/flags.go b/internal/hypercore/flags.go index c1c8e01..3300b92 100644 --- a/internal/hypercore/flags.go +++ b/internal/hypercore/flags.go @@ -21,12 +21,17 @@ const ( clusterBaseURLFlag = "cluster-base-url" clusterTLSCertFlag = "cluster-tls-cert" clusterTLSKeyFlag = "cluster-tls-key" + clusterPolicyFileFlag = "cluster-policy" respawnOnNodeFailureFlag = "respawn-on-node-failure" + beaconEndpointFlag = "beacon-endpoint" + beaconPriceFlag = "beacon-price" + beaconReputationFlag = "beacon-reputation" cpuFlag = "cpu" memoryFlag = "mem" imageRefFlag = "image-ref" portsFlag = "ports" envFlag = "env" + policyFileFlag = "policy" idFlag = "id" ) @@ -59,7 +64,11 @@ func AddClusterFlags(cmd *cobra.Command, cfg *Config) { cmd.Flags().StringVar(&cfg.ClusterBaseURL, clusterBaseURLFlag, "example.com", "Cluster base URL") cmd.Flags().StringVar(&cfg.ClusterTLSCert, clusterTLSCertFlag, "", "Cluster tls cert path") cmd.Flags().StringVar(&cfg.ClusterTLSKey, clusterTLSKeyFlag, "", "Cluster tls key path") + cmd.Flags().StringVar(&cfg.ClusterPolicyFile, clusterPolicyFileFlag, "", "Path to IBRL policy file (JSON)") cmd.Flags().BoolVar(&cfg.RespawnOnNodeFailure, respawnOnNodeFailureFlag, false, "Whether this node monitors other cluster nodes and re-schedules their tasks on failure") + cmd.Flags().StringVar(&cfg.BeaconEndpoint, beaconEndpointFlag, "", "IBRL beacon network endpoint (HTTP/HTTPS URL or TCP address)") + cmd.Flags().Float64Var(&cfg.BeaconPrice, beaconPriceFlag, 0.01, "Price per GB for this node (used in policy evaluation)") + cmd.Flags().StringVar(&cfg.BeaconReputation, beaconReputationFlag, "1.0", "Reputation score for this node (0.0-1.0, used in policy evaluation)") } func AddClusterSpawnFlags(cmd *cobra.Command, cfg *Config) { @@ -69,6 +78,7 @@ func AddClusterSpawnFlags(cmd *cobra.Command, cfg *Config) { cmd.Flags().StringVar(&cfg.ClusterSpawn.ImageRef, imageRefFlag, "", "Image Reference") cmd.Flags().StringVar(&cfg.ClusterSpawn.Ports, portsFlag, "", "comma-separated list of ports to expose") cmd.Flags().StringSliceVar(&cfg.ClusterSpawn.Env, envFlag, []string{}, "list of env variables to pass to container") + cmd.Flags().StringVar(&cfg.ClusterSpawn.PolicyFile, policyFileFlag, "", "Path to policy file for this spawn (overrides cluster default)") } func AddClusterStopFlags(cmd *cobra.Command, cfg *Config) { diff --git a/pkg/beacon/attestation.go b/pkg/beacon/attestation.go new file mode 100644 index 0000000..fbc8539 --- /dev/null +++ b/pkg/beacon/attestation.go @@ -0,0 +1,209 @@ +package beacon + +import ( + "context" + "crypto/ed25519" + "crypto/sha256" + "encoding/hex" + "fmt" + "time" + + "github.com/sirupsen/logrus" +) + +// AttestationType defines the type of attestation +type AttestationType string + +const ( + // NodeIdentityAttestation attests to the node's identity + NodeIdentityAttestation AttestationType = "NODE_IDENTITY" + + // StateHashAttestation attests to the node's current state hash + StateHashAttestation AttestationType = "STATE_HASH" + + // WorkloadAttestation attests to a specific workload + WorkloadAttestation AttestationType = "WORKLOAD" +) + +// Attestation represents a cryptographic attestation +type Attestation struct { + Type AttestationType + NodeID string + Data []byte + Signature []byte + Timestamp int64 + PublicKey []byte +} + +// AttestationVerifier verifies attestations +type AttestationVerifier struct { + logger *logrus.Logger +} + +// NewAttestationVerifier creates a new attestation verifier +func NewAttestationVerifier(logger *logrus.Logger) *AttestationVerifier { + return &AttestationVerifier{ + logger: logger, + } +} + +// GenerateAttestation generates a new attestation +func GenerateAttestation( + ctx context.Context, + attestationType AttestationType, + nodeID string, + data []byte, + privateKey ed25519.PrivateKey, + publicKey ed25519.PublicKey, +) (*Attestation, error) { + if len(data) == 0 { + return nil, fmt.Errorf("attestation data cannot be empty") + } + + timestamp := time.Now().Unix() + + // Create attestation message: type|nodeID|timestamp|data + message := fmt.Sprintf("%s|%s|%d|%s", attestationType, nodeID, timestamp, hex.EncodeToString(data)) + + // Sign the message + signature := ed25519.Sign(privateKey, []byte(message)) + + return &Attestation{ + Type: attestationType, + NodeID: nodeID, + Data: data, + Signature: signature, + Timestamp: timestamp, + PublicKey: publicKey, + }, nil +} + +// Verify verifies an attestation signature +func (v *AttestationVerifier) Verify(ctx context.Context, attestation *Attestation) (bool, error) { + if attestation == nil { + return false, fmt.Errorf("attestation cannot be nil") + } + + if len(attestation.PublicKey) != ed25519.PublicKeySize { + return false, fmt.Errorf("invalid public key size: %d", len(attestation.PublicKey)) + } + + // Reconstruct the signed message + message := fmt.Sprintf("%s|%s|%d|%s", + attestation.Type, + attestation.NodeID, + attestation.Timestamp, + hex.EncodeToString(attestation.Data), + ) + + // Verify signature + publicKey := ed25519.PublicKey(attestation.PublicKey) + valid := ed25519.Verify(publicKey, []byte(message), attestation.Signature) + + if valid { + v.logger.WithFields(logrus.Fields{ + "type": attestation.Type, + "node_id": attestation.NodeID, + }).Debug("attestation verified successfully") + } else { + v.logger.WithFields(logrus.Fields{ + "type": attestation.Type, + "node_id": attestation.NodeID, + }).Warn("attestation verification failed") + } + + return valid, nil +} + +// VerifyWithAge verifies an attestation and checks if it's not too old +func (v *AttestationVerifier) VerifyWithAge(ctx context.Context, attestation *Attestation, maxAge time.Duration) (bool, error) { + // First verify the signature + valid, err := v.Verify(ctx, attestation) + if err != nil || !valid { + return false, err + } + + // Check age + now := time.Now().Unix() + age := now - attestation.Timestamp + + if time.Duration(age)*time.Second > maxAge { + v.logger.WithFields(logrus.Fields{ + "type": attestation.Type, + "node_id": attestation.NodeID, + "age": age, + "max_age": maxAge.Seconds(), + }).Warn("attestation is too old") + return false, fmt.Errorf("attestation is too old: %ds > %ds", age, int(maxAge.Seconds())) + } + + return true, nil +} + +// HashStateData creates a hash of state data for attestation +func HashStateData(data []byte) []byte { + hash := sha256.Sum256(data) + return hash[:] +} + +// AttestNodeIdentity creates a node identity attestation +func AttestNodeIdentity( + ctx context.Context, + nodeID string, + privateKey ed25519.PrivateKey, + publicKey ed25519.PublicKey, +) (*Attestation, error) { + // Use the node ID as the data for identity attestation + data := []byte(nodeID) + + return GenerateAttestation( + ctx, + NodeIdentityAttestation, + nodeID, + data, + privateKey, + publicKey, + ) +} + +// AttestStateHash creates a state hash attestation +func AttestStateHash( + ctx context.Context, + nodeID string, + stateData []byte, + privateKey ed25519.PrivateKey, + publicKey ed25519.PublicKey, +) (*Attestation, error) { + // Hash the state data + hash := HashStateData(stateData) + + return GenerateAttestation( + ctx, + StateHashAttestation, + nodeID, + hash, + privateKey, + publicKey, + ) +} + +// AttestWorkload creates a workload attestation +func AttestWorkload( + ctx context.Context, + nodeID string, + workloadID string, + privateKey ed25519.PrivateKey, + publicKey ed25519.PublicKey, +) (*Attestation, error) { + // Use workload ID as the data + data := []byte(workloadID) + + return GenerateAttestation( + ctx, + WorkloadAttestation, + nodeID, + data, + privateKey, + publicKey, + ) +} diff --git a/pkg/beacon/client.go b/pkg/beacon/client.go new file mode 100644 index 0000000..e109345 --- /dev/null +++ b/pkg/beacon/client.go @@ -0,0 +1,256 @@ +package beacon + +import ( + "context" + "crypto/ed25519" + "crypto/rand" + "encoding/hex" + "fmt" + "net" + "net/http" + "strings" + "sync" + "time" + + "github.com/sirupsen/logrus" + pb "vistara-node/pkg/proto/cluster" +) + +// Client represents a beacon client that manages node attestation and metrics +type Client struct { + logger *logrus.Logger + endpoint string + nodeID string + privateKey ed25519.PrivateKey + publicKey ed25519.PublicKey + metrics *NodeMetrics + metricsMutex sync.RWMutex + connected bool + connMutex sync.RWMutex +} + +// NodeMetrics holds current metrics for the node +type NodeMetrics struct { + LatencyMs float64 + JitterMs float64 + PacketLoss float64 + QueueDepth uint32 + PricePerGB float64 + ReputationScore string + Capabilities []string + LastUpdate time.Time +} + +// AttestationResult contains the result of an attestation request +type AttestationResult struct { + NodeID string + Signature []byte + Timestamp int64 + Valid bool +} + +// NewClient creates a new beacon client +func NewClient(logger *logrus.Logger, endpoint string) (*Client, error) { + if logger == nil { + return nil, fmt.Errorf("logger cannot be nil") + } + + // Generate ed25519 keypair for signing attestations + publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate keypair: %w", err) + } + + nodeID := hex.EncodeToString(publicKey[:8]) // Use first 8 bytes as node ID + + client := &Client{ + logger: logger, + endpoint: endpoint, + nodeID: nodeID, + privateKey: privateKey, + publicKey: publicKey, + metrics: &NodeMetrics{ + LatencyMs: 0.0, + JitterMs: 0.0, + PacketLoss: 0.0, + QueueDepth: 0, + PricePerGB: 0.01, // Default price + ReputationScore: "1.0", + Capabilities: []string{"container", "vm"}, + LastUpdate: time.Now(), + }, + connected: false, + } + + // If endpoint is provided, attempt connection + if endpoint != "" { + if err := client.Connect(context.Background()); err != nil { + logger.WithError(err).Warn("failed to connect to beacon endpoint, operating in standalone mode") + } + } else { + logger.Info("no beacon endpoint provided, operating in standalone mode") + } + + return client, nil +} + +// Connect establishes connection to the beacon network +func (c *Client) Connect(ctx context.Context) error { + c.connMutex.Lock() + defer c.connMutex.Unlock() + + if c.endpoint == "" { + return fmt.Errorf("no beacon endpoint configured") + } + + c.logger.WithField("endpoint", c.endpoint).Info("connecting to beacon network") + + // Attempt HTTP health check first + if strings.HasPrefix(c.endpoint, "http://") || strings.HasPrefix(c.endpoint, "https://") { + client := &http.Client{ + Timeout: 5 * time.Second, + } + resp, err := client.Get(c.endpoint + "/health") + if err != nil { + c.logger.WithError(err).Warn("beacon endpoint health check failed, operating in standalone mode") + return err + } + resp.Body.Close() + if resp.StatusCode != http.StatusOK { + c.logger.WithField("status", resp.StatusCode).Warn("beacon endpoint returned non-OK status, operating in standalone mode") + return fmt.Errorf("beacon endpoint returned status %d", resp.StatusCode) + } + c.connected = true + c.logger.Info("successfully connected to beacon network via HTTP") + return nil + } + + // Attempt TCP connection for other protocols + conn, err := net.DialTimeout("tcp", c.endpoint, 5*time.Second) + if err != nil { + c.logger.WithError(err).Warn("beacon endpoint connection failed, operating in standalone mode") + return err + } + conn.Close() + + c.connected = true + c.logger.Info("successfully connected to beacon network") + return nil +} + +// IsConnected returns whether the client is connected to the beacon network +func (c *Client) IsConnected() bool { + c.connMutex.RLock() + defer c.connMutex.RUnlock() + return c.connected +} + +// Attest generates a cryptographic attestation for the given node ID +func (c *Client) Attest(ctx context.Context, nodeID string) (*AttestationResult, error) { + // Create attestation message + timestamp := time.Now().Unix() + message := fmt.Sprintf("%s:%d", nodeID, timestamp) + + // Sign the message + signature := ed25519.Sign(c.privateKey, []byte(message)) + + result := &AttestationResult{ + NodeID: c.nodeID, + Signature: signature, + Timestamp: timestamp, + Valid: true, + } + + c.logger.WithFields(logrus.Fields{ + "node_id": nodeID, + "timestamp": timestamp, + }).Debug("generated attestation") + + return result, nil +} + +// UpdateMetrics updates the current node metrics +func (c *Client) UpdateMetrics(latency, jitter, packetLoss float64, queueDepth uint32) { + c.metricsMutex.Lock() + defer c.metricsMutex.Unlock() + + c.metrics.LatencyMs = latency + c.metrics.JitterMs = jitter + c.metrics.PacketLoss = packetLoss + c.metrics.QueueDepth = queueDepth + c.metrics.LastUpdate = time.Now() + + c.logger.WithFields(logrus.Fields{ + "latency_ms": latency, + "jitter_ms": jitter, + "packet_loss": packetLoss, + "queue_depth": queueDepth, + }).Debug("updated node metrics") +} + +// SetPrice sets the price per GB for this node +func (c *Client) SetPrice(pricePerGB float64) { + c.metricsMutex.Lock() + defer c.metricsMutex.Unlock() + c.metrics.PricePerGB = pricePerGB +} + +// SetReputationScore sets the reputation score for this node +func (c *Client) SetReputationScore(score string) { + c.metricsMutex.Lock() + defer c.metricsMutex.Unlock() + c.metrics.ReputationScore = score +} + +// GetMetrics returns the current metrics +func (c *Client) GetMetrics() *NodeMetrics { + c.metricsMutex.RLock() + defer c.metricsMutex.RUnlock() + + // Return a copy to avoid race conditions + return &NodeMetrics{ + LatencyMs: c.metrics.LatencyMs, + JitterMs: c.metrics.JitterMs, + PacketLoss: c.metrics.PacketLoss, + QueueDepth: c.metrics.QueueDepth, + PricePerGB: c.metrics.PricePerGB, + ReputationScore: c.metrics.ReputationScore, + Capabilities: append([]string{}, c.metrics.Capabilities...), + LastUpdate: c.metrics.LastUpdate, + } +} + +// GetBeaconMetadata returns the beacon metadata for inclusion in cluster state +func (c *Client) GetBeaconMetadata() *pb.BeaconMetadata { + c.metricsMutex.RLock() + defer c.metricsMutex.RUnlock() + + return &pb.BeaconMetadata{ + BeaconNodeId: c.nodeID, + NodeSignature: c.publicKey, + Timestamp: time.Now().Unix(), + ReputationScore: c.metrics.ReputationScore, + NodeCapabilities: c.metrics.Capabilities, + LatencyMs: c.metrics.LatencyMs, + JitterMs: c.metrics.JitterMs, + PacketLoss: c.metrics.PacketLoss, + QueueDepth: c.metrics.QueueDepth, + PricePerGb: c.metrics.PricePerGB, + } +} + +// Close closes the beacon client +func (c *Client) Close() error { + c.connMutex.Lock() + defer c.connMutex.Unlock() + + c.connected = false + c.logger.Info("beacon client closed") + + return nil +} + +// GetNodeID returns the node ID +func (c *Client) GetNodeID() string { + return c.nodeID +} diff --git a/pkg/beacon/registry.go b/pkg/beacon/registry.go new file mode 100644 index 0000000..b325c94 --- /dev/null +++ b/pkg/beacon/registry.go @@ -0,0 +1,181 @@ +package beacon + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/sirupsen/logrus" + pb "vistara-node/pkg/proto/cluster" +) + +// Registry maintains a registry of known nodes and their beacon metadata +type Registry struct { + logger *logrus.Logger + nodes map[string]*NodeRecord + mutex sync.RWMutex +} + +// NodeRecord represents a registered node with its metadata +type NodeRecord struct { + NodeID string + Metadata *pb.BeaconMetadata + LastSeen time.Time + Verified bool +} + +// NewRegistry creates a new beacon registry +func NewRegistry(logger *logrus.Logger) *Registry { + return &Registry{ + logger: logger, + nodes: make(map[string]*NodeRecord), + } +} + +// Register registers or updates a node in the registry +func (r *Registry) Register(ctx context.Context, nodeID string, metadata *pb.BeaconMetadata) error { + if nodeID == "" { + return fmt.Errorf("node ID cannot be empty") + } + + if metadata == nil { + return fmt.Errorf("metadata cannot be nil") + } + + r.mutex.Lock() + defer r.mutex.Unlock() + + record, exists := r.nodes[nodeID] + if exists { + // Update existing record + record.Metadata = metadata + record.LastSeen = time.Now() + r.logger.WithField("node_id", nodeID).Debug("updated node registration") + } else { + // Create new record + r.nodes[nodeID] = &NodeRecord{ + NodeID: nodeID, + Metadata: metadata, + LastSeen: time.Now(), + Verified: false, // Will be verified after attestation + } + r.logger.WithField("node_id", nodeID).Info("registered new node") + } + + return nil +} + +// Get retrieves a node record from the registry +func (r *Registry) Get(nodeID string) (*NodeRecord, error) { + r.mutex.RLock() + defer r.mutex.RUnlock() + + record, exists := r.nodes[nodeID] + if !exists { + return nil, fmt.Errorf("node %s not found in registry", nodeID) + } + + return record, nil +} + +// List returns all registered nodes +func (r *Registry) List() []*NodeRecord { + r.mutex.RLock() + defer r.mutex.RUnlock() + + records := make([]*NodeRecord, 0, len(r.nodes)) + for _, record := range r.nodes { + records = append(records, record) + } + + return records +} + +// Remove removes a node from the registry +func (r *Registry) Remove(nodeID string) error { + r.mutex.Lock() + defer r.mutex.Unlock() + + if _, exists := r.nodes[nodeID]; !exists { + return fmt.Errorf("node %s not found in registry", nodeID) + } + + delete(r.nodes, nodeID) + r.logger.WithField("node_id", nodeID).Info("removed node from registry") + + return nil +} + +// Cleanup removes stale nodes that haven't been seen for a specified duration +func (r *Registry) Cleanup(maxAge time.Duration) int { + r.mutex.Lock() + defer r.mutex.Unlock() + + removed := 0 + now := time.Now() + + for nodeID, record := range r.nodes { + if now.Sub(record.LastSeen) > maxAge { + delete(r.nodes, nodeID) + removed++ + r.logger.WithFields(logrus.Fields{ + "node_id": nodeID, + "last_seen": record.LastSeen, + }).Info("removed stale node from registry") + } + } + + return removed +} + +// Count returns the number of registered nodes +func (r *Registry) Count() int { + r.mutex.RLock() + defer r.mutex.RUnlock() + return len(r.nodes) +} + +// MarkVerified marks a node as verified after successful attestation +func (r *Registry) MarkVerified(nodeID string) error { + r.mutex.Lock() + defer r.mutex.Unlock() + + record, exists := r.nodes[nodeID] + if !exists { + return fmt.Errorf("node %s not found in registry", nodeID) + } + + record.Verified = true + r.logger.WithField("node_id", nodeID).Info("marked node as verified") + + return nil +} + +// GetByMetrics returns nodes that match the specified metric criteria +func (r *Registry) GetByMetrics(maxLatency float64, minReputation string) []*NodeRecord { + r.mutex.RLock() + defer r.mutex.RUnlock() + + var matches []*NodeRecord + + for _, record := range r.nodes { + if record.Metadata == nil { + continue + } + + // Filter by latency + if maxLatency > 0 && record.Metadata.LatencyMs > maxLatency { + continue + } + + // Filter by reputation (simple string comparison for now) + if minReputation != "" && record.Metadata.ReputationScore < minReputation { + continue + } + + matches = append(matches, record) + } + + return matches +} diff --git a/pkg/cluster/serf.go b/pkg/cluster/serf.go index b39d9f2..b660932 100644 --- a/pkg/cluster/serf.go +++ b/pkg/cluster/serf.go @@ -17,7 +17,9 @@ import ( "strings" "sync" "time" + "vistara-node/pkg/beacon" vcontainerd "vistara-node/pkg/containerd" + "vistara-node/pkg/policy" pb "vistara-node/pkg/proto/cluster" ctask "github.com/containerd/containerd/api/types/task" @@ -63,11 +65,23 @@ type Agent struct { lastStateHash string // Track state hash to detect changes stateMu sync.Mutex + // IBRL components + beaconClient *beacon.Client + beaconRegistry *beacon.Registry + policyEngine *policy.Engine + + // Latency tracking for jitter calculation + latencyHistory []float64 + latencyHistoryMu sync.Mutex + // Prometheus metrics serfQueueDepth prometheus.Gauge workloadCount prometheus.Gauge broadcastSkipped prometheus.Counter stateChanges prometheus.Counter + + // IBRL metrics + ibrlBeaconConnected prometheus.Gauge } // hashWorkloadState creates a consistent hash of the workload state @@ -87,7 +101,7 @@ func (a *Agent) hashWorkloadState(state *pb.NodeStateResponse) string { return hex.EncodeToString(hash.Sum(nil)) } -func NewAgent(logger *log.Logger, baseURL, bindAddr string, respawn bool, repo *vcontainerd.Repo, tlsConfig *TLSConfig) (*Agent, error) { +func NewAgent(logger *log.Logger, baseURL, bindAddr string, respawn bool, repo *vcontainerd.Repo, tlsConfig *TLSConfig, policyFilePath string, beaconEndpoint string, beaconPrice float64, beaconReputation string) (*Agent, error) { eventCh := make(chan serf.Event, 64) serviceProxy, err := NewServiceProxy(logger, tlsConfig) @@ -144,8 +158,40 @@ func NewAgent(logger *log.Logger, baseURL, bindAddr string, respawn bool, repo * Help: "Total number of state changes detected", }) + ibrlBeaconConnected := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "hypercore_ibrl_beacon_connected", + Help: "IBRL beacon connection status (1=connected, 0=disconnected)", + }) + // Register metrics - prometheus.MustRegister(serfQueueDepth, workloadCount, broadcastSkipped, stateChanges) + prometheus.MustRegister(serfQueueDepth, workloadCount, broadcastSkipped, stateChanges, ibrlBeaconConnected) + + // Initialize IBRL beacon client + beaconClient, err := beacon.NewClient(logger, beaconEndpoint) + if err != nil { + return nil, fmt.Errorf("failed to initialize beacon client: %w", err) + } + + // Set price and reputation if provided + if beaconPrice > 0 { + beaconClient.SetPrice(beaconPrice) + } + if beaconReputation != "" { + beaconClient.SetReputationScore(beaconReputation) + } + + // Initialize beacon registry + beaconRegistry := beacon.NewRegistry(logger) + + // Initialize policy engine + policyEngine := policy.NewEngine(logger) + + // Load policy file if specified + if policyFilePath != "" { + if err := policyEngine.LoadPolicy(policyFilePath); err != nil { + return nil, fmt.Errorf("failed to load policy file: %w", err) + } + } agent := &Agent{ eventCh: eventCh, @@ -161,6 +207,18 @@ func NewAgent(logger *log.Logger, baseURL, bindAddr string, respawn bool, repo * workloadCount: workloadCount, broadcastSkipped: broadcastSkipped, stateChanges: stateChanges, + beaconClient: beaconClient, + beaconRegistry: beaconRegistry, + policyEngine: policyEngine, + ibrlBeaconConnected: ibrlBeaconConnected, + latencyHistory: make([]float64, 0, 10), // Keep last 10 measurements + } + + // Update beacon connection metric + if beaconClient.IsConnected() { + agent.ibrlBeaconConnected.Set(1) + } else { + agent.ibrlBeaconConnected.Set(0) } // Start monitoring workloads and state updates @@ -421,6 +479,10 @@ func (a *Agent) Handler() { } partialWorkloads.Workloads = append(partialWorkloads.Workloads, workloads.GetWorkloads()...) + // Preserve beacon metadata from the finish message (should be same as begin) + if workloads.GetBeacon() != nil { + partialWorkloads.Beacon = workloads.GetBeacon() + } case "begin": a.tmpStateUpdates[id] = &workloads @@ -434,6 +496,10 @@ func (a *Agent) Handler() { } partialWorkloads.Workloads = append(partialWorkloads.Workloads, workloads.GetWorkloads()...) + // Preserve beacon metadata from begin message (only set if not already set) + if partialWorkloads.GetBeacon() == nil && workloads.GetBeacon() != nil { + partialWorkloads.Beacon = workloads.GetBeacon() + } continue } @@ -499,6 +565,95 @@ func wrapClusterErrorMessage(errorMessage string) ([]byte, error) { // Request another node to spawn a VM func (a *Agent) SpawnRequest(req *pb.VmSpawnRequest) (*pb.VmSpawnResponse, error) { + // Check if policy allows this spawn + if allowed, reason := a.policyEngine.CanSpawn(req); !allowed { + return nil, fmt.Errorf("policy violation: %s", reason) + } + + // Get current cluster state for policy evaluation + a.lastStateMu.Lock() + stateMap := make(map[string]*pb.NodeStateResponse) + for nodeName, savedUpdate := range a.lastStateUpdate { + stateMap[nodeName] = savedUpdate.update + } + // Include self state if available (for single-node clusters) + if a.lastStateSelf != nil { + stateMap[a.serf.LocalMember().Name] = a.lastStateSelf + } + a.lastStateMu.Unlock() + + // Use policy engine to select best nodes in priority order + members := a.serf.Members() + selectedNodes, err := a.policyEngine.SelectNodes(req, members, stateMap) + if err != nil { + a.logger.WithError(err).Warn("policy-based node selection failed, falling back to broadcast") + // Fall back to original broadcast behavior + return a.spawnRequestBroadcast(req) + } + + a.logger.WithFields(log.Fields{ + "policy": a.policyEngine.GetPolicy().Name, + "selected": len(selectedNodes), + "top_node": selectedNodes[0], + }).Info("policy-based node selection completed") + + // Try nodes in priority order + req.DryRun = false + payload, err := wrapClusterMessage(pb.ClusterEvent_SPAWN, req) + if err != nil { + return nil, err + } + + for i, nodeName := range selectedNodes { + a.logger.WithFields(log.Fields{ + "node": nodeName, + "priority": i + 1, + "total": len(selectedNodes), + }).Info("attempting to spawn on policy-selected node") + + params := a.serf.DefaultQueryParams() + params.Timeout = time.Second * 90 + params.FilterNodes = []string{nodeName} + + query, err := a.serf.Query(QueryName, payload, params) + if err != nil { + a.logger.WithError(err).WithField("node", nodeName).Warn("query failed, trying next node") + continue + } + + for response := range query.ResponseCh() { + var resp pb.ClusterMessage + if err := proto.Unmarshal(response.Payload, &resp); err != nil { + a.logger.WithError(err).Error("failed to unmarshal response") + continue + } + + if resp.GetEvent() == pb.ClusterEvent_ERROR { + var errorResp pb.ErrorResponse + if err := resp.GetWrappedMessage().UnmarshalTo(&errorResp); err != nil { + a.logger.WithError(err).Error("failed to unmarshal error response") + continue + } + + a.logger.WithField("error", errorResp.GetError()).Warn("node returned error, trying next node") + continue + } + + var wrappedResp pb.VmSpawnResponse + if err := resp.GetWrappedMessage().UnmarshalTo(&wrappedResp); err != nil { + return nil, err + } + + a.logger.WithField("node", response.From).Info("successfully spawned VM on policy-selected node") + return &wrappedResp, nil + } + } + + return nil, errors.New("no suitable node found after trying all policy-selected candidates") +} + +// spawnRequestBroadcast is the original broadcast-based spawn (fallback) +func (a *Agent) spawnRequestBroadcast(req *pb.VmSpawnRequest) (*pb.VmSpawnResponse, error) { req.DryRun = true payload, err := wrapClusterMessage(pb.ClusterEvent_SPAWN, req) if err != nil { @@ -520,10 +675,7 @@ func (a *Agent) SpawnRequest(req *pb.VmSpawnRequest) (*pb.VmSpawnResponse, error a.logger.Infof("Successful response from node: %s", response.From) params := a.serf.DefaultQueryParams() - // Give 90 seconds to the node to pull the image from the network - // and spawn the VM params.Timeout = time.Second * 90 - // Only send the query to the node that sent the response params.FilterNodes = []string{response.From} query, err = a.serf.Query(QueryName, payload, params) @@ -675,6 +827,47 @@ func (a *Agent) monitorWorkloads() { }, } + // Update metrics from Serf stats before getting beacon metadata + if a.beaconClient != nil { + // Get queue depth from Serf stats + stats := a.serf.Stats() + var queueDepth uint32 + if queueDepthStr, ok := stats["event_queue_depth"]; ok { + if qd, err := strconv.Atoi(queueDepthStr); err == nil { + queueDepth = uint32(qd) + a.logger.WithField("queue_depth", queueDepth).Debug("read queue depth from Serf stats") + } else { + a.logger.WithError(err).WithField("queue_depth_str", queueDepthStr).Debug("failed to parse queue depth") + } + } else { + a.logger.Debug("queue_depth not found in Serf stats") + } + + // Measure average latency to other cluster members + latencyMs := a.measureClusterLatency() + if latencyMs > 0 { + a.logger.WithField("latency_ms", latencyMs).Debug("measured cluster latency") + } else { + a.logger.Debug("latency measurement returned 0 (no other members or measurement failed)") + } + + // Calculate jitter (variance in latency measurements) + jitterMs := a.calculateJitter() + + // Update beacon metrics with real measurements + a.beaconClient.UpdateMetrics(latencyMs, jitterMs, 0.0, queueDepth) + + beaconMetadata := a.beaconClient.GetBeaconMetadata() + resp.Beacon = beaconMetadata + a.logger.WithFields(log.Fields{ + "beacon_node_id": beaconMetadata.BeaconNodeId, + "latency_ms": beaconMetadata.LatencyMs, + "jitter_ms": beaconMetadata.JitterMs, + "queue_depth": beaconMetadata.QueueDepth, + "price_per_gb": beaconMetadata.PricePerGb, + }).Debug("added beacon metadata to state response") + } + for _, task := range tasks { a.logger.Infof("Got task %s, state: %s", task.GetID(), task.GetStatus()) @@ -794,6 +987,7 @@ func (a *Agent) monitorWorkloads() { partResp := pb.NodeStateResponse{ Node: resp.GetNode(), Workloads: resp.GetWorkloads()[(part * 10):min((part+1)*10, len(resp.GetWorkloads()))], + Beacon: resp.GetBeacon(), // Include beacon metadata in all parts } if parts == 1 { @@ -876,6 +1070,96 @@ func (a *Agent) findMember(name string) *serf.Member { return nil } +// measureClusterLatency measures average latency to other cluster members +// Uses Serf's member RTT if available, otherwise falls back to TCP connection test +func (a *Agent) measureClusterLatency() float64 { + members := a.serf.Members() + if len(members) <= 1 { + return 0.0 // No other members to measure + } + + var totalLatency time.Duration + var measuredCount int + + for _, member := range members { + if member.Status != serf.StatusAlive || member.Name == a.serf.LocalMember().Name { + continue + } + + // Try to use Serf's internal RTT measurement if available + // Serf tracks RTT for each member in its memberlist + // For now, measure latency by attempting TCP connection to gRPC port + // (more reliable than UDP port 7946) + start := time.Now() + // Try gRPC port (8000) instead of Serf port (7946 UDP) + addr := fmt.Sprintf("%s:8000", member.Addr.String()) + conn, err := net.DialTimeout("tcp", addr, 200*time.Millisecond) + if err == nil { + latency := time.Since(start) + totalLatency += latency + measuredCount++ + conn.Close() + a.logger.WithFields(log.Fields{ + "member": member.Name, + "addr": addr, + "latency_ms": float64(latency.Nanoseconds()) / 1e6, + }).Debug("measured latency to cluster member") + } else { + a.logger.WithFields(log.Fields{ + "member": member.Name, + "addr": addr, + "error": err, + }).Debug("failed to measure latency to cluster member") + } + } + + if measuredCount == 0 { + return 0.0 + } + + avgLatency := totalLatency / time.Duration(measuredCount) + latencyMs := float64(avgLatency.Nanoseconds()) / 1e6 // Convert to milliseconds + + // Store in history for jitter calculation + a.latencyHistoryMu.Lock() + a.latencyHistory = append(a.latencyHistory, latencyMs) + if len(a.latencyHistory) > 10 { + a.latencyHistory = a.latencyHistory[1:] // Keep last 10 + } + a.latencyHistoryMu.Unlock() + + return latencyMs +} + +// calculateJitter calculates jitter (variance) from latency history +func (a *Agent) calculateJitter() float64 { + a.latencyHistoryMu.Lock() + defer a.latencyHistoryMu.Unlock() + + if len(a.latencyHistory) < 2 { + return 0.0 // Need at least 2 measurements for variance + } + + // Calculate mean + var sum float64 + for _, l := range a.latencyHistory { + sum += l + } + mean := sum / float64(len(a.latencyHistory)) + + // Calculate variance (jitter) + var variance float64 + for _, l := range a.latencyHistory { + diff := l - mean + variance += diff * diff + } + variance /= float64(len(a.latencyHistory)) + + // Jitter is standard deviation (square root of variance) + jitter := math.Sqrt(variance) + return jitter +} + func (a *Agent) Join(addr string) error { _, err := a.serf.Join([]string{addr}, true) diff --git a/pkg/policy/engine.go b/pkg/policy/engine.go new file mode 100644 index 0000000..3a1a198 --- /dev/null +++ b/pkg/policy/engine.go @@ -0,0 +1,306 @@ +package policy + +import ( + "fmt" + "os" + "strconv" + "sync" + + "github.com/hashicorp/serf/serf" + "github.com/sirupsen/logrus" + pb "vistara-node/pkg/proto/cluster" +) + +// Engine evaluates policies and selects nodes for workload placement +type Engine struct { + logger *logrus.Logger + currentPolicy *Policy + policyMutex sync.RWMutex + + // Metrics + evaluations int64 + violations int64 + metricsMutex sync.RWMutex +} + +// NewEngine creates a new policy engine +func NewEngine(logger *logrus.Logger) *Engine { + return &Engine{ + logger: logger, + currentPolicy: DefaultPolicy(), + evaluations: 0, + violations: 0, + } +} + +// LoadPolicy loads a policy from a file path +func (e *Engine) LoadPolicy(policyPath string) error { + if policyPath == "" { + e.logger.Info("no policy file specified, using default policy") + e.SetPolicy(DefaultPolicy()) + return nil + } + + data, err := os.ReadFile(policyPath) + if err != nil { + return fmt.Errorf("failed to read policy file: %w", err) + } + + policy, err := LoadPolicyFromJSON(data) + if err != nil { + return err + } + + if err := policy.Validate(); err != nil { + return fmt.Errorf("invalid policy: %w", err) + } + + e.SetPolicy(policy) + e.logger.WithFields(logrus.Fields{ + "name": policy.Name, + "mode": policy.Mode, + }).Info("loaded policy") + + return nil +} + +// SetPolicy sets the current policy +func (e *Engine) SetPolicy(policy *Policy) { + e.policyMutex.Lock() + defer e.policyMutex.Unlock() + e.currentPolicy = policy +} + +// GetPolicy returns the current policy +func (e *Engine) GetPolicy() *Policy { + e.policyMutex.RLock() + defer e.policyMutex.RUnlock() + return e.currentPolicy +} + +// CanSpawn checks if a spawn request is allowed by the current policy +func (e *Engine) CanSpawn(req *pb.VmSpawnRequest) (bool, string) { + e.incrementEvaluations() + + policy := e.GetPolicy() + + // In permissive mode, always allow + if policy.Mode == "permissive" { + return true, "" + } + + // In enforce mode, check constraints + // For now, always allow spawn requests - node selection happens in SelectNodes + return true, "" +} + +// SelectNodes selects the best nodes for a workload based on the current policy +func (e *Engine) SelectNodes(req *pb.VmSpawnRequest, members []serf.Member, stateMap map[string]*pb.NodeStateResponse) ([]string, error) { + e.incrementEvaluations() + + policy := e.GetPolicy() + + // Build candidate list with scores + type candidate struct { + name string + score float64 + metadata *pb.BeaconMetadata + } + + var candidates []candidate + + for _, member := range members { + // Skip if not alive + if member.Status != serf.StatusAlive { + continue + } + + // Get state for this node + state, hasState := stateMap[member.Name] + if !hasState || state.Beacon == nil { + e.logger.WithField("node", member.Name).Debug("node has no beacon metadata, using permissive evaluation") + + // In permissive mode, include nodes without beacon data + if policy.Mode == "permissive" { + candidates = append(candidates, candidate{ + name: member.Name, + score: 0.5, // Neutral score + metadata: nil, + }) + } + continue + } + + beacon := state.Beacon + + // Check hard constraints + if !e.meetsConstraints(policy, beacon) { + e.logger.WithFields(logrus.Fields{ + "node": member.Name, + "latency": beacon.LatencyMs, + "price": beacon.PricePerGb, + "reputation": beacon.ReputationScore, + }).Debug("node does not meet policy constraints") + + e.incrementViolations() + continue + } + + // Calculate score + score := e.calculateScore(policy, beacon) + + candidates = append(candidates, candidate{ + name: member.Name, + score: score, + metadata: beacon, + }) + } + + if len(candidates) == 0 { + return nil, fmt.Errorf("no nodes match policy constraints") + } + + // Sort candidates by score (descending) + for i := 0; i < len(candidates); i++ { + for j := i + 1; j < len(candidates); j++ { + if candidates[j].score > candidates[i].score { + candidates[i], candidates[j] = candidates[j], candidates[i] + } + } + } + + // Log top candidates + e.logger.WithFields(logrus.Fields{ + "policy": policy.Name, + "candidates": len(candidates), + "top_node": candidates[0].name, + "top_score": candidates[0].score, + }).Info("policy evaluation completed") + + // Return node names in score order + nodeNames := make([]string, len(candidates)) + for i, c := range candidates { + nodeNames[i] = c.name + } + + return nodeNames, nil +} + +// meetsConstraints checks if a node meets the hard constraints +func (e *Engine) meetsConstraints(policy *Policy, beacon *pb.BeaconMetadata) bool { + rules := policy.Rules + + // Check latency + if rules.MaxLatencyMs > 0 && beacon.LatencyMs > rules.MaxLatencyMs { + return false + } + + // Check price + if rules.MaxPricePerGB > 0 && beacon.PricePerGb > rules.MaxPricePerGB { + return false + } + + // Check reputation + if rules.MinReputationScore > 0 { + repScore, err := strconv.ParseFloat(beacon.ReputationScore, 64) + if err != nil || repScore < rules.MinReputationScore { + return false + } + } + + // Check queue depth + if rules.MaxQueueDepth > 0 && beacon.QueueDepth > rules.MaxQueueDepth { + return false + } + + // Check packet loss + if rules.MaxPacketLoss > 0 && beacon.PacketLoss > rules.MaxPacketLoss { + return false + } + + // Check jitter + if rules.MaxJitterMs > 0 && beacon.JitterMs > rules.MaxJitterMs { + return false + } + + // Check required capabilities + if len(rules.RequiredCapabilities) > 0 { + capMap := make(map[string]bool) + for _, cap := range beacon.NodeCapabilities { + capMap[cap] = true + } + + for _, required := range rules.RequiredCapabilities { + if !capMap[required] { + return false + } + } + } + + return true +} + +// calculateScore computes a score for a node based on policy weights +func (e *Engine) calculateScore(policy *Policy, beacon *pb.BeaconMetadata) float64 { + weights := policy.Scoring + score := 0.0 + + // Latency score (lower is better) - normalize to 0-1 + if weights.LatencyWeight > 0 { + // Assume 200ms is "bad" latency, 0ms is perfect + latencyScore := 1.0 - (beacon.LatencyMs / 200.0) + if latencyScore < 0 { + latencyScore = 0 + } + score += weights.LatencyWeight * latencyScore + } + + // Price score (lower is better) - normalize to 0-1 + if weights.PriceWeight > 0 { + // Assume $1/GB is "expensive", $0 is free + priceScore := 1.0 - (beacon.PricePerGb / 1.0) + if priceScore < 0 { + priceScore = 0 + } + score += weights.PriceWeight * priceScore + } + + // Reputation score (higher is better) - already 0-1 + if weights.ReputationWeight > 0 { + repScore, err := strconv.ParseFloat(beacon.ReputationScore, 64) + if err == nil { + score += weights.ReputationWeight * repScore + } + } + + // Queue depth score (lower is better) - normalize to 0-1 + if weights.QueueWeight > 0 { + // Assume queue depth of 100 is "bad", 0 is perfect + queueScore := 1.0 - (float64(beacon.QueueDepth) / 100.0) + if queueScore < 0 { + queueScore = 0 + } + score += weights.QueueWeight * queueScore + } + + return score +} + +// GetMetrics returns policy engine metrics +func (e *Engine) GetMetrics() (evaluations int64, violations int64) { + e.metricsMutex.RLock() + defer e.metricsMutex.RUnlock() + return e.evaluations, e.violations +} + +func (e *Engine) incrementEvaluations() { + e.metricsMutex.Lock() + defer e.metricsMutex.Unlock() + e.evaluations++ +} + +func (e *Engine) incrementViolations() { + e.metricsMutex.Lock() + defer e.metricsMutex.Unlock() + e.violations++ +} diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go new file mode 100644 index 0000000..0500252 --- /dev/null +++ b/pkg/policy/policy.go @@ -0,0 +1,121 @@ +package policy + +import ( + "encoding/json" + "fmt" +) + +// Policy defines the structure for workload placement policies +type Policy struct { + Name string `json:"name"` + Description string `json:"description"` + Mode string `json:"mode"` // "enforce" or "permissive" + Rules PolicyRules `json:"rules"` + Scoring ScoreWeights `json:"scoring,omitempty"` +} + +// PolicyRules defines constraints and preferences for node selection +type PolicyRules struct { + // Hard constraints (must match) + RequiredCapabilities []string `json:"required_capabilities,omitempty"` + MaxLatencyMs float64 `json:"max_latency_ms,omitempty"` + MaxPricePerGB float64 `json:"max_price_per_gb,omitempty"` + MinReputationScore float64 `json:"min_reputation_score,omitempty"` + MaxQueueDepth uint32 `json:"max_queue_depth,omitempty"` + MaxPacketLoss float64 `json:"max_packet_loss,omitempty"` + MaxJitterMs float64 `json:"max_jitter_ms,omitempty"` + + // Soft preferences (ranked by score) + PreferLowLatency bool `json:"prefer_low_latency,omitempty"` + PreferLowPrice bool `json:"prefer_low_price,omitempty"` + PreferHighReputation bool `json:"prefer_high_reputation,omitempty"` +} + +// ScoreWeights defines how to weight different metrics when ranking nodes +type ScoreWeights struct { + LatencyWeight float64 `json:"latency_weight"` // Higher = prioritize low latency + PriceWeight float64 `json:"price_weight"` // Higher = prioritize low price + ReputationWeight float64 `json:"reputation_weight"` // Higher = prioritize high reputation + QueueWeight float64 `json:"queue_weight"` // Higher = prioritize low queue depth +} + +// DefaultPolicy returns a permissive default policy +func DefaultPolicy() *Policy { + return &Policy{ + Name: "default", + Description: "Default permissive policy - accepts any node", + Mode: "permissive", + Rules: PolicyRules{ + RequiredCapabilities: []string{}, + MaxLatencyMs: 0, // 0 = no limit + MaxPricePerGB: 0, + MinReputationScore: 0, + MaxQueueDepth: 0, + MaxPacketLoss: 100.0, + MaxJitterMs: 0, + }, + Scoring: ScoreWeights{ + LatencyWeight: 0.25, + PriceWeight: 0.25, + ReputationWeight: 0.25, + QueueWeight: 0.25, + }, + } +} + +// LoadPolicyFromJSON parses a policy from JSON bytes +func LoadPolicyFromJSON(data []byte) (*Policy, error) { + var policy Policy + if err := json.Unmarshal(data, &policy); err != nil { + return nil, fmt.Errorf("failed to parse policy JSON: %w", err) + } + + // Validate mode + if policy.Mode != "enforce" && policy.Mode != "permissive" { + return nil, fmt.Errorf("invalid policy mode: %s (must be 'enforce' or 'permissive')", policy.Mode) + } + + // Normalize score weights + if policy.Scoring.LatencyWeight == 0 && policy.Scoring.PriceWeight == 0 && + policy.Scoring.ReputationWeight == 0 && policy.Scoring.QueueWeight == 0 { + // No weights specified, use defaults + policy.Scoring = DefaultPolicy().Scoring + } + + return &policy, nil +} + +// ToJSON serializes the policy to JSON +func (p *Policy) ToJSON() ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} + +// Validate checks if the policy is valid +func (p *Policy) Validate() error { + if p.Name == "" { + return fmt.Errorf("policy name cannot be empty") + } + + if p.Mode != "enforce" && p.Mode != "permissive" { + return fmt.Errorf("invalid mode: %s", p.Mode) + } + + // Validate constraints make sense + if p.Rules.MaxLatencyMs < 0 { + return fmt.Errorf("max_latency_ms cannot be negative") + } + + if p.Rules.MaxPricePerGB < 0 { + return fmt.Errorf("max_price_per_gb cannot be negative") + } + + if p.Rules.MinReputationScore < 0 || p.Rules.MinReputationScore > 1 { + return fmt.Errorf("min_reputation_score must be between 0 and 1") + } + + if p.Rules.MaxPacketLoss < 0 || p.Rules.MaxPacketLoss > 100 { + return fmt.Errorf("max_packet_loss must be between 0 and 100") + } + + return nil +} diff --git a/pkg/proto/cluster.proto b/pkg/proto/cluster.proto index 66fd898..d6de5b2 100644 --- a/pkg/proto/cluster.proto +++ b/pkg/proto/cluster.proto @@ -17,6 +17,9 @@ enum ClusterEvent { ERROR = 0; SPAWN = 1; STOP = 2; + BEACON_ATTEST = 3; + POLICY_QUERY = 4; + PROOF_VERIFY = 5; } message ClusterMessage { @@ -24,6 +27,55 @@ message ClusterMessage { google.protobuf.Any wrappedMessage = 2; } +// IBRL: Beacon module messages +message BeaconMetadata { + string beacon_node_id = 1; + bytes node_signature = 2; + int64 timestamp = 3; + string reputation_score = 4; + repeated string node_capabilities = 5; + double latency_ms = 6; + double jitter_ms = 7; + double packet_loss = 8; + uint32 queue_depth = 9; + double price_per_gb = 10; +} + +message BeaconAttestation { + string node_id = 1; + string attestation_type = 2; + bytes attestation_data = 3; +} + +// IBRL: Policy module messages +message PolicyContext { + string policy_id = 1; + repeated string tags = 2; + string enforcement_level = 3; +} + +message PolicyQuery { + string workload_id = 1; + string policy_type = 2; + map context = 3; +} + +// IBRL: Proof module messages +message WorkloadProof { + string proof_hash = 1; + bytes proof_signature = 2; + map metrics = 3; + int64 proof_timestamp = 4; + string hypervisor_type = 5; +} + +message ProofVerification { + string workload_id = 1; + string proof_hash = 2; + string verification_result = 3; + string beacon_registry_hash = 4; +} + message ErrorResponse { string error = 1; } @@ -50,11 +102,15 @@ message VmStopRequest { message WorkloadState { string id = 1; VmSpawnRequest source_request = 2; + WorkloadProof proof = 3; } message NodeStateResponse { Node node = 1; repeated WorkloadState workloads = 2; + BeaconMetadata beacon = 3; + PolicyContext policy = 4; + string state_signature = 5; } message NodesStateResponse { diff --git a/pkg/proto/cluster/cluster.pb.go b/pkg/proto/cluster/cluster.pb.go index 4ad3a11..29d460a 100644 --- a/pkg/proto/cluster/cluster.pb.go +++ b/pkg/proto/cluster/cluster.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.2 -// protoc v6.30.1 +// protoc-gen-go v1.36.10 +// protoc v3.21.12 // source: pkg/proto/cluster.proto package cluster @@ -12,6 +12,7 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -24,9 +25,12 @@ const ( type ClusterEvent int32 const ( - ClusterEvent_ERROR ClusterEvent = 0 - ClusterEvent_SPAWN ClusterEvent = 1 - ClusterEvent_STOP ClusterEvent = 2 + ClusterEvent_ERROR ClusterEvent = 0 + ClusterEvent_SPAWN ClusterEvent = 1 + ClusterEvent_STOP ClusterEvent = 2 + ClusterEvent_BEACON_ATTEST ClusterEvent = 3 + ClusterEvent_POLICY_QUERY ClusterEvent = 4 + ClusterEvent_PROOF_VERIFY ClusterEvent = 5 ) // Enum value maps for ClusterEvent. @@ -35,11 +39,17 @@ var ( 0: "ERROR", 1: "SPAWN", 2: "STOP", + 3: "BEACON_ATTEST", + 4: "POLICY_QUERY", + 5: "PROOF_VERIFY", } ClusterEvent_value = map[string]int32{ - "ERROR": 0, - "SPAWN": 1, - "STOP": 2, + "ERROR": 0, + "SPAWN": 1, + "STOP": 2, + "BEACON_ATTEST": 3, + "POLICY_QUERY": 4, + "PROOF_VERIFY": 5, } ) @@ -122,6 +132,449 @@ func (x *ClusterMessage) GetWrappedMessage() *anypb.Any { return nil } +// IBRL: Beacon module messages +type BeaconMetadata struct { + state protoimpl.MessageState `protogen:"open.v1"` + BeaconNodeId string `protobuf:"bytes,1,opt,name=beacon_node_id,json=beaconNodeId,proto3" json:"beacon_node_id,omitempty"` + NodeSignature []byte `protobuf:"bytes,2,opt,name=node_signature,json=nodeSignature,proto3" json:"node_signature,omitempty"` + Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + ReputationScore string `protobuf:"bytes,4,opt,name=reputation_score,json=reputationScore,proto3" json:"reputation_score,omitempty"` + NodeCapabilities []string `protobuf:"bytes,5,rep,name=node_capabilities,json=nodeCapabilities,proto3" json:"node_capabilities,omitempty"` + LatencyMs float64 `protobuf:"fixed64,6,opt,name=latency_ms,json=latencyMs,proto3" json:"latency_ms,omitempty"` + JitterMs float64 `protobuf:"fixed64,7,opt,name=jitter_ms,json=jitterMs,proto3" json:"jitter_ms,omitempty"` + PacketLoss float64 `protobuf:"fixed64,8,opt,name=packet_loss,json=packetLoss,proto3" json:"packet_loss,omitempty"` + QueueDepth uint32 `protobuf:"varint,9,opt,name=queue_depth,json=queueDepth,proto3" json:"queue_depth,omitempty"` + PricePerGb float64 `protobuf:"fixed64,10,opt,name=price_per_gb,json=pricePerGb,proto3" json:"price_per_gb,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BeaconMetadata) Reset() { + *x = BeaconMetadata{} + mi := &file_pkg_proto_cluster_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BeaconMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BeaconMetadata) ProtoMessage() {} + +func (x *BeaconMetadata) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_cluster_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BeaconMetadata.ProtoReflect.Descriptor instead. +func (*BeaconMetadata) Descriptor() ([]byte, []int) { + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{1} +} + +func (x *BeaconMetadata) GetBeaconNodeId() string { + if x != nil { + return x.BeaconNodeId + } + return "" +} + +func (x *BeaconMetadata) GetNodeSignature() []byte { + if x != nil { + return x.NodeSignature + } + return nil +} + +func (x *BeaconMetadata) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *BeaconMetadata) GetReputationScore() string { + if x != nil { + return x.ReputationScore + } + return "" +} + +func (x *BeaconMetadata) GetNodeCapabilities() []string { + if x != nil { + return x.NodeCapabilities + } + return nil +} + +func (x *BeaconMetadata) GetLatencyMs() float64 { + if x != nil { + return x.LatencyMs + } + return 0 +} + +func (x *BeaconMetadata) GetJitterMs() float64 { + if x != nil { + return x.JitterMs + } + return 0 +} + +func (x *BeaconMetadata) GetPacketLoss() float64 { + if x != nil { + return x.PacketLoss + } + return 0 +} + +func (x *BeaconMetadata) GetQueueDepth() uint32 { + if x != nil { + return x.QueueDepth + } + return 0 +} + +func (x *BeaconMetadata) GetPricePerGb() float64 { + if x != nil { + return x.PricePerGb + } + return 0 +} + +type BeaconAttestation struct { + state protoimpl.MessageState `protogen:"open.v1"` + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + AttestationType string `protobuf:"bytes,2,opt,name=attestation_type,json=attestationType,proto3" json:"attestation_type,omitempty"` + AttestationData []byte `protobuf:"bytes,3,opt,name=attestation_data,json=attestationData,proto3" json:"attestation_data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BeaconAttestation) Reset() { + *x = BeaconAttestation{} + mi := &file_pkg_proto_cluster_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BeaconAttestation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BeaconAttestation) ProtoMessage() {} + +func (x *BeaconAttestation) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_cluster_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BeaconAttestation.ProtoReflect.Descriptor instead. +func (*BeaconAttestation) Descriptor() ([]byte, []int) { + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{2} +} + +func (x *BeaconAttestation) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *BeaconAttestation) GetAttestationType() string { + if x != nil { + return x.AttestationType + } + return "" +} + +func (x *BeaconAttestation) GetAttestationData() []byte { + if x != nil { + return x.AttestationData + } + return nil +} + +// IBRL: Policy module messages +type PolicyContext struct { + state protoimpl.MessageState `protogen:"open.v1"` + PolicyId string `protobuf:"bytes,1,opt,name=policy_id,json=policyId,proto3" json:"policy_id,omitempty"` + Tags []string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"` + EnforcementLevel string `protobuf:"bytes,3,opt,name=enforcement_level,json=enforcementLevel,proto3" json:"enforcement_level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PolicyContext) Reset() { + *x = PolicyContext{} + mi := &file_pkg_proto_cluster_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PolicyContext) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PolicyContext) ProtoMessage() {} + +func (x *PolicyContext) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_cluster_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PolicyContext.ProtoReflect.Descriptor instead. +func (*PolicyContext) Descriptor() ([]byte, []int) { + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{3} +} + +func (x *PolicyContext) GetPolicyId() string { + if x != nil { + return x.PolicyId + } + return "" +} + +func (x *PolicyContext) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *PolicyContext) GetEnforcementLevel() string { + if x != nil { + return x.EnforcementLevel + } + return "" +} + +type PolicyQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + WorkloadId string `protobuf:"bytes,1,opt,name=workload_id,json=workloadId,proto3" json:"workload_id,omitempty"` + PolicyType string `protobuf:"bytes,2,opt,name=policy_type,json=policyType,proto3" json:"policy_type,omitempty"` + Context map[string]string `protobuf:"bytes,3,rep,name=context,proto3" json:"context,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PolicyQuery) Reset() { + *x = PolicyQuery{} + mi := &file_pkg_proto_cluster_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PolicyQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PolicyQuery) ProtoMessage() {} + +func (x *PolicyQuery) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_cluster_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PolicyQuery.ProtoReflect.Descriptor instead. +func (*PolicyQuery) Descriptor() ([]byte, []int) { + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{4} +} + +func (x *PolicyQuery) GetWorkloadId() string { + if x != nil { + return x.WorkloadId + } + return "" +} + +func (x *PolicyQuery) GetPolicyType() string { + if x != nil { + return x.PolicyType + } + return "" +} + +func (x *PolicyQuery) GetContext() map[string]string { + if x != nil { + return x.Context + } + return nil +} + +// IBRL: Proof module messages +type WorkloadProof struct { + state protoimpl.MessageState `protogen:"open.v1"` + ProofHash string `protobuf:"bytes,1,opt,name=proof_hash,json=proofHash,proto3" json:"proof_hash,omitempty"` + ProofSignature []byte `protobuf:"bytes,2,opt,name=proof_signature,json=proofSignature,proto3" json:"proof_signature,omitempty"` + Metrics map[string]string `protobuf:"bytes,3,rep,name=metrics,proto3" json:"metrics,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + ProofTimestamp int64 `protobuf:"varint,4,opt,name=proof_timestamp,json=proofTimestamp,proto3" json:"proof_timestamp,omitempty"` + HypervisorType string `protobuf:"bytes,5,opt,name=hypervisor_type,json=hypervisorType,proto3" json:"hypervisor_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WorkloadProof) Reset() { + *x = WorkloadProof{} + mi := &file_pkg_proto_cluster_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WorkloadProof) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkloadProof) ProtoMessage() {} + +func (x *WorkloadProof) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_cluster_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WorkloadProof.ProtoReflect.Descriptor instead. +func (*WorkloadProof) Descriptor() ([]byte, []int) { + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{5} +} + +func (x *WorkloadProof) GetProofHash() string { + if x != nil { + return x.ProofHash + } + return "" +} + +func (x *WorkloadProof) GetProofSignature() []byte { + if x != nil { + return x.ProofSignature + } + return nil +} + +func (x *WorkloadProof) GetMetrics() map[string]string { + if x != nil { + return x.Metrics + } + return nil +} + +func (x *WorkloadProof) GetProofTimestamp() int64 { + if x != nil { + return x.ProofTimestamp + } + return 0 +} + +func (x *WorkloadProof) GetHypervisorType() string { + if x != nil { + return x.HypervisorType + } + return "" +} + +type ProofVerification struct { + state protoimpl.MessageState `protogen:"open.v1"` + WorkloadId string `protobuf:"bytes,1,opt,name=workload_id,json=workloadId,proto3" json:"workload_id,omitempty"` + ProofHash string `protobuf:"bytes,2,opt,name=proof_hash,json=proofHash,proto3" json:"proof_hash,omitempty"` + VerificationResult string `protobuf:"bytes,3,opt,name=verification_result,json=verificationResult,proto3" json:"verification_result,omitempty"` + BeaconRegistryHash string `protobuf:"bytes,4,opt,name=beacon_registry_hash,json=beaconRegistryHash,proto3" json:"beacon_registry_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProofVerification) Reset() { + *x = ProofVerification{} + mi := &file_pkg_proto_cluster_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProofVerification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProofVerification) ProtoMessage() {} + +func (x *ProofVerification) ProtoReflect() protoreflect.Message { + mi := &file_pkg_proto_cluster_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProofVerification.ProtoReflect.Descriptor instead. +func (*ProofVerification) Descriptor() ([]byte, []int) { + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{6} +} + +func (x *ProofVerification) GetWorkloadId() string { + if x != nil { + return x.WorkloadId + } + return "" +} + +func (x *ProofVerification) GetProofHash() string { + if x != nil { + return x.ProofHash + } + return "" +} + +func (x *ProofVerification) GetVerificationResult() string { + if x != nil { + return x.VerificationResult + } + return "" +} + +func (x *ProofVerification) GetBeaconRegistryHash() string { + if x != nil { + return x.BeaconRegistryHash + } + return "" +} + type ErrorResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` @@ -131,7 +584,7 @@ type ErrorResponse struct { func (x *ErrorResponse) Reset() { *x = ErrorResponse{} - mi := &file_pkg_proto_cluster_proto_msgTypes[1] + mi := &file_pkg_proto_cluster_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -143,7 +596,7 @@ func (x *ErrorResponse) String() string { func (*ErrorResponse) ProtoMessage() {} func (x *ErrorResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[1] + mi := &file_pkg_proto_cluster_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -156,7 +609,7 @@ func (x *ErrorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrorResponse.ProtoReflect.Descriptor instead. func (*ErrorResponse) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{1} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{7} } func (x *ErrorResponse) GetError() string { @@ -176,7 +629,7 @@ type Node struct { func (x *Node) Reset() { *x = Node{} - mi := &file_pkg_proto_cluster_proto_msgTypes[2] + mi := &file_pkg_proto_cluster_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -188,7 +641,7 @@ func (x *Node) String() string { func (*Node) ProtoMessage() {} func (x *Node) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[2] + mi := &file_pkg_proto_cluster_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -201,7 +654,7 @@ func (x *Node) ProtoReflect() protoreflect.Message { // Deprecated: Use Node.ProtoReflect.Descriptor instead. func (*Node) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{2} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{8} } func (x *Node) GetId() string { @@ -233,7 +686,7 @@ type VmSpawnRequest struct { func (x *VmSpawnRequest) Reset() { *x = VmSpawnRequest{} - mi := &file_pkg_proto_cluster_proto_msgTypes[3] + mi := &file_pkg_proto_cluster_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -245,7 +698,7 @@ func (x *VmSpawnRequest) String() string { func (*VmSpawnRequest) ProtoMessage() {} func (x *VmSpawnRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[3] + mi := &file_pkg_proto_cluster_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -258,7 +711,7 @@ func (x *VmSpawnRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VmSpawnRequest.ProtoReflect.Descriptor instead. func (*VmSpawnRequest) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{3} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{9} } func (x *VmSpawnRequest) GetCores() uint32 { @@ -312,7 +765,7 @@ type VmStopRequest struct { func (x *VmStopRequest) Reset() { *x = VmStopRequest{} - mi := &file_pkg_proto_cluster_proto_msgTypes[4] + mi := &file_pkg_proto_cluster_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -324,7 +777,7 @@ func (x *VmStopRequest) String() string { func (*VmStopRequest) ProtoMessage() {} func (x *VmStopRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[4] + mi := &file_pkg_proto_cluster_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -337,7 +790,7 @@ func (x *VmStopRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VmStopRequest.ProtoReflect.Descriptor instead. func (*VmStopRequest) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{4} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{10} } func (x *VmStopRequest) GetId() string { @@ -351,13 +804,14 @@ type WorkloadState struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` SourceRequest *VmSpawnRequest `protobuf:"bytes,2,opt,name=source_request,json=sourceRequest,proto3" json:"source_request,omitempty"` + Proof *WorkloadProof `protobuf:"bytes,3,opt,name=proof,proto3" json:"proof,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *WorkloadState) Reset() { *x = WorkloadState{} - mi := &file_pkg_proto_cluster_proto_msgTypes[5] + mi := &file_pkg_proto_cluster_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -369,7 +823,7 @@ func (x *WorkloadState) String() string { func (*WorkloadState) ProtoMessage() {} func (x *WorkloadState) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[5] + mi := &file_pkg_proto_cluster_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -382,7 +836,7 @@ func (x *WorkloadState) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadState.ProtoReflect.Descriptor instead. func (*WorkloadState) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{5} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{11} } func (x *WorkloadState) GetId() string { @@ -399,17 +853,27 @@ func (x *WorkloadState) GetSourceRequest() *VmSpawnRequest { return nil } +func (x *WorkloadState) GetProof() *WorkloadProof { + if x != nil { + return x.Proof + } + return nil +} + type NodeStateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - Workloads []*WorkloadState `protobuf:"bytes,2,rep,name=workloads,proto3" json:"workloads,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + Workloads []*WorkloadState `protobuf:"bytes,2,rep,name=workloads,proto3" json:"workloads,omitempty"` + Beacon *BeaconMetadata `protobuf:"bytes,3,opt,name=beacon,proto3" json:"beacon,omitempty"` + Policy *PolicyContext `protobuf:"bytes,4,opt,name=policy,proto3" json:"policy,omitempty"` + StateSignature string `protobuf:"bytes,5,opt,name=state_signature,json=stateSignature,proto3" json:"state_signature,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NodeStateResponse) Reset() { *x = NodeStateResponse{} - mi := &file_pkg_proto_cluster_proto_msgTypes[6] + mi := &file_pkg_proto_cluster_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -421,7 +885,7 @@ func (x *NodeStateResponse) String() string { func (*NodeStateResponse) ProtoMessage() {} func (x *NodeStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[6] + mi := &file_pkg_proto_cluster_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -434,7 +898,7 @@ func (x *NodeStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use NodeStateResponse.ProtoReflect.Descriptor instead. func (*NodeStateResponse) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{6} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{12} } func (x *NodeStateResponse) GetNode() *Node { @@ -451,6 +915,27 @@ func (x *NodeStateResponse) GetWorkloads() []*WorkloadState { return nil } +func (x *NodeStateResponse) GetBeacon() *BeaconMetadata { + if x != nil { + return x.Beacon + } + return nil +} + +func (x *NodeStateResponse) GetPolicy() *PolicyContext { + if x != nil { + return x.Policy + } + return nil +} + +func (x *NodeStateResponse) GetStateSignature() string { + if x != nil { + return x.StateSignature + } + return "" +} + type NodesStateResponse struct { state protoimpl.MessageState `protogen:"open.v1"` States []*NodeStateResponse `protobuf:"bytes,1,rep,name=states,proto3" json:"states,omitempty"` @@ -460,7 +945,7 @@ type NodesStateResponse struct { func (x *NodesStateResponse) Reset() { *x = NodesStateResponse{} - mi := &file_pkg_proto_cluster_proto_msgTypes[7] + mi := &file_pkg_proto_cluster_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -472,7 +957,7 @@ func (x *NodesStateResponse) String() string { func (*NodesStateResponse) ProtoMessage() {} func (x *NodesStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[7] + mi := &file_pkg_proto_cluster_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -485,7 +970,7 @@ func (x *NodesStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use NodesStateResponse.ProtoReflect.Descriptor instead. func (*NodesStateResponse) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{7} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{13} } func (x *NodesStateResponse) GetStates() []*NodeStateResponse { @@ -505,7 +990,7 @@ type VmSpawnResponse struct { func (x *VmSpawnResponse) Reset() { *x = VmSpawnResponse{} - mi := &file_pkg_proto_cluster_proto_msgTypes[8] + mi := &file_pkg_proto_cluster_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -517,7 +1002,7 @@ func (x *VmSpawnResponse) String() string { func (*VmSpawnResponse) ProtoMessage() {} func (x *VmSpawnResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[8] + mi := &file_pkg_proto_cluster_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -530,7 +1015,7 @@ func (x *VmSpawnResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VmSpawnResponse.ProtoReflect.Descriptor instead. func (*VmSpawnResponse) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{8} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{14} } func (x *VmSpawnResponse) GetId() string { @@ -555,7 +1040,7 @@ type VmQueryRequest struct { func (x *VmQueryRequest) Reset() { *x = VmQueryRequest{} - mi := &file_pkg_proto_cluster_proto_msgTypes[9] + mi := &file_pkg_proto_cluster_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -567,7 +1052,7 @@ func (x *VmQueryRequest) String() string { func (*VmQueryRequest) ProtoMessage() {} func (x *VmQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[9] + mi := &file_pkg_proto_cluster_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -580,7 +1065,7 @@ func (x *VmQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VmQueryRequest.ProtoReflect.Descriptor instead. func (*VmQueryRequest) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{9} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{15} } type VmQueryResponse struct { @@ -592,7 +1077,7 @@ type VmQueryResponse struct { func (x *VmQueryResponse) Reset() { *x = VmQueryResponse{} - mi := &file_pkg_proto_cluster_proto_msgTypes[10] + mi := &file_pkg_proto_cluster_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -604,7 +1089,7 @@ func (x *VmQueryResponse) String() string { func (*VmQueryResponse) ProtoMessage() {} func (x *VmQueryResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[10] + mi := &file_pkg_proto_cluster_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -617,7 +1102,7 @@ func (x *VmQueryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VmQueryResponse.ProtoReflect.Descriptor instead. func (*VmQueryResponse) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{10} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{16} } func (x *VmQueryResponse) GetVms() map[string]*VmSpawnRequest { @@ -636,7 +1121,7 @@ type VmLogsRequest struct { func (x *VmLogsRequest) Reset() { *x = VmLogsRequest{} - mi := &file_pkg_proto_cluster_proto_msgTypes[11] + mi := &file_pkg_proto_cluster_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -648,7 +1133,7 @@ func (x *VmLogsRequest) String() string { func (*VmLogsRequest) ProtoMessage() {} func (x *VmLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[11] + mi := &file_pkg_proto_cluster_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -661,7 +1146,7 @@ func (x *VmLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VmLogsRequest.ProtoReflect.Descriptor instead. func (*VmLogsRequest) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{11} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{17} } func (x *VmLogsRequest) GetId() string { @@ -680,7 +1165,7 @@ type VmLogsResponse struct { func (x *VmLogsResponse) Reset() { *x = VmLogsResponse{} - mi := &file_pkg_proto_cluster_proto_msgTypes[12] + mi := &file_pkg_proto_cluster_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -692,7 +1177,7 @@ func (x *VmLogsResponse) String() string { func (*VmLogsResponse) ProtoMessage() {} func (x *VmLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_proto_cluster_proto_msgTypes[12] + mi := &file_pkg_proto_cluster_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -705,7 +1190,7 @@ func (x *VmLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VmLogsResponse.ProtoReflect.Descriptor instead. func (*VmLogsResponse) Descriptor() ([]byte, []int) { - return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{12} + return file_pkg_proto_cluster_proto_rawDescGZIP(), []int{18} } func (x *VmLogsResponse) GetLogs() string { @@ -717,171 +1202,187 @@ func (x *VmLogsResponse) GetLogs() string { var File_pkg_proto_cluster_proto protoreflect.FileDescriptor -var file_pkg_proto_cluster_proto_rawDesc = []byte{ - 0x0a, 0x17, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x1a, - 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x88, 0x01, 0x0a, 0x0e, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, - 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x63, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x0e, 0x77, 0x72, 0x61, 0x70, 0x70, - 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x25, 0x0a, 0x0d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x26, 0x0a, 0x04, - 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x70, 0x22, 0x87, 0x02, 0x0a, 0x0e, 0x56, 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x72, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x16, 0x0a, - 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6d, - 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x72, - 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x66, 0x12, 0x45, 0x0a, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, - 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, - 0x75, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x03, 0x65, 0x6e, 0x76, 0x1a, 0x38, 0x0a, 0x0a, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1f, - 0x0a, 0x0d, 0x56, 0x6d, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, - 0x6c, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x4b, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x56, 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0d, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x86, 0x01, - 0x0a, 0x11, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, - 0x6f, 0x64, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x6f, - 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x09, 0x77, 0x6f, 0x72, - 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x22, 0x55, 0x0a, 0x12, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x33, 0x0a, - 0x0f, 0x56, 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, - 0x72, 0x6c, 0x22, 0x10, 0x0a, 0x0e, 0x56, 0x6d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0xb1, 0x01, 0x0a, 0x0f, 0x56, 0x6d, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x03, 0x76, 0x6d, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x6d, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x6d, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x76, 0x6d, 0x73, 0x1a, 0x5c, 0x0a, 0x08, 0x56, 0x6d, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, - 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1f, 0x0a, 0x0d, 0x56, 0x6d, 0x4c, 0x6f, - 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x24, 0x0a, 0x0e, 0x56, 0x6d, 0x4c, - 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, - 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x2a, - 0x2e, 0x0a, 0x0c, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x50, - 0x41, 0x57, 0x4e, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x02, 0x32, - 0xda, 0x02, 0x0a, 0x0e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x54, 0x0a, 0x05, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x12, 0x24, 0x2e, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x56, 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x6d, 0x53, 0x70, 0x61, 0x77, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, - 0x12, 0x23, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x6d, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x56, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x2e, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x56, 0x6d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x28, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x04, 0x4c, 0x6f, 0x67, - 0x73, 0x12, 0x23, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x6d, - 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x1b, 0x5a, 0x19, - 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x3b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} +const file_pkg_proto_cluster_proto_rawDesc = "" + + "\n" + + "\x17pkg/proto/cluster.proto\x12\x14cluster.services.api\x1a\x19google/protobuf/any.proto\"\x88\x01\n" + + "\x0eClusterMessage\x128\n" + + "\x05event\x18\x01 \x01(\x0e2\".cluster.services.api.ClusterEventR\x05event\x12<\n" + + "\x0ewrappedMessage\x18\x02 \x01(\v2\x14.google.protobuf.AnyR\x0ewrappedMessage\"\xf3\x02\n" + + "\x0eBeaconMetadata\x12$\n" + + "\x0ebeacon_node_id\x18\x01 \x01(\tR\fbeaconNodeId\x12%\n" + + "\x0enode_signature\x18\x02 \x01(\fR\rnodeSignature\x12\x1c\n" + + "\ttimestamp\x18\x03 \x01(\x03R\ttimestamp\x12)\n" + + "\x10reputation_score\x18\x04 \x01(\tR\x0freputationScore\x12+\n" + + "\x11node_capabilities\x18\x05 \x03(\tR\x10nodeCapabilities\x12\x1d\n" + + "\n" + + "latency_ms\x18\x06 \x01(\x01R\tlatencyMs\x12\x1b\n" + + "\tjitter_ms\x18\a \x01(\x01R\bjitterMs\x12\x1f\n" + + "\vpacket_loss\x18\b \x01(\x01R\n" + + "packetLoss\x12\x1f\n" + + "\vqueue_depth\x18\t \x01(\rR\n" + + "queueDepth\x12 \n" + + "\fprice_per_gb\x18\n" + + " \x01(\x01R\n" + + "pricePerGb\"\x82\x01\n" + + "\x11BeaconAttestation\x12\x17\n" + + "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12)\n" + + "\x10attestation_type\x18\x02 \x01(\tR\x0fattestationType\x12)\n" + + "\x10attestation_data\x18\x03 \x01(\fR\x0fattestationData\"m\n" + + "\rPolicyContext\x12\x1b\n" + + "\tpolicy_id\x18\x01 \x01(\tR\bpolicyId\x12\x12\n" + + "\x04tags\x18\x02 \x03(\tR\x04tags\x12+\n" + + "\x11enforcement_level\x18\x03 \x01(\tR\x10enforcementLevel\"\xd5\x01\n" + + "\vPolicyQuery\x12\x1f\n" + + "\vworkload_id\x18\x01 \x01(\tR\n" + + "workloadId\x12\x1f\n" + + "\vpolicy_type\x18\x02 \x01(\tR\n" + + "policyType\x12H\n" + + "\acontext\x18\x03 \x03(\v2..cluster.services.api.PolicyQuery.ContextEntryR\acontext\x1a:\n" + + "\fContextEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xb1\x02\n" + + "\rWorkloadProof\x12\x1d\n" + + "\n" + + "proof_hash\x18\x01 \x01(\tR\tproofHash\x12'\n" + + "\x0fproof_signature\x18\x02 \x01(\fR\x0eproofSignature\x12J\n" + + "\ametrics\x18\x03 \x03(\v20.cluster.services.api.WorkloadProof.MetricsEntryR\ametrics\x12'\n" + + "\x0fproof_timestamp\x18\x04 \x01(\x03R\x0eproofTimestamp\x12'\n" + + "\x0fhypervisor_type\x18\x05 \x01(\tR\x0ehypervisorType\x1a:\n" + + "\fMetricsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xb6\x01\n" + + "\x11ProofVerification\x12\x1f\n" + + "\vworkload_id\x18\x01 \x01(\tR\n" + + "workloadId\x12\x1d\n" + + "\n" + + "proof_hash\x18\x02 \x01(\tR\tproofHash\x12/\n" + + "\x13verification_result\x18\x03 \x01(\tR\x12verificationResult\x120\n" + + "\x14beacon_registry_hash\x18\x04 \x01(\tR\x12beaconRegistryHash\"%\n" + + "\rErrorResponse\x12\x14\n" + + "\x05error\x18\x01 \x01(\tR\x05error\"&\n" + + "\x04Node\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x0e\n" + + "\x02ip\x18\x02 \x01(\tR\x02ip\"\x87\x02\n" + + "\x0eVmSpawnRequest\x12\x14\n" + + "\x05cores\x18\x01 \x01(\rR\x05cores\x12\x16\n" + + "\x06memory\x18\x02 \x01(\rR\x06memory\x12\x1b\n" + + "\timage_ref\x18\x03 \x01(\tR\bimageRef\x12E\n" + + "\x05ports\x18\x04 \x03(\v2/.cluster.services.api.VmSpawnRequest.PortsEntryR\x05ports\x12\x17\n" + + "\adry_run\x18\x05 \x01(\bR\x06dryRun\x12\x10\n" + + "\x03env\x18\x06 \x03(\tR\x03env\x1a8\n" + + "\n" + + "PortsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\rR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\rR\x05value:\x028\x01\"\x1f\n" + + "\rVmStopRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"\xa7\x01\n" + + "\rWorkloadState\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12K\n" + + "\x0esource_request\x18\x02 \x01(\v2$.cluster.services.api.VmSpawnRequestR\rsourceRequest\x129\n" + + "\x05proof\x18\x03 \x01(\v2#.cluster.services.api.WorkloadProofR\x05proof\"\xaa\x02\n" + + "\x11NodeStateResponse\x12.\n" + + "\x04node\x18\x01 \x01(\v2\x1a.cluster.services.api.NodeR\x04node\x12A\n" + + "\tworkloads\x18\x02 \x03(\v2#.cluster.services.api.WorkloadStateR\tworkloads\x12<\n" + + "\x06beacon\x18\x03 \x01(\v2$.cluster.services.api.BeaconMetadataR\x06beacon\x12;\n" + + "\x06policy\x18\x04 \x01(\v2#.cluster.services.api.PolicyContextR\x06policy\x12'\n" + + "\x0fstate_signature\x18\x05 \x01(\tR\x0estateSignature\"U\n" + + "\x12NodesStateResponse\x12?\n" + + "\x06states\x18\x01 \x03(\v2'.cluster.services.api.NodeStateResponseR\x06states\"3\n" + + "\x0fVmSpawnResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x10\n" + + "\x03url\x18\x02 \x01(\tR\x03url\"\x10\n" + + "\x0eVmQueryRequest\"\xb1\x01\n" + + "\x0fVmQueryResponse\x12@\n" + + "\x03vms\x18\x01 \x03(\v2..cluster.services.api.VmQueryResponse.VmsEntryR\x03vms\x1a\\\n" + + "\bVmsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" + + "\x05value\x18\x02 \x01(\v2$.cluster.services.api.VmSpawnRequestR\x05value:\x028\x01\"\x1f\n" + + "\rVmLogsRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"$\n" + + "\x0eVmLogsResponse\x12\x12\n" + + "\x04logs\x18\x01 \x01(\tR\x04logs*e\n" + + "\fClusterEvent\x12\t\n" + + "\x05ERROR\x10\x00\x12\t\n" + + "\x05SPAWN\x10\x01\x12\b\n" + + "\x04STOP\x10\x02\x12\x11\n" + + "\rBEACON_ATTEST\x10\x03\x12\x10\n" + + "\fPOLICY_QUERY\x10\x04\x12\x10\n" + + "\fPROOF_VERIFY\x10\x052\xda\x02\n" + + "\x0eClusterService\x12T\n" + + "\x05Spawn\x12$.cluster.services.api.VmSpawnRequest\x1a%.cluster.services.api.VmSpawnResponse\x12G\n" + + "\x04Stop\x12#.cluster.services.api.VmStopRequest\x1a\x1a.cluster.services.api.Node\x12V\n" + + "\x04List\x12$.cluster.services.api.VmQueryRequest\x1a(.cluster.services.api.NodesStateResponse\x12Q\n" + + "\x04Logs\x12#.cluster.services.api.VmLogsRequest\x1a$.cluster.services.api.VmLogsResponseB\x1bZ\x19pkg/proto/cluster;clusterb\x06proto3" var ( file_pkg_proto_cluster_proto_rawDescOnce sync.Once - file_pkg_proto_cluster_proto_rawDescData = file_pkg_proto_cluster_proto_rawDesc + file_pkg_proto_cluster_proto_rawDescData []byte ) func file_pkg_proto_cluster_proto_rawDescGZIP() []byte { file_pkg_proto_cluster_proto_rawDescOnce.Do(func() { - file_pkg_proto_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_proto_cluster_proto_rawDescData) + file_pkg_proto_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_pkg_proto_cluster_proto_rawDesc), len(file_pkg_proto_cluster_proto_rawDesc))) }) return file_pkg_proto_cluster_proto_rawDescData } var file_pkg_proto_cluster_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_pkg_proto_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_pkg_proto_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 23) var file_pkg_proto_cluster_proto_goTypes = []any{ (ClusterEvent)(0), // 0: cluster.services.api.ClusterEvent (*ClusterMessage)(nil), // 1: cluster.services.api.ClusterMessage - (*ErrorResponse)(nil), // 2: cluster.services.api.ErrorResponse - (*Node)(nil), // 3: cluster.services.api.Node - (*VmSpawnRequest)(nil), // 4: cluster.services.api.VmSpawnRequest - (*VmStopRequest)(nil), // 5: cluster.services.api.VmStopRequest - (*WorkloadState)(nil), // 6: cluster.services.api.WorkloadState - (*NodeStateResponse)(nil), // 7: cluster.services.api.NodeStateResponse - (*NodesStateResponse)(nil), // 8: cluster.services.api.NodesStateResponse - (*VmSpawnResponse)(nil), // 9: cluster.services.api.VmSpawnResponse - (*VmQueryRequest)(nil), // 10: cluster.services.api.VmQueryRequest - (*VmQueryResponse)(nil), // 11: cluster.services.api.VmQueryResponse - (*VmLogsRequest)(nil), // 12: cluster.services.api.VmLogsRequest - (*VmLogsResponse)(nil), // 13: cluster.services.api.VmLogsResponse - nil, // 14: cluster.services.api.VmSpawnRequest.PortsEntry - nil, // 15: cluster.services.api.VmQueryResponse.VmsEntry - (*anypb.Any)(nil), // 16: google.protobuf.Any + (*BeaconMetadata)(nil), // 2: cluster.services.api.BeaconMetadata + (*BeaconAttestation)(nil), // 3: cluster.services.api.BeaconAttestation + (*PolicyContext)(nil), // 4: cluster.services.api.PolicyContext + (*PolicyQuery)(nil), // 5: cluster.services.api.PolicyQuery + (*WorkloadProof)(nil), // 6: cluster.services.api.WorkloadProof + (*ProofVerification)(nil), // 7: cluster.services.api.ProofVerification + (*ErrorResponse)(nil), // 8: cluster.services.api.ErrorResponse + (*Node)(nil), // 9: cluster.services.api.Node + (*VmSpawnRequest)(nil), // 10: cluster.services.api.VmSpawnRequest + (*VmStopRequest)(nil), // 11: cluster.services.api.VmStopRequest + (*WorkloadState)(nil), // 12: cluster.services.api.WorkloadState + (*NodeStateResponse)(nil), // 13: cluster.services.api.NodeStateResponse + (*NodesStateResponse)(nil), // 14: cluster.services.api.NodesStateResponse + (*VmSpawnResponse)(nil), // 15: cluster.services.api.VmSpawnResponse + (*VmQueryRequest)(nil), // 16: cluster.services.api.VmQueryRequest + (*VmQueryResponse)(nil), // 17: cluster.services.api.VmQueryResponse + (*VmLogsRequest)(nil), // 18: cluster.services.api.VmLogsRequest + (*VmLogsResponse)(nil), // 19: cluster.services.api.VmLogsResponse + nil, // 20: cluster.services.api.PolicyQuery.ContextEntry + nil, // 21: cluster.services.api.WorkloadProof.MetricsEntry + nil, // 22: cluster.services.api.VmSpawnRequest.PortsEntry + nil, // 23: cluster.services.api.VmQueryResponse.VmsEntry + (*anypb.Any)(nil), // 24: google.protobuf.Any } var file_pkg_proto_cluster_proto_depIdxs = []int32{ 0, // 0: cluster.services.api.ClusterMessage.event:type_name -> cluster.services.api.ClusterEvent - 16, // 1: cluster.services.api.ClusterMessage.wrappedMessage:type_name -> google.protobuf.Any - 14, // 2: cluster.services.api.VmSpawnRequest.ports:type_name -> cluster.services.api.VmSpawnRequest.PortsEntry - 4, // 3: cluster.services.api.WorkloadState.source_request:type_name -> cluster.services.api.VmSpawnRequest - 3, // 4: cluster.services.api.NodeStateResponse.node:type_name -> cluster.services.api.Node - 6, // 5: cluster.services.api.NodeStateResponse.workloads:type_name -> cluster.services.api.WorkloadState - 7, // 6: cluster.services.api.NodesStateResponse.states:type_name -> cluster.services.api.NodeStateResponse - 15, // 7: cluster.services.api.VmQueryResponse.vms:type_name -> cluster.services.api.VmQueryResponse.VmsEntry - 4, // 8: cluster.services.api.VmQueryResponse.VmsEntry.value:type_name -> cluster.services.api.VmSpawnRequest - 4, // 9: cluster.services.api.ClusterService.Spawn:input_type -> cluster.services.api.VmSpawnRequest - 5, // 10: cluster.services.api.ClusterService.Stop:input_type -> cluster.services.api.VmStopRequest - 10, // 11: cluster.services.api.ClusterService.List:input_type -> cluster.services.api.VmQueryRequest - 12, // 12: cluster.services.api.ClusterService.Logs:input_type -> cluster.services.api.VmLogsRequest - 9, // 13: cluster.services.api.ClusterService.Spawn:output_type -> cluster.services.api.VmSpawnResponse - 3, // 14: cluster.services.api.ClusterService.Stop:output_type -> cluster.services.api.Node - 8, // 15: cluster.services.api.ClusterService.List:output_type -> cluster.services.api.NodesStateResponse - 13, // 16: cluster.services.api.ClusterService.Logs:output_type -> cluster.services.api.VmLogsResponse - 13, // [13:17] is the sub-list for method output_type - 9, // [9:13] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 24, // 1: cluster.services.api.ClusterMessage.wrappedMessage:type_name -> google.protobuf.Any + 20, // 2: cluster.services.api.PolicyQuery.context:type_name -> cluster.services.api.PolicyQuery.ContextEntry + 21, // 3: cluster.services.api.WorkloadProof.metrics:type_name -> cluster.services.api.WorkloadProof.MetricsEntry + 22, // 4: cluster.services.api.VmSpawnRequest.ports:type_name -> cluster.services.api.VmSpawnRequest.PortsEntry + 10, // 5: cluster.services.api.WorkloadState.source_request:type_name -> cluster.services.api.VmSpawnRequest + 6, // 6: cluster.services.api.WorkloadState.proof:type_name -> cluster.services.api.WorkloadProof + 9, // 7: cluster.services.api.NodeStateResponse.node:type_name -> cluster.services.api.Node + 12, // 8: cluster.services.api.NodeStateResponse.workloads:type_name -> cluster.services.api.WorkloadState + 2, // 9: cluster.services.api.NodeStateResponse.beacon:type_name -> cluster.services.api.BeaconMetadata + 4, // 10: cluster.services.api.NodeStateResponse.policy:type_name -> cluster.services.api.PolicyContext + 13, // 11: cluster.services.api.NodesStateResponse.states:type_name -> cluster.services.api.NodeStateResponse + 23, // 12: cluster.services.api.VmQueryResponse.vms:type_name -> cluster.services.api.VmQueryResponse.VmsEntry + 10, // 13: cluster.services.api.VmQueryResponse.VmsEntry.value:type_name -> cluster.services.api.VmSpawnRequest + 10, // 14: cluster.services.api.ClusterService.Spawn:input_type -> cluster.services.api.VmSpawnRequest + 11, // 15: cluster.services.api.ClusterService.Stop:input_type -> cluster.services.api.VmStopRequest + 16, // 16: cluster.services.api.ClusterService.List:input_type -> cluster.services.api.VmQueryRequest + 18, // 17: cluster.services.api.ClusterService.Logs:input_type -> cluster.services.api.VmLogsRequest + 15, // 18: cluster.services.api.ClusterService.Spawn:output_type -> cluster.services.api.VmSpawnResponse + 9, // 19: cluster.services.api.ClusterService.Stop:output_type -> cluster.services.api.Node + 14, // 20: cluster.services.api.ClusterService.List:output_type -> cluster.services.api.NodesStateResponse + 19, // 21: cluster.services.api.ClusterService.Logs:output_type -> cluster.services.api.VmLogsResponse + 18, // [18:22] is the sub-list for method output_type + 14, // [14:18] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_pkg_proto_cluster_proto_init() } @@ -893,9 +1394,9 @@ func file_pkg_proto_cluster_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_pkg_proto_cluster_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_pkg_proto_cluster_proto_rawDesc), len(file_pkg_proto_cluster_proto_rawDesc)), NumEnums: 1, - NumMessages: 15, + NumMessages: 23, NumExtensions: 0, NumServices: 1, }, @@ -905,7 +1406,6 @@ func file_pkg_proto_cluster_proto_init() { MessageInfos: file_pkg_proto_cluster_proto_msgTypes, }.Build() File_pkg_proto_cluster_proto = out.File - file_pkg_proto_cluster_proto_rawDesc = nil file_pkg_proto_cluster_proto_goTypes = nil file_pkg_proto_cluster_proto_depIdxs = nil } diff --git a/pkg/proto/cluster/cluster_grpc.pb.go b/pkg/proto/cluster/cluster_grpc.pb.go index d7846e0..27376f0 100644 --- a/pkg/proto/cluster/cluster_grpc.pb.go +++ b/pkg/proto/cluster/cluster_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v6.30.1 +// - protoc v3.21.12 // source: pkg/proto/cluster.proto package cluster