forked from equinixmetal-archive/packngo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdevice_ports.go
332 lines (296 loc) · 9.27 KB
/
device_ports.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
package packngo
import (
"fmt"
"strings"
)
const portBasePath = "/ports"
// DevicePortService handles operations on a port which belongs to a particular device
//
// Deprecated: use PortService or Device methods
type DevicePortService interface {
Assign(*PortAssignRequest) (*Port, *Response, error)
Unassign(*PortAssignRequest) (*Port, *Response, error)
AssignNative(*PortAssignRequest) (*Port, *Response, error)
UnassignNative(string) (*Port, *Response, error)
Bond(*Port, bool) (*Port, *Response, error)
Disbond(*Port, bool) (*Port, *Response, error)
DeviceToNetworkType(string, string) (*Device, error)
DeviceNetworkType(string) (string, error)
PortToLayerTwo(string, string) (*Port, *Response, error)
PortToLayerThree(string, string) (*Port, *Response, error)
GetPortByName(string, string) (*Port, error)
GetOddEthPorts(*Device) (map[string]*Port, error)
GetAllEthPorts(*Device) (map[string]*Port, error)
ConvertDevice(*Device, string) error
}
// DevicePortServiceOp implements DevicePortService on the Equinix Metal API
//
// Deprecated: use PortServiceOp or Device methods
type DevicePortServiceOp struct {
client *Client
}
// GetPortByName returns the matching Port on the specified device
//
// Deprecated: use Device.GetPortByName
func (i *DevicePortServiceOp) GetPortByName(deviceID, name string) (*Port, error) {
device, _, err := i.client.Devices.Get(deviceID, nil)
if err != nil {
return nil, err
}
return device.GetPortByName(name)
}
// Assign the specified VLAN to the specified Port
//
// Deprecated: use PortServiceOp.Assign
func (i *DevicePortServiceOp) Assign(par *PortAssignRequest) (*Port, *Response, error) {
return i.client.Ports.Assign(par.PortID, par.VirtualNetworkID)
}
// AssignNative designates the specified VLAN as the native VLAN for the
// specified Port
//
// Deprecated: use PortServiceOp.AssignNative
func (i *DevicePortServiceOp) AssignNative(par *PortAssignRequest) (*Port, *Response, error) {
return i.client.Ports.AssignNative(par.PortID, par.VirtualNetworkID)
}
// UnassignNative removes the native VLAN from the specified Port
//
// Deprecated: use PortServiceOp.UnassignNative
func (i *DevicePortServiceOp) UnassignNative(portID string) (*Port, *Response, error) {
if validateErr := ValidateUUID(portID); validateErr != nil {
return nil, nil, validateErr
}
return i.client.Ports.UnassignNative(portID)
}
// Unassign removes the specified VLAN from the specified Port
//
// Deprecated: use PortServiceOp.Unassign
func (i *DevicePortServiceOp) Unassign(par *PortAssignRequest) (*Port, *Response, error) {
return i.client.Ports.Unassign(par.PortID, par.VirtualNetworkID)
}
// Bond enabled bonding on the specified port
//
// Deprecated: use PortServiceOp.Bond
func (i *DevicePortServiceOp) Bond(p *Port, bulk_enable bool) (*Port, *Response, error) {
if p.Data.Bonded {
return p, nil, nil
}
return i.client.Ports.Bond(p.ID, bulk_enable)
}
// Disbond disables bonding on the specified port
//
// Deprecated: use PortServiceOp.Disbond
func (i *DevicePortServiceOp) Disbond(p *Port, bulk_disable bool) (*Port, *Response, error) {
if !p.Data.Bonded {
return p, nil, nil
}
return i.client.Ports.Disbond(p.ID, bulk_disable)
}
// PortToLayerTwo fetches the specified device, finds the matching port by name,
// and converts it to layer2. A port may already be in a layer2 mode, in which
// case the port will be returned with a nil response and nil error with no
// additional action taking place.
//
// Deprecated: use PortServiceOp.ConvertToLayerTwo
func (i *DevicePortServiceOp) PortToLayerTwo(deviceID, portName string) (*Port, *Response, error) {
p, err := i.GetPortByName(deviceID, portName)
if err != nil {
return nil, nil, err
}
if strings.HasPrefix(p.NetworkType, "layer2") {
return p, nil, nil
}
return i.client.Ports.ConvertToLayerTwo(p.ID)
}
// PortToLayerThree fetches the specified device, finds the matching port by
// name, and converts it to layer3. A port may already be in a layer3 mode, in
// which case the port will be returned with a nil response and nil error with
// no additional action taking place.
//
// When switching to Layer3, a new set of IP addresses will be requested
// including Public IPv4, Public IPv6, and Private IPv6 addresses.
//
// Deprecated: use PortServiceOp.ConvertToLayerTwo
func (i *DevicePortServiceOp) PortToLayerThree(deviceID, portName string) (*Port, *Response, error) {
p, err := i.GetPortByName(deviceID, portName)
if err != nil {
return nil, nil, err
}
if (p.NetworkType == NetworkTypeL3) || (p.NetworkType == NetworkTypeHybrid) {
return p, nil, nil
}
ips := []AddressRequest{
{AddressFamily: 4, Public: true},
{AddressFamily: 4, Public: false},
{AddressFamily: 6, Public: true},
}
return i.client.Ports.ConvertToLayerThree(p.ID, ips)
}
// DeviceNetworkType fetches the specified Device and returns a heuristic single
// word network type consistent with the Equinix Metal console experience.
//
// Deprecated: use Device.GetNetworkType
func (i *DevicePortServiceOp) DeviceNetworkType(deviceID string) (string, error) {
if validateErr := ValidateUUID(deviceID); validateErr != nil {
return "", validateErr
}
d, _, err := i.client.Devices.Get(deviceID, nil)
if err != nil {
return "", err
}
return d.GetNetworkType(), nil
}
// GetAllEthPorts fetches the specified Device and returns a heuristic single
// word network type consistent with the Equinix Metal console experience.
//
// Deprecated: use Device.GetPhysicalPorts
func (i *DevicePortServiceOp) GetAllEthPorts(d *Device) (map[string]*Port, error) {
d, _, err := i.client.Devices.Get(d.ID, nil)
if err != nil {
return nil, err
}
return d.GetPhysicalPorts(), nil
}
// GetOddEthPorts fetches the specified Device and returns physical
// ports eth1 and eth3.
//
// Deprecated: use Device.GetPhysicalPorts and filter the map to only the keys
// ending with odd digits
func (i *DevicePortServiceOp) GetOddEthPorts(d *Device) (map[string]*Port, error) {
d, _, err := i.client.Devices.Get(d.ID, nil)
if err != nil {
return nil, err
}
ret := map[string]*Port{}
eth1, err := d.GetPortByName("eth1")
if err != nil {
return nil, err
}
ret["eth1"] = eth1
eth3, err := d.GetPortByName("eth3")
if err != nil {
return ret, nil
}
ret["eth3"] = eth3
return ret, nil
}
// ConvertDevice converts the specified device's network ports (including
// addresses and vlans) to the named network type, consistent with the Equinix
// Metal console experience.
//
// Deprecated: Equinix Metal devices may support more than two ports and the
// whole-device single word network type can no longer capture the capabilities
// and permutations of device port configurations.
func (i *DevicePortServiceOp) ConvertDevice(d *Device, targetType string) error {
bondPorts := d.GetBondPorts()
if targetType == NetworkTypeL3 {
// TODO: remove vlans from all the ports
for _, p := range bondPorts {
_, _, err := i.Bond(p, false)
if err != nil {
return err
}
}
_, _, err := i.PortToLayerThree(d.ID, "bond0")
if err != nil {
return err
}
allEthPorts, err := i.GetAllEthPorts(d)
if err != nil {
return err
}
for _, p := range allEthPorts {
_, _, err := i.Bond(p, false)
if err != nil {
return err
}
}
}
if targetType == NetworkTypeHybrid {
for _, p := range bondPorts {
_, _, err := i.Bond(p, false)
if err != nil {
return err
}
}
_, _, err := i.PortToLayerThree(d.ID, "bond0")
if err != nil {
return err
}
// ports need to be refreshed before bonding/disbonding
oddEthPorts, err := i.GetOddEthPorts(d)
if err != nil {
return err
}
for _, p := range oddEthPorts {
_, _, err := i.Disbond(p, false)
if err != nil {
return err
}
}
}
if targetType == NetworkTypeL2Individual {
_, _, err := i.PortToLayerTwo(d.ID, "bond0")
if err != nil {
return err
}
for _, p := range bondPorts {
_, _, err = i.Disbond(p, true)
if err != nil {
return err
}
}
}
if targetType == NetworkTypeL2Bonded {
for _, p := range bondPorts {
_, _, err := i.PortToLayerTwo(d.ID, p.Name)
if err != nil {
return err
}
}
allEthPorts, err := i.GetAllEthPorts(d)
if err != nil {
return err
}
for _, p := range allEthPorts {
_, _, err := i.Bond(p, false)
if err != nil {
return err
}
}
}
return nil
}
// DeviceToNetworkType fetches the specified device and converts its network
// ports (including addresses and vlans) to the named network type, consistent
// with the Equinix Metal console experience.
//
// Deprecated: use DevicePortServiceOp.ConvertDevice which this function thinly
// wraps.
func (i *DevicePortServiceOp) DeviceToNetworkType(deviceID string, targetType string) (*Device, error) {
if validateErr := ValidateUUID(deviceID); validateErr != nil {
return nil, validateErr
}
d, _, err := i.client.Devices.Get(deviceID, nil)
if err != nil {
return nil, err
}
curType := d.GetNetworkType()
if curType == targetType {
return nil, fmt.Errorf("Device already is in state %s", targetType)
}
err = i.ConvertDevice(d, targetType)
if err != nil {
return nil, err
}
d, _, err = i.client.Devices.Get(deviceID, nil)
if err != nil {
return nil, err
}
finalType := d.GetNetworkType()
if finalType != targetType {
return nil, fmt.Errorf(
"Failed to convert device %s from %s to %s. New type was %s",
deviceID, curType, targetType, finalType)
}
return d, err
}