blob: 3100ad2f404a2819d10fa61310bba8fb1e74209d [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 })
122 f.devices[dev.ID].Network = []*packngo.IPAddressAssignment{
123 {
124 IpAddressCommon: packngo.IpAddressCommon{
125 ID: "fake",
126 Address: "1.2.3.4",
127 Management: true,
128 AddressFamily: 4,
129 Public: true,
130 },
131 },
132 }
133 err = sess.Transact(ctx, func(q *model.Queries) error {
134 machine, err := q.NewMachine(ctx)
135 if err != nil {
136 return err
137 }
138 return q.MachineAddProvided(ctx, model.MachineAddProvidedParams{
139 MachineID: machine.MachineID,
140 Provider: model.ProviderEquinix,
141 ProviderID: dev.ID,
142 })
143 })
144 if err != nil {
145 t.Fatalf("Failed to create BMDB machine: %v", err)
146 }
147 }
148
Serge Bazanskicaa12082023-02-16 14:54:04 +0100149 // Expect to find 0 machines needing start.
150 for {
151 time.Sleep(100 * time.Millisecond)
152
153 var machines []model.MachineProvided
154 err = sess.Transact(ctx, func(q *model.Queries) error {
155 var err error
Tim Windelschmidt0e749612023-08-07 17:42:59 +0000156 machines, err = q.GetMachinesForAgentStart(ctx, model.GetMachinesForAgentStartParams{
157 Limit: 100,
158 Provider: model.ProviderEquinix,
159 })
Serge Bazanskicaa12082023-02-16 14:54:04 +0100160 return err
161 })
162 if err != nil {
163 t.Fatalf("Failed to run Transaction: %v", err)
164 }
165 if len(machines) == 0 {
166 break
167 }
168 }
169}