blob: fc34a10d55b91dcc91cc926f16dbc517b1ccd764 [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"
Jan Schär0175d7a2025-03-26 12:57:23 +000015 "golang.org/x/crypto/ssh"
Serge Bazanskicaa12082023-02-16 14:54:04 +010016 "golang.org/x/time/rate"
Tim Windelschmidt0e749612023-08-07 17:42:59 +000017
Serge Bazanskicaa12082023-02-16 14:54:04 +010018 "source.monogon.dev/cloud/bmaas/bmdb"
19 "source.monogon.dev/cloud/bmaas/bmdb/model"
20 "source.monogon.dev/cloud/lib/component"
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020021 "source.monogon.dev/cloud/shepherd/manager"
Serge Bazanskicaa12082023-02-16 14:54:04 +010022)
23
Serge Bazanski86a714d2023-04-17 15:54:21 +020024type initializerDut struct {
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020025 f *fakequinix
26 i *manager.Initializer
27 bmdb *bmdb.Connection
28 ctx context.Context
29 provider *equinixProvider
Serge Bazanski86a714d2023-04-17 15:54:21 +020030}
31
32func newInitializerDut(t *testing.T) *initializerDut {
33 t.Helper()
34
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020035 sc := providerConfig{
Serge Bazanskicaa12082023-02-16 14:54:04 +010036 ProjectId: "noproject",
37 KeyLabel: "somekey",
Serge Bazanskicaa12082023-02-16 14:54:04 +010038 DevicePrefix: "test-",
39 }
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020040 _, key, _ := ed25519.GenerateKey(rand.Reader)
41 k := manager.SSHKey{
42 Key: key,
43 }
44
45 f := newFakequinix(sc.ProjectId, 100)
46 provider, err := sc.New(&k, f)
47 if err != nil {
48 t.Fatalf("Could not create Provider: %v", err)
49 }
50
51 ic := manager.InitializerConfig{
52 ControlLoopConfig: manager.ControlLoopConfig{
Serge Bazanski86a714d2023-04-17 15:54:21 +020053 DBQueryLimiter: rate.NewLimiter(rate.Every(time.Second), 10),
54 },
Jan Schär0175d7a2025-03-26 12:57:23 +000055 Executable: []byte("beep boop i'm a real program"),
56 TargetPath: "/fake/path",
57 Endpoint: "example.com:1234",
58 SSHConfig: ssh.ClientConfig{
59 Timeout: time.Second,
60 },
61 SSHExecTimeout: time.Second,
62 DialSSH: manager.FakeSSHDial,
Serge Bazanskicaa12082023-02-16 14:54:04 +010063 }
Serge Bazanski86a714d2023-04-17 15:54:21 +020064
Jan Schär0175d7a2025-03-26 12:57:23 +000065 i, err := manager.NewInitializer(provider, ic)
Serge Bazanskicaa12082023-02-16 14:54:04 +010066 if err != nil {
67 t.Fatalf("Could not create Initializer: %v", err)
68 }
69
Serge Bazanskicaa12082023-02-16 14:54:04 +010070 b := bmdb.BMDB{
71 Config: bmdb.Config{
72 Database: component.CockroachConfig{
73 InMemory: true,
74 },
75 ComponentName: "test",
76 RuntimeInfo: "test",
77 },
78 }
79 conn, err := b.Open(true)
80 if err != nil {
81 t.Fatalf("Could not create in-memory BMDB: %v", err)
82 }
83
Serge Bazanski86a714d2023-04-17 15:54:21 +020084 ctx, ctxC := context.WithCancel(context.Background())
85 t.Cleanup(ctxC)
86
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020087 if err := provider.SSHEquinixEnsure(ctx); err != nil {
Serge Bazanskicaa12082023-02-16 14:54:04 +010088 t.Fatalf("Failed to ensure SSH key: %v", err)
89 }
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020090 go manager.RunControlLoop(ctx, conn, i)
Serge Bazanski86a714d2023-04-17 15:54:21 +020091
92 return &initializerDut{
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020093 f: f,
94 i: i,
95 bmdb: conn,
96 ctx: ctx,
97 provider: provider,
Serge Bazanski86a714d2023-04-17 15:54:21 +020098 }
99}
100
101// TestInitializerSmokes makes sure the Initializer doesn't go up in flames on
102// the happy path.
103func TestInitializerSmokes(t *testing.T) {
104 dut := newInitializerDut(t)
105 f := dut.f
106 ctx := dut.ctx
107 conn := dut.bmdb
Serge Bazanskicaa12082023-02-16 14:54:04 +0100108
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200109 reservations, _ := f.ListReservations(ctx, f.pid)
110 kid, err := dut.provider.sshEquinixId(ctx)
Serge Bazanskicaa12082023-02-16 14:54:04 +0100111 if err != nil {
112 t.Fatalf("Failed to retrieve equinix key ID: %v", err)
113 }
114 sess, err := conn.StartSession(ctx)
115 if err != nil {
116 t.Fatalf("Failed to create BMDB session for verifiaction: %v", err)
117 }
118
119 // Create 10 provided machines for testing.
120 for i := 0; i < 10; i++ {
121 res := reservations[i]
122 dev, _ := f.CreateDevice(ctx, &packngo.DeviceCreateRequest{
123 Hostname: fmt.Sprintf("test-%d", i),
124 OS: "fake",
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200125 ProjectID: f.pid,
Serge Bazanskicaa12082023-02-16 14:54:04 +0100126 HardwareReservationID: res.ID,
127 ProjectSSHKeys: []string{kid},
128 })
Tim Windelschmidt0996ea82025-01-09 20:57:23 +0100129 f.mu.Lock()
Serge Bazanskicaa12082023-02-16 14:54:04 +0100130 f.devices[dev.ID].Network = []*packngo.IPAddressAssignment{
131 {
132 IpAddressCommon: packngo.IpAddressCommon{
133 ID: "fake",
134 Address: "1.2.3.4",
135 Management: true,
136 AddressFamily: 4,
137 Public: true,
138 },
139 },
140 }
Tim Windelschmidt0996ea82025-01-09 20:57:23 +0100141 f.mu.Unlock()
Serge Bazanskicaa12082023-02-16 14:54:04 +0100142 err = sess.Transact(ctx, func(q *model.Queries) error {
143 machine, err := q.NewMachine(ctx)
144 if err != nil {
145 return err
146 }
147 return q.MachineAddProvided(ctx, model.MachineAddProvidedParams{
148 MachineID: machine.MachineID,
149 Provider: model.ProviderEquinix,
150 ProviderID: dev.ID,
151 })
152 })
153 if err != nil {
154 t.Fatalf("Failed to create BMDB machine: %v", err)
155 }
156 }
157
Serge Bazanskicaa12082023-02-16 14:54:04 +0100158 // Expect to find 0 machines needing start.
159 for {
160 time.Sleep(100 * time.Millisecond)
161
162 var machines []model.MachineProvided
163 err = sess.Transact(ctx, func(q *model.Queries) error {
164 var err error
Tim Windelschmidt0e749612023-08-07 17:42:59 +0000165 machines, err = q.GetMachinesForAgentStart(ctx, model.GetMachinesForAgentStartParams{
166 Limit: 100,
167 Provider: model.ProviderEquinix,
168 })
Serge Bazanskicaa12082023-02-16 14:54:04 +0100169 return err
170 })
171 if err != nil {
172 t.Fatalf("Failed to run Transaction: %v", err)
173 }
174 if len(machines) == 0 {
175 break
176 }
177 }
178}