blob: aa0b2349912b44ea49f49f121e7bb1f1c8bd1d86 [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"
Tim Windelschmidt72a903f2023-06-27 15:49:36 +02008 "fmt"
Serge Bazanskicaa12082023-02-16 14:54:04 +01009 "net/http"
10 "sync"
11
12 "github.com/google/uuid"
13 "github.com/packethost/packngo"
14)
15
16// fakequinix implements a wrapngo.Client for testing. It starts out with a
17// number of made up hardware reservations, and allows for creating devices and
18// SSH keys.
19type fakequinix struct {
20 mu sync.Mutex
21
22 pid string
23 devices map[string]*packngo.Device
24 reservations map[string]*packngo.HardwareReservation
25 sshKeys map[string]*packngo.SSHKey
Serge Bazanskiae004682023-04-18 13:28:48 +020026 reboots map[string]int
Serge Bazanskicaa12082023-02-16 14:54:04 +010027}
28
Tim Windelschmidtde12c7e2024-04-25 18:00:40 +020029func (f *fakequinix) ListOrganizationReservations(ctx context.Context, oid string) ([]packngo.HardwareReservation, error) {
30 return nil, fmt.Errorf("not implemented")
31}
32
Serge Bazanskicaa12082023-02-16 14:54:04 +010033// newFakequinix makes a fakequinix with a given fake project ID and number of
34// hardware reservations to create.
35func newFakequinix(pid string, numReservations int) *fakequinix {
36 f := fakequinix{
37 pid: pid,
38 devices: make(map[string]*packngo.Device),
39 reservations: make(map[string]*packngo.HardwareReservation),
40 sshKeys: make(map[string]*packngo.SSHKey),
Serge Bazanskiae004682023-04-18 13:28:48 +020041 reboots: make(map[string]int),
Serge Bazanskicaa12082023-02-16 14:54:04 +010042 }
43
44 for i := 0; i < numReservations; i++ {
45 uid := uuid.New()
46 f.reservations[uid.String()] = &packngo.HardwareReservation{
47 ID: uid.String(),
48 ShortID: uid.String(),
49 Provisionable: true,
50 }
51 }
52
53 return &f
54}
55
56func (f *fakequinix) notFound() error {
57 return &packngo.ErrorResponse{
58 Response: &http.Response{
59 StatusCode: http.StatusNotFound,
60 },
61 }
62}
63
Serge Bazanski4969fd72023-04-19 17:43:12 +020064func (f *fakequinix) GetDevice(_ context.Context, pid, did string, _ *packngo.ListOptions) (*packngo.Device, error) {
Serge Bazanskicaa12082023-02-16 14:54:04 +010065 f.mu.Lock()
66 defer f.mu.Unlock()
67
Serge Bazanskicaa12082023-02-16 14:54:04 +010068 val := f.devices[did]
69 if val == nil {
70 return nil, f.notFound()
71 }
72 return val, nil
73}
74
75func (f *fakequinix) ListDevices(_ context.Context, pid string) ([]packngo.Device, error) {
76 f.mu.Lock()
77 defer f.mu.Unlock()
78
79 if pid != f.pid {
80 return nil, nil
81 }
82 var res []packngo.Device
83 for _, dev := range f.devices {
84 res = append(res, *dev)
85 }
86 return res, nil
87}
88
Tim Windelschmidt72a903f2023-06-27 15:49:36 +020089func (f *fakequinix) UpdateDevice(ctx context.Context, id string, r *packngo.DeviceUpdateRequest) (*packngo.Device, error) {
90 return nil, fmt.Errorf("not implemented")
91}
92
Tim Windelschmidt8180de92023-05-11 19:45:37 +020093// MoveReservation is not implemented in fakequinix
94func (f *fakequinix) MoveReservation(_ context.Context, hardwareReservationDID, projectID string) (*packngo.HardwareReservation, error) {
95 return nil, &packngo.ErrorResponse{
96 Response: &http.Response{
97 StatusCode: http.StatusNotImplemented,
98 },
99 }
100}
101
102func (f *fakequinix) DeleteDevice(_ context.Context, id string) error {
103 f.mu.Lock()
104 defer f.mu.Unlock()
105
106 if _, ok := f.devices[id]; !ok {
107 return f.notFound()
108 }
109
110 delete(f.devices, id)
111
112 return nil
113}
114
Serge Bazanskicaa12082023-02-16 14:54:04 +0100115func (f *fakequinix) CreateDevice(_ context.Context, request *packngo.DeviceCreateRequest) (*packngo.Device, error) {
116 f.mu.Lock()
117 defer f.mu.Unlock()
118
119 rid := request.HardwareReservationID
120 res := f.reservations[rid]
121 if res == nil {
122 return nil, f.notFound()
123 }
124 if res.Device != nil {
125 return nil, f.notFound()
126 }
127
128 dev := &packngo.Device{
Serge Bazanskiafd3cf82023-04-19 17:43:46 +0200129 ID: uuid.New().String(),
130 State: "active",
131 HardwareReservation: &packngo.HardwareReservation{
132 ID: rid,
133 },
134 Network: []*packngo.IPAddressAssignment{
135 {
136 IpAddressCommon: packngo.IpAddressCommon{
137 Public: true,
138 Address: "1.2.3.4",
139 },
140 },
141 },
142 Facility: &packngo.Facility{
143 Code: "wad",
144 },
Serge Bazanskicaa12082023-02-16 14:54:04 +0100145 Hostname: request.Hostname,
146 OS: &packngo.OS{
147 Name: request.OS,
148 Slug: request.OS,
149 },
150 }
151 res.Device = dev
152 res.Provisionable = false
153
154 f.devices[dev.ID] = dev
155 return dev, nil
156}
157
158func (f *fakequinix) ListReservations(_ context.Context, pid string) ([]packngo.HardwareReservation, error) {
159 f.mu.Lock()
160 defer f.mu.Unlock()
161
162 var res []packngo.HardwareReservation
163 for _, r := range f.reservations {
164 res = append(res, *r)
165 }
166
167 return res, nil
168}
169
170func (f *fakequinix) ListSSHKeys(_ context.Context) ([]packngo.SSHKey, error) {
171 f.mu.Lock()
172 defer f.mu.Unlock()
173
174 var res []packngo.SSHKey
175 for _, key := range f.sshKeys {
176 res = append(res, *key)
177 }
178
179 return res, nil
180}
181
182func (f *fakequinix) CreateSSHKey(_ context.Context, req *packngo.SSHKeyCreateRequest) (*packngo.SSHKey, error) {
183 f.mu.Lock()
184 defer f.mu.Unlock()
185
186 for _, k := range f.sshKeys {
187 if k.Key == req.Key {
188 return nil, f.notFound()
189 }
190 if k.Label == req.Label {
191 return nil, f.notFound()
192 }
193 }
194
195 uid := uuid.New().String()
196 f.sshKeys[uid] = &packngo.SSHKey{
197 ID: uid,
198 Label: req.Label,
199 Key: req.Key,
200 }
201
202 return f.sshKeys[uid], nil
203}
204
205func (f *fakequinix) UpdateSSHKey(_ context.Context, kid string, req *packngo.SSHKeyUpdateRequest) (*packngo.SSHKey, error) {
206 f.mu.Lock()
207 defer f.mu.Unlock()
208
209 key := f.sshKeys[kid]
210 if key == nil {
211 return nil, f.notFound()
212 }
213 key.Key = *req.Key
214
215 return key, nil
216}
217
Serge Bazanskiae004682023-04-18 13:28:48 +0200218func (f *fakequinix) RebootDevice(_ context.Context, did string) error {
219 f.mu.Lock()
220 defer f.mu.Unlock()
221
222 f.reboots[did]++
223
224 return nil
225}
226
Serge Bazanskicaa12082023-02-16 14:54:04 +0100227func (f *fakequinix) Close() {
228}