blob: 767ee29a45029febf881bd8abbaa464e2f04cea1 [file] [log] [blame]
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +02001package main
Serge Bazanskicaa12082023-02-16 14:54:04 +01002
3import (
4 "context"
5 "crypto/ed25519"
6 "crypto/rand"
7 "fmt"
8 "testing"
9 "time"
10
11 "github.com/packethost/packngo"
Serge Bazanskicaa12082023-02-16 14:54:04 +010012 "golang.org/x/time/rate"
Tim Windelschmidt0e749612023-08-07 17:42:59 +000013
Serge Bazanskicaa12082023-02-16 14:54:04 +010014 "source.monogon.dev/cloud/bmaas/bmdb"
15 "source.monogon.dev/cloud/bmaas/bmdb/model"
16 "source.monogon.dev/cloud/lib/component"
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020017 "source.monogon.dev/cloud/shepherd/manager"
Serge Bazanskicaa12082023-02-16 14:54:04 +010018)
19
Serge Bazanski86a714d2023-04-17 15:54:21 +020020type initializerDut struct {
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020021 f *fakequinix
22 i *manager.Initializer
23 bmdb *bmdb.Connection
24 ctx context.Context
25 provider *equinixProvider
Serge Bazanski86a714d2023-04-17 15:54:21 +020026}
27
28func newInitializerDut(t *testing.T) *initializerDut {
29 t.Helper()
30
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020031 sc := providerConfig{
Serge Bazanskicaa12082023-02-16 14:54:04 +010032 ProjectId: "noproject",
33 KeyLabel: "somekey",
Serge Bazanskicaa12082023-02-16 14:54:04 +010034 DevicePrefix: "test-",
35 }
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020036 _, key, _ := ed25519.GenerateKey(rand.Reader)
37 k := manager.SSHKey{
38 Key: key,
39 }
40
41 f := newFakequinix(sc.ProjectId, 100)
42 provider, err := sc.New(&k, f)
43 if err != nil {
44 t.Fatalf("Could not create Provider: %v", err)
45 }
46
47 ic := manager.InitializerConfig{
48 ControlLoopConfig: manager.ControlLoopConfig{
Serge Bazanski86a714d2023-04-17 15:54:21 +020049 DBQueryLimiter: rate.NewLimiter(rate.Every(time.Second), 10),
50 },
Serge Bazanskicaa12082023-02-16 14:54:04 +010051 Executable: []byte("beep boop i'm a real program"),
52 TargetPath: "/fake/path",
53 Endpoint: "example.com:1234",
54 SSHConnectTimeout: time.Second,
55 SSHExecTimeout: time.Second,
56 }
Serge Bazanski86a714d2023-04-17 15:54:21 +020057
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020058 i, err := manager.NewInitializer(provider, &manager.FakeSSHClient{}, ic)
Serge Bazanskicaa12082023-02-16 14:54:04 +010059 if err != nil {
60 t.Fatalf("Could not create Initializer: %v", err)
61 }
62
Serge Bazanskicaa12082023-02-16 14:54:04 +010063 b := bmdb.BMDB{
64 Config: bmdb.Config{
65 Database: component.CockroachConfig{
66 InMemory: true,
67 },
68 ComponentName: "test",
69 RuntimeInfo: "test",
70 },
71 }
72 conn, err := b.Open(true)
73 if err != nil {
74 t.Fatalf("Could not create in-memory BMDB: %v", err)
75 }
76
Serge Bazanski86a714d2023-04-17 15:54:21 +020077 ctx, ctxC := context.WithCancel(context.Background())
78 t.Cleanup(ctxC)
79
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020080 if err := provider.SSHEquinixEnsure(ctx); err != nil {
Serge Bazanskicaa12082023-02-16 14:54:04 +010081 t.Fatalf("Failed to ensure SSH key: %v", err)
82 }
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020083 go manager.RunControlLoop(ctx, conn, i)
Serge Bazanski86a714d2023-04-17 15:54:21 +020084
85 return &initializerDut{
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020086 f: f,
87 i: i,
88 bmdb: conn,
89 ctx: ctx,
90 provider: provider,
Serge Bazanski86a714d2023-04-17 15:54:21 +020091 }
92}
93
94// TestInitializerSmokes makes sure the Initializer doesn't go up in flames on
95// the happy path.
96func TestInitializerSmokes(t *testing.T) {
97 dut := newInitializerDut(t)
98 f := dut.f
99 ctx := dut.ctx
100 conn := dut.bmdb
Serge Bazanskicaa12082023-02-16 14:54:04 +0100101
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200102 reservations, _ := f.ListReservations(ctx, f.pid)
103 kid, err := dut.provider.sshEquinixId(ctx)
Serge Bazanskicaa12082023-02-16 14:54:04 +0100104 if err != nil {
105 t.Fatalf("Failed to retrieve equinix key ID: %v", err)
106 }
107 sess, err := conn.StartSession(ctx)
108 if err != nil {
109 t.Fatalf("Failed to create BMDB session for verifiaction: %v", err)
110 }
111
112 // Create 10 provided machines for testing.
113 for i := 0; i < 10; i++ {
114 res := reservations[i]
115 dev, _ := f.CreateDevice(ctx, &packngo.DeviceCreateRequest{
116 Hostname: fmt.Sprintf("test-%d", i),
117 OS: "fake",
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200118 ProjectID: f.pid,
Serge Bazanskicaa12082023-02-16 14:54:04 +0100119 HardwareReservationID: res.ID,
120 ProjectSSHKeys: []string{kid},
121 })
Tim Windelschmidt0996ea82025-01-09 20:57:23 +0100122 f.mu.Lock()
Serge Bazanskicaa12082023-02-16 14:54:04 +0100123 f.devices[dev.ID].Network = []*packngo.IPAddressAssignment{
124 {
125 IpAddressCommon: packngo.IpAddressCommon{
126 ID: "fake",
127 Address: "1.2.3.4",
128 Management: true,
129 AddressFamily: 4,
130 Public: true,
131 },
132 },
133 }
Tim Windelschmidt0996ea82025-01-09 20:57:23 +0100134 f.mu.Unlock()
Serge Bazanskicaa12082023-02-16 14:54:04 +0100135 err = sess.Transact(ctx, func(q *model.Queries) error {
136 machine, err := q.NewMachine(ctx)
137 if err != nil {
138 return err
139 }
140 return q.MachineAddProvided(ctx, model.MachineAddProvidedParams{
141 MachineID: machine.MachineID,
142 Provider: model.ProviderEquinix,
143 ProviderID: dev.ID,
144 })
145 })
146 if err != nil {
147 t.Fatalf("Failed to create BMDB machine: %v", err)
148 }
149 }
150
Serge Bazanskicaa12082023-02-16 14:54:04 +0100151 // Expect to find 0 machines needing start.
152 for {
153 time.Sleep(100 * time.Millisecond)
154
155 var machines []model.MachineProvided
156 err = sess.Transact(ctx, func(q *model.Queries) error {
157 var err error
Tim Windelschmidt0e749612023-08-07 17:42:59 +0000158 machines, err = q.GetMachinesForAgentStart(ctx, model.GetMachinesForAgentStartParams{
159 Limit: 100,
160 Provider: model.ProviderEquinix,
161 })
Serge Bazanskicaa12082023-02-16 14:54:04 +0100162 return err
163 })
164 if err != nil {
165 t.Fatalf("Failed to run Transaction: %v", err)
166 }
167 if len(machines) == 0 {
168 break
169 }
170 }
171}