226 lines
5.7 KiB
Go
226 lines
5.7 KiB
Go
package packngo
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
const portBasePath = "/ports"
|
|
|
|
type NetworkType int
|
|
|
|
const (
|
|
NetworkL3 NetworkType = iota
|
|
NetworkHybrid
|
|
NetworkL2Bonded
|
|
NetworkL2Individual
|
|
NetworkUnknown
|
|
)
|
|
|
|
// DevicePortService handles operations on a port which belongs to a particular device
|
|
type DevicePortService interface {
|
|
Assign(*PortAssignRequest) (*Port, *Response, error)
|
|
Unassign(*PortAssignRequest) (*Port, *Response, error)
|
|
Bond(*BondRequest) (*Port, *Response, error)
|
|
Disbond(*DisbondRequest) (*Port, *Response, error)
|
|
PortToLayerTwo(string) (*Port, *Response, error)
|
|
PortToLayerThree(string) (*Port, *Response, error)
|
|
DeviceToLayerTwo(string) (*Device, error)
|
|
DeviceToLayerThree(string) (*Device, error)
|
|
DeviceNetworkType(string) (NetworkType, error)
|
|
GetBondPort(string) (*Port, error)
|
|
GetPortByName(string, string) (*Port, error)
|
|
}
|
|
|
|
type PortData struct {
|
|
MAC string `json:"mac"`
|
|
Bonded bool `json:"bonded"`
|
|
}
|
|
|
|
type Port struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
Data PortData `json:"data"`
|
|
AttachedVirtualNetworks []VirtualNetwork `json:"virtual_networks"`
|
|
}
|
|
|
|
type AddressRequest struct {
|
|
AddressFamily int `json:"address_family"`
|
|
Public bool `json:"public"`
|
|
}
|
|
|
|
type BackToL3Request struct {
|
|
RequestIPs []AddressRequest `json:"request_ips"`
|
|
}
|
|
|
|
type DevicePortServiceOp struct {
|
|
client *Client
|
|
}
|
|
|
|
type PortAssignRequest struct {
|
|
PortID string `json:"id"`
|
|
VirtualNetworkID string `json:"vnid"`
|
|
}
|
|
|
|
type BondRequest struct {
|
|
PortID string `json:"id"`
|
|
BulkEnable bool `json:"bulk_enable"`
|
|
}
|
|
|
|
type DisbondRequest struct {
|
|
PortID string `json:"id"`
|
|
BulkDisable bool `json:"bulk_disable"`
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) GetBondPort(deviceID string) (*Port, error) {
|
|
device, _, err := i.client.Devices.Get(deviceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, port := range device.NetworkPorts {
|
|
if port.Type == "NetworkBondPort" {
|
|
return &port, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("No bonded port found in device %s", deviceID)
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) GetPortByName(deviceID, name string) (*Port, error) {
|
|
device, _, err := i.client.Devices.Get(deviceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, port := range device.NetworkPorts {
|
|
if port.Name == name {
|
|
return &port, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("Port %s not found in device %s", name, deviceID)
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) Assign(par *PortAssignRequest) (*Port, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s/assign", portBasePath, par.PortID)
|
|
return i.portAction(path, par)
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) Unassign(par *PortAssignRequest) (*Port, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s/unassign", portBasePath, par.PortID)
|
|
return i.portAction(path, par)
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) Bond(br *BondRequest) (*Port, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s/bond", portBasePath, br.PortID)
|
|
return i.portAction(path, br)
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) Disbond(dr *DisbondRequest) (*Port, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s/disbond", portBasePath, dr.PortID)
|
|
return i.portAction(path, dr)
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) portAction(path string, req interface{}) (*Port, *Response, error) {
|
|
port := new(Port)
|
|
|
|
resp, err := i.client.DoRequest("POST", path, req, port)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return port, resp, err
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) PortToLayerTwo(portID string) (*Port, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s/convert/layer-2", portBasePath, portID)
|
|
port := new(Port)
|
|
|
|
resp, err := i.client.DoRequest("POST", path, nil, port)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return port, resp, err
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) PortToLayerThree(portID string) (*Port, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s/convert/layer-3", portBasePath, portID)
|
|
port := new(Port)
|
|
|
|
req := BackToL3Request{
|
|
RequestIPs: []AddressRequest{
|
|
AddressRequest{AddressFamily: 4, Public: true},
|
|
AddressRequest{AddressFamily: 4, Public: false},
|
|
AddressRequest{AddressFamily: 6, Public: true},
|
|
},
|
|
}
|
|
|
|
resp, err := i.client.DoRequest("POST", path, &req, port)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return port, resp, err
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) DeviceNetworkType(deviceID string) (NetworkType, error) {
|
|
d, _, err := i.client.Devices.Get(deviceID)
|
|
if err != nil {
|
|
return NetworkUnknown, err
|
|
}
|
|
if d.Plan.Slug == "baremetal_0" || d.Plan.Slug == "baremetal_1" {
|
|
return NetworkL3, nil
|
|
}
|
|
if d.Plan.Slug == "baremetal_1e" {
|
|
return NetworkHybrid, nil
|
|
}
|
|
if len(d.NetworkPorts) < 1 {
|
|
// really?
|
|
return NetworkL2Individual, nil
|
|
}
|
|
if d.NetworkPorts[0].Data.Bonded {
|
|
if d.NetworkPorts[2].Data.Bonded {
|
|
for _, ip := range d.Network {
|
|
if ip.Management {
|
|
return NetworkL3, nil
|
|
}
|
|
}
|
|
return NetworkL2Bonded, nil
|
|
} else {
|
|
return NetworkHybrid, nil
|
|
}
|
|
}
|
|
return NetworkL2Individual, nil
|
|
}
|
|
|
|
func (i *DevicePortServiceOp) DeviceToLayerThree(deviceID string) (*Device, error) {
|
|
// hopefull all the VLANs are unassigned at this point
|
|
bond0, err := i.client.DevicePorts.GetBondPort(deviceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bond0, _, err = i.client.DevicePorts.PortToLayerThree(bond0.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
d, _, err := i.client.Devices.Get(deviceID)
|
|
return d, err
|
|
}
|
|
|
|
// DeviceToLayerTwo converts device to L2 networking. Use bond0 to attach VLAN.
|
|
func (i *DevicePortServiceOp) DeviceToLayerTwo(deviceID string) (*Device, error) {
|
|
bond0, err := i.client.DevicePorts.GetBondPort(deviceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bond0, _, err = i.client.DevicePorts.PortToLayerTwo(bond0.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
d, _, err := i.client.Devices.Get(deviceID)
|
|
return d, err
|
|
|
|
}
|