blob: 2dc3fa94296f37f67e4772e8b0ac5c2ce40ceecb [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 manager
5
6import (
7 "context"
8 "fmt"
9 "net/netip"
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +010010 "sync"
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020011
12 "github.com/google/uuid"
Jan Schär0175d7a2025-03-26 12:57:23 +000013 "golang.org/x/crypto/ssh"
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020014 "k8s.io/klog/v2"
15
16 "source.monogon.dev/cloud/bmaas/bmdb"
17 "source.monogon.dev/cloud/bmaas/bmdb/model"
18 "source.monogon.dev/cloud/shepherd"
19)
20
21type dummyMachine struct {
22 id shepherd.ProviderID
23 addr netip.Addr
Tim Windelschmidtc4dd0032024-02-19 13:13:31 +010024 availability shepherd.Availability
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020025 agentStarted bool
26}
27
Tim Windelschmidtfdd87ab2023-12-07 18:03:21 +010028func (dm *dummyMachine) Failed() bool {
29 return false
30}
31
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020032func (dm *dummyMachine) ID() shepherd.ProviderID {
33 return dm.id
34}
35
36func (dm *dummyMachine) Addr() netip.Addr {
37 return dm.addr
38}
39
Tim Windelschmidtc4dd0032024-02-19 13:13:31 +010040func (dm *dummyMachine) Availability() shepherd.Availability {
41 return dm.availability
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020042}
43
44type dummySSHClient struct {
Jan Schär0175d7a2025-03-26 12:57:23 +000045 SSHClient
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020046 m *dummyMachine
47}
48
Jan Schär0175d7a2025-03-26 12:57:23 +000049func (dsc *dummySSHClient) Execute(ctx context.Context, command string, stdin []byte) ([]byte, []byte, error) {
50 stdout, stderr, err := dsc.SSHClient.Execute(ctx, command, stdin)
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020051 if err != nil {
52 return nil, nil, err
53 }
54
55 dsc.m.agentStarted = true
56 return stdout, stderr, nil
57}
58
Jan Schär0175d7a2025-03-26 12:57:23 +000059func (dp *dummyProvider) FakeSSHDial(ctx context.Context, address string, config *ssh.ClientConfig) (SSHClient, error) {
60 conn, err := FakeSSHDial(ctx, address, config)
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020061 if err != nil {
62 return nil, err
63 }
64
65 addrPort := netip.MustParseAddrPort(address)
66 uid, err := uuid.FromBytes(addrPort.Addr().AsSlice())
67 if err != nil {
68 return nil, err
69 }
70
Jan Schär0175d7a2025-03-26 12:57:23 +000071 dp.muMachines.RLock()
72 m := dp.machines[shepherd.ProviderID(uid.String())]
73 dp.muMachines.RUnlock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020074 if m == nil {
75 return nil, fmt.Errorf("failed finding machine in map")
76 }
77
Jan Schär0175d7a2025-03-26 12:57:23 +000078 return &dummySSHClient{conn, m}, nil
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020079}
80
81func newDummyProvider(cap int) *dummyProvider {
82 return &dummyProvider{
83 capacity: cap,
84 machines: make(map[shepherd.ProviderID]*dummyMachine),
85 }
86}
87
88type dummyProvider struct {
Tim Windelschmidt99e15112025-02-05 17:38:16 +010089 capacity int
90 machines map[shepherd.ProviderID]*dummyMachine
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +010091 muMachines sync.RWMutex
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020092}
93
94func (dp *dummyProvider) createDummyMachines(ctx context.Context, session *bmdb.Session, count int) ([]shepherd.Machine, error) {
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +010095 dp.muMachines.RLock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020096 if len(dp.machines)+count > dp.capacity {
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +010097 dp.muMachines.RUnlock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020098 return nil, fmt.Errorf("no capacity left")
99 }
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +0100100 dp.muMachines.RUnlock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200101
102 var machines []shepherd.Machine
103 for i := 0; i < count; i++ {
104 uid := uuid.Must(uuid.NewRandom())
105 m, err := dp.CreateMachine(ctx, session, shepherd.CreateMachineRequest{
106 UnusedMachine: &dummyMachine{
Tim Windelschmidtc4dd0032024-02-19 13:13:31 +0100107 id: shepherd.ProviderID(uid.String()),
108 availability: shepherd.AvailabilityKnownUsed,
109 addr: netip.AddrFrom16(uid),
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200110 },
111 })
112 if err != nil {
113 return nil, err
114 }
115 machines = append(machines, m)
116 }
117
118 return machines, nil
119}
120
121func (dp *dummyProvider) ListMachines(ctx context.Context) ([]shepherd.Machine, error) {
122 var machines []shepherd.Machine
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +0100123 dp.muMachines.RLock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200124 for _, m := range dp.machines {
125 machines = append(machines, m)
126 }
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +0100127 dp.muMachines.RUnlock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200128
129 unusedMachineCount := dp.capacity - len(machines)
130 for i := 0; i < unusedMachineCount; i++ {
131 uid := uuid.Must(uuid.NewRandom())
132 machines = append(machines, &dummyMachine{
Tim Windelschmidtc4dd0032024-02-19 13:13:31 +0100133 id: shepherd.ProviderID(uid.String()),
134 availability: shepherd.AvailabilityKnownUnused,
135 addr: netip.AddrFrom16(uid),
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200136 })
137 }
138
139 return machines, nil
140}
141
142func (dp *dummyProvider) GetMachine(ctx context.Context, id shepherd.ProviderID) (shepherd.Machine, error) {
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +0100143 dp.muMachines.RLock()
144 defer dp.muMachines.RUnlock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200145 for _, m := range dp.machines {
146 if m.ID() == id {
147 return m, nil
148 }
149 }
150
151 return nil, shepherd.ErrMachineNotFound
152}
153
154func (dp *dummyProvider) CreateMachine(ctx context.Context, session *bmdb.Session, request shepherd.CreateMachineRequest) (shepherd.Machine, error) {
155 dm := request.UnusedMachine.(*dummyMachine)
156
157 err := session.Transact(ctx, func(q *model.Queries) error {
158 // Create a new machine record within BMDB.
159 m, err := q.NewMachine(ctx)
160 if err != nil {
161 return fmt.Errorf("while creating a new machine record in BMDB: %w", err)
162 }
163
164 p := model.MachineAddProvidedParams{
165 MachineID: m.MachineID,
166 ProviderID: string(dm.id),
167 Provider: dp.Type(),
168 }
169 klog.Infof("Setting \"provided\" tag (ID: %s, PID: %s, Provider: %s).", p.MachineID, p.ProviderID, p.Provider)
170 if err := q.MachineAddProvided(ctx, p); err != nil {
171 return fmt.Errorf("while tagging machine active: %w", err)
172 }
173 return nil
174 })
175
176 if err != nil {
177 return nil, err
178 }
179
Tim Windelschmidtc4dd0032024-02-19 13:13:31 +0100180 dm.availability = shepherd.AvailabilityKnownUsed
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +0100181 dp.muMachines.Lock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200182 dp.machines[dm.id] = dm
Tim Windelschmidt8eeae7b2024-12-09 22:52:55 +0100183 dp.muMachines.Unlock()
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +0200184
185 return dm, nil
186}
187
188func (dp *dummyProvider) Type() model.Provider {
189 return model.ProviderNone
190}