blob: 587b70a430c9f878e67818c0a85732bf07c07491 [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +02004package main
Serge Bazanskicaa12082023-02-16 14:54:04 +01005
6import (
7 "context"
8 "crypto/ed25519"
9 "crypto/rand"
10 "fmt"
11 "testing"
12 "time"
13
14 "github.com/packethost/packngo"
Serge Bazanskicaa12082023-02-16 14:54:04 +010015 "golang.org/x/time/rate"
Tim Windelschmidt0e749612023-08-07 17:42:59 +000016
Serge Bazanskicaa12082023-02-16 14:54:04 +010017 "source.monogon.dev/cloud/bmaas/bmdb"
18 "source.monogon.dev/cloud/bmaas/bmdb/model"
19 "source.monogon.dev/cloud/lib/component"
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020020 "source.monogon.dev/cloud/shepherd/manager"
Serge Bazanskicaa12082023-02-16 14:54:04 +010021)
22
Serge Bazanski86a714d2023-04-17 15:54:21 +020023type initializerDut struct {
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020024 f *fakequinix
25 i *manager.Initializer
26 bmdb *bmdb.Connection
27 ctx context.Context
28 provider *equinixProvider
Serge Bazanski86a714d2023-04-17 15:54:21 +020029}
30
31func newInitializerDut(t *testing.T) *initializerDut {
32 t.Helper()
33
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020034 sc := providerConfig{
Serge Bazanskicaa12082023-02-16 14:54:04 +010035 ProjectId: "noproject",
36 KeyLabel: "somekey",
Serge Bazanskicaa12082023-02-16 14:54:04 +010037 DevicePrefix: "test-",
38 }
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020039 _, key, _ := ed25519.GenerateKey(rand.Reader)
40 k := manager.SSHKey{
41 Key: key,
42 }
43
44 f := newFakequinix(sc.ProjectId, 100)
45 provider, err := sc.New(&k, f)
46 if err != nil {
47 t.Fatalf("Could not create Provider: %v", err)
48 }
49
50 ic := manager.InitializerConfig{
51 ControlLoopConfig: manager.ControlLoopConfig{
Serge Bazanski86a714d2023-04-17 15:54:21 +020052 DBQueryLimiter: rate.NewLimiter(rate.Every(time.Second), 10),
53 },
Serge Bazanskicaa12082023-02-16 14:54:04 +010054 Executable: []byte("beep boop i'm a real program"),
55 TargetPath: "/fake/path",
56 Endpoint: "example.com:1234",
57 SSHConnectTimeout: time.Second,
58 SSHExecTimeout: time.Second,
59 }
Serge Bazanski86a714d2023-04-17 15:54:21 +020060
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020061 i, err := manager.NewInitializer(provider, &manager.FakeSSHClient{}, ic)
Serge Bazanskicaa12082023-02-16 14:54:04 +010062 if err != nil {
63 t.Fatalf("Could not create Initializer: %v", err)
64 }
65
Serge Bazanskicaa12082023-02-16 14:54:04 +010066 b := bmdb.BMDB{
67 Config: bmdb.Config{
68 Database: component.CockroachConfig{
69 InMemory: true,
70 },
71 ComponentName: "test",
72 RuntimeInfo: "test",
73 },
74 }
75 conn, err := b.Open(true)
76 if err != nil {
77 t.Fatalf("Could not create in-memory BMDB: %v", err)
78 }
79
Serge Bazanski86a714d2023-04-17 15:54:21 +020080 ctx, ctxC := context.WithCancel(context.Background())
81 t.Cleanup(ctxC)
82
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020083 if err := provider.SSHEquinixEnsure(ctx); err != nil {
Serge Bazanskicaa12082023-02-16 14:54:04 +010084 t.Fatalf("Failed to ensure SSH key: %v", err)
85 }
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020086 go manager.RunControlLoop(ctx, conn, i)
Serge Bazanski86a714d2023-04-17 15:54:21 +020087
88 return &initializerDut{
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020089 f: f,
90 i: i,
91 bmdb: conn,
92 ctx: ctx,
93 provider: provider,
Serge Bazanski86a714d2023-04-17 15:54:21 +020094 }
95}
96
97// TestInitializerSmokes makes sure the Initializer doesn't go up in flames on
98// the happy path.
99func TestInitializerSmokes(t *testing.T) {
100 dut := newInitializerDut(t)
101 f := dut.f
102 ctx := dut.ctx
103 conn := dut.bmdb
Serge Bazanskicaa12082023-02-16 14:54:04 +0100104
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200105 reservations, _ := f.ListReservations(ctx, f.pid)
106 kid, err := dut.provider.sshEquinixId(ctx)
Serge Bazanskicaa12082023-02-16 14:54:04 +0100107 if err != nil {
108 t.Fatalf("Failed to retrieve equinix key ID: %v", err)
109 }
110 sess, err := conn.StartSession(ctx)
111 if err != nil {
112 t.Fatalf("Failed to create BMDB session for verifiaction: %v", err)
113 }
114
115 // Create 10 provided machines for testing.
116 for i := 0; i < 10; i++ {
117 res := reservations[i]
118 dev, _ := f.CreateDevice(ctx, &packngo.DeviceCreateRequest{
119 Hostname: fmt.Sprintf("test-%d", i),
120 OS: "fake",
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200121 ProjectID: f.pid,
Serge Bazanskicaa12082023-02-16 14:54:04 +0100122 HardwareReservationID: res.ID,
123 ProjectSSHKeys: []string{kid},
124 })
Tim Windelschmidt0996ea82025-01-09 20:57:23 +0100125 f.mu.Lock()
Serge Bazanskicaa12082023-02-16 14:54:04 +0100126 f.devices[dev.ID].Network = []*packngo.IPAddressAssignment{
127 {
128 IpAddressCommon: packngo.IpAddressCommon{
129 ID: "fake",
130 Address: "1.2.3.4",
131 Management: true,
132 AddressFamily: 4,
133 Public: true,
134 },
135 },
136 }
Tim Windelschmidt0996ea82025-01-09 20:57:23 +0100137 f.mu.Unlock()
Serge Bazanskicaa12082023-02-16 14:54:04 +0100138 err = sess.Transact(ctx, func(q *model.Queries) error {
139 machine, err := q.NewMachine(ctx)
140 if err != nil {
141 return err
142 }
143 return q.MachineAddProvided(ctx, model.MachineAddProvidedParams{
144 MachineID: machine.MachineID,
145 Provider: model.ProviderEquinix,
146 ProviderID: dev.ID,
147 })
148 })
149 if err != nil {
150 t.Fatalf("Failed to create BMDB machine: %v", err)
151 }
152 }
153
Serge Bazanskicaa12082023-02-16 14:54:04 +0100154 // Expect to find 0 machines needing start.
155 for {
156 time.Sleep(100 * time.Millisecond)
157
158 var machines []model.MachineProvided
159 err = sess.Transact(ctx, func(q *model.Queries) error {
160 var err error
Tim Windelschmidt0e749612023-08-07 17:42:59 +0000161 machines, err = q.GetMachinesForAgentStart(ctx, model.GetMachinesForAgentStartParams{
162 Limit: 100,
163 Provider: model.ProviderEquinix,
164 })
Serge Bazanskicaa12082023-02-16 14:54:04 +0100165 return err
166 })
167 if err != nil {
168 t.Fatalf("Failed to run Transaction: %v", err)
169 }
170 if len(machines) == 0 {
171 break
172 }
173 }
174}