blob: bc3201aeaeaef09a0a94ec80c652ec00841eaf31 [file] [log] [blame]
Serge Bazanski4abeb132022-10-11 11:32:19 +02001package server
2
3import (
4 "context"
5 "crypto/ed25519"
6 "crypto/rand"
7 "testing"
8 "time"
9
10 "github.com/google/uuid"
11 "google.golang.org/grpc"
12
13 "source.monogon.dev/cloud/bmaas/bmdb"
14 "source.monogon.dev/cloud/bmaas/bmdb/model"
15 apb "source.monogon.dev/cloud/bmaas/server/api"
16 "source.monogon.dev/cloud/lib/component"
17 "source.monogon.dev/metropolis/node/core/rpc"
18)
19
20func dut() *Server {
21 return &Server{
22 Config: Config{
23 Component: component.ComponentConfig{
24 GRPCListenAddress: ":0",
25 DevCerts: true,
26 DevCertsPath: "/tmp/foo",
27 },
28 BMDB: bmdb.BMDB{
29 Config: bmdb.Config{
30 Database: component.CockroachConfig{
31 InMemory: true,
32 },
33 },
34 },
35 PublicListenAddress: ":0",
36 },
37 }
38}
39
40// TestAgentCallbackService exercises the basic flow for submitting an agent
41// heartbeat and hardware report.
42func TestAgentCallbackService(t *testing.T) {
43 s := dut()
44 ctx, ctxC := context.WithCancel(context.Background())
45 defer ctxC()
46 s.Start(ctx)
47
48 pub, priv, err := ed25519.GenerateKey(rand.Reader)
49 if err != nil {
50 t.Fatalf("could not generate keypair: %v", err)
51 }
52
53 sess, err := s.bmdb.StartSession(ctx)
54 if err != nil {
55 t.Fatalf("could not start session")
56 }
57
58 heartbeat := func(mid uuid.UUID) error {
59 creds, err := rpc.NewEphemeralCredentials(priv, nil)
60 if err != nil {
61 t.Fatalf("could not generate ephemeral credentials: %v", err)
62 }
63 conn, err := grpc.Dial(s.ListenPublic, grpc.WithTransportCredentials(creds))
64 if err != nil {
65 t.Fatalf("Dial failed: %v", err)
66 }
67 defer conn.Close()
68
69 stub := apb.NewAgentCallbackClient(conn)
70 _, err = stub.Heartbeat(ctx, &apb.AgentHeartbeatRequest{
71 MachineId: mid.String(),
72 HardwareReport: &apb.AgentHardwareReport{},
73 })
74 return err
75 }
76
77 // First, attempt to heartbeat for some totally made up machine ID. That should
78 // fail.
79 if err := heartbeat(uuid.New()); err == nil {
80 t.Errorf("heartbeat for made up UUID should've failed")
81 }
82
83 // Create an actual machine in the BMDB alongside the expected pubkey within an
84 // AgentStarted tag.
85 var machine model.Machine
86 err = sess.Transact(ctx, func(q *model.Queries) error {
87 machine, err = q.NewMachine(ctx)
88 if err != nil {
89 return err
90 }
91 err = q.MachineAddProvided(ctx, model.MachineAddProvidedParams{
92 MachineID: machine.MachineID,
93 Provider: model.ProviderEquinix,
94 ProviderID: "123",
95 })
96 if err != nil {
97 return err
98 }
99 return q.MachineSetAgentStarted(ctx, model.MachineSetAgentStartedParams{
100 MachineID: machine.MachineID,
101 AgentStartedAt: time.Now(),
102 AgentPublicKey: pub,
103 })
104 })
105 if err != nil {
106 t.Fatalf("could not create machine: %v", err)
107 }
108
109 // Now heartbeat with correct machine ID and key. This should succeed.
110 if err := heartbeat(machine.MachineID); err != nil {
111 t.Errorf("heartbeat should've succeeded, got: %v", err)
112 }
113
114 // TODO(q3k): test hardware report being attached once we have some debug API
115 // for tags.
116}