blob: 1ee55c4e27dbf9c71e31cab401c41a2f410d2bf1 [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
5
6import (
7 "context"
8 "database/sql"
9 "fmt"
10 "net/netip"
11
12 "k8s.io/klog/v2"
13
14 "source.monogon.dev/cloud/bmaas/bmdb"
15 "source.monogon.dev/cloud/bmaas/bmdb/model"
16 "source.monogon.dev/cloud/shepherd"
17)
18
19// provider represents a shepherd.Provider that works entirely on a
20// static device list. It requires a provider type and a device list.
21type provider struct {
22 providerType model.Provider
23 machines map[shepherd.ProviderID]machine
24}
25
26type machine struct {
27 ProviderID shepherd.ProviderID `json:"ID"`
28 Address netip.Addr `json:"Addr"`
29 Location string `json:"Location"`
30}
31
Tim Windelschmidtfdd87ab2023-12-07 18:03:21 +010032func (d machine) Failed() bool {
33 return false
34}
35
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020036func (d machine) ID() shepherd.ProviderID {
37 return d.ProviderID
38}
39
40func (d machine) Addr() netip.Addr {
41 return d.Address
42}
43
Tim Windelschmidtc4dd0032024-02-19 13:13:31 +010044func (d machine) Availability() shepherd.Availability {
45 return shepherd.AvailabilityPossiblyUsed
Tim Windelschmidtb6308cd2023-10-10 21:19:03 +020046}
47
48func (p *provider) ListMachines(ctx context.Context) ([]shepherd.Machine, error) {
49 machines := make([]shepherd.Machine, 0, len(p.machines))
50 for _, m := range p.machines {
51 machines = append(machines, m)
52 }
53
54 return machines, nil
55}
56
57func (p *provider) GetMachine(ctx context.Context, id shepherd.ProviderID) (shepherd.Machine, error) {
58 // If the provided machine is not inside our known machines,
59 // bail-out early as this is unsupported.
60 if _, ok := p.machines[id]; !ok {
61 return nil, fmt.Errorf("unknown provided machine requested")
62 }
63
64 return p.machines[id], nil
65}
66
67func (p *provider) CreateMachine(ctx context.Context, session *bmdb.Session, request shepherd.CreateMachineRequest) (shepherd.Machine, error) {
68 if request.UnusedMachine == nil {
69 return nil, fmt.Errorf("parameter UnusedMachine is missing")
70 }
71
72 //TODO: Do we just trust the implementation to be correct?
73 m, ok := request.UnusedMachine.(machine)
74 if !ok {
75 return nil, fmt.Errorf("invalid type for parameter UnusedMachine")
76 }
77
78 if err := p.assimilate(ctx, session, m); err != nil {
79 klog.Errorf("Failed to provision machine %s: %v", m.ProviderID, err)
80 return nil, err
81 }
82
83 return m, nil
84}
85
86func (p *provider) assimilate(ctx context.Context, sess *bmdb.Session, machine machine) error {
87 return sess.Transact(ctx, func(q *model.Queries) error {
88 // Create a new machine record within BMDB.
89 m, err := q.NewMachine(ctx)
90 if err != nil {
91 return fmt.Errorf("while creating a new machine record in BMDB: %w", err)
92 }
93
94 // Link the new machine with the device, and tag it "provided".
95 addParams := model.MachineAddProvidedParams{
96 MachineID: m.MachineID,
97 ProviderID: string(machine.ProviderID),
98 Provider: p.providerType,
99 }
100 klog.Infof("Setting \"provided\" tag (ID: %s, PID: %s, Provider: %s).", addParams.MachineID, addParams.ProviderID, addParams.Provider)
101 if err := q.MachineAddProvided(ctx, addParams); err != nil {
102 return fmt.Errorf("while tagging machine active: %w", err)
103 }
104
105 upParams := model.MachineUpdateProviderStatusParams{
106 ProviderID: string(machine.ProviderID),
107 Provider: p.providerType,
108 ProviderIpAddress: sql.NullString{
109 String: machine.Address.String(),
110 Valid: true,
111 },
112 ProviderLocation: sql.NullString{
113 String: machine.Location,
114 Valid: machine.Location != "",
115 },
116 ProviderStatus: model.NullProviderStatus{
117 ProviderStatus: model.ProviderStatusUnknown,
118 Valid: true,
119 },
120 }
121
122 klog.Infof("Setting \"provided\" tag status parameter (ID: %s, PID: %s, Provider: %s).", addParams.MachineID, upParams.ProviderID, upParams.Provider)
123 if err := q.MachineUpdateProviderStatus(ctx, upParams); err != nil {
124 return fmt.Errorf("while setting machine params: %w", err)
125 }
126
127 return nil
128 })
129}
130
131func (p *provider) Type() model.Provider {
132 return p.providerType
133}