open-vault/vendor/github.com/packethost/packngo/ports.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
}