1package packngo 2 3import ( 4 "fmt" 5) 6 7const portBasePath = "/ports" 8 9type NetworkType int 10 11const ( 12 NetworkL3 NetworkType = iota 13 NetworkHybrid 14 NetworkL2Bonded 15 NetworkL2Individual 16 NetworkUnknown 17) 18 19// DevicePortService handles operations on a port which belongs to a particular device 20type DevicePortService interface { 21 Assign(*PortAssignRequest) (*Port, *Response, error) 22 Unassign(*PortAssignRequest) (*Port, *Response, error) 23 Bond(*BondRequest) (*Port, *Response, error) 24 Disbond(*DisbondRequest) (*Port, *Response, error) 25 PortToLayerTwo(string) (*Port, *Response, error) 26 PortToLayerThree(string) (*Port, *Response, error) 27 DeviceToLayerTwo(string) (*Device, error) 28 DeviceToLayerThree(string) (*Device, error) 29 DeviceNetworkType(string) (NetworkType, error) 30 GetBondPort(string) (*Port, error) 31 GetPortByName(string, string) (*Port, error) 32} 33 34type PortData struct { 35 MAC string `json:"mac"` 36 Bonded bool `json:"bonded"` 37} 38 39type Port struct { 40 ID string `json:"id"` 41 Type string `json:"type"` 42 Name string `json:"name"` 43 Data PortData `json:"data"` 44 AttachedVirtualNetworks []VirtualNetwork `json:"virtual_networks"` 45} 46 47type AddressRequest struct { 48 AddressFamily int `json:"address_family"` 49 Public bool `json:"public"` 50} 51 52type BackToL3Request struct { 53 RequestIPs []AddressRequest `json:"request_ips"` 54} 55 56type DevicePortServiceOp struct { 57 client *Client 58} 59 60type PortAssignRequest struct { 61 PortID string `json:"id"` 62 VirtualNetworkID string `json:"vnid"` 63} 64 65type BondRequest struct { 66 PortID string `json:"id"` 67 BulkEnable bool `json:"bulk_enable"` 68} 69 70type DisbondRequest struct { 71 PortID string `json:"id"` 72 BulkDisable bool `json:"bulk_disable"` 73} 74 75func (i *DevicePortServiceOp) GetBondPort(deviceID string) (*Port, error) { 76 device, _, err := i.client.Devices.Get(deviceID) 77 if err != nil { 78 return nil, err 79 } 80 for _, port := range device.NetworkPorts { 81 if port.Type == "NetworkBondPort" { 82 return &port, nil 83 } 84 } 85 86 return nil, fmt.Errorf("No bonded port found in device %s", deviceID) 87} 88 89func (i *DevicePortServiceOp) GetPortByName(deviceID, name string) (*Port, error) { 90 device, _, err := i.client.Devices.Get(deviceID) 91 if err != nil { 92 return nil, err 93 } 94 for _, port := range device.NetworkPorts { 95 if port.Name == name { 96 return &port, nil 97 } 98 } 99 100 return nil, fmt.Errorf("Port %s not found in device %s", name, deviceID) 101} 102 103func (i *DevicePortServiceOp) Assign(par *PortAssignRequest) (*Port, *Response, error) { 104 path := fmt.Sprintf("%s/%s/assign", portBasePath, par.PortID) 105 return i.portAction(path, par) 106} 107 108func (i *DevicePortServiceOp) Unassign(par *PortAssignRequest) (*Port, *Response, error) { 109 path := fmt.Sprintf("%s/%s/unassign", portBasePath, par.PortID) 110 return i.portAction(path, par) 111} 112 113func (i *DevicePortServiceOp) Bond(br *BondRequest) (*Port, *Response, error) { 114 path := fmt.Sprintf("%s/%s/bond", portBasePath, br.PortID) 115 return i.portAction(path, br) 116} 117 118func (i *DevicePortServiceOp) Disbond(dr *DisbondRequest) (*Port, *Response, error) { 119 path := fmt.Sprintf("%s/%s/disbond", portBasePath, dr.PortID) 120 return i.portAction(path, dr) 121} 122 123func (i *DevicePortServiceOp) portAction(path string, req interface{}) (*Port, *Response, error) { 124 port := new(Port) 125 126 resp, err := i.client.DoRequest("POST", path, req, port) 127 if err != nil { 128 return nil, resp, err 129 } 130 131 return port, resp, err 132} 133 134func (i *DevicePortServiceOp) PortToLayerTwo(portID string) (*Port, *Response, error) { 135 path := fmt.Sprintf("%s/%s/convert/layer-2", portBasePath, portID) 136 port := new(Port) 137 138 resp, err := i.client.DoRequest("POST", path, nil, port) 139 if err != nil { 140 return nil, resp, err 141 } 142 143 return port, resp, err 144} 145 146func (i *DevicePortServiceOp) PortToLayerThree(portID string) (*Port, *Response, error) { 147 path := fmt.Sprintf("%s/%s/convert/layer-3", portBasePath, portID) 148 port := new(Port) 149 150 req := BackToL3Request{ 151 RequestIPs: []AddressRequest{ 152 AddressRequest{AddressFamily: 4, Public: true}, 153 AddressRequest{AddressFamily: 4, Public: false}, 154 AddressRequest{AddressFamily: 6, Public: true}, 155 }, 156 } 157 158 resp, err := i.client.DoRequest("POST", path, &req, port) 159 if err != nil { 160 return nil, resp, err 161 } 162 163 return port, resp, err 164} 165 166func (i *DevicePortServiceOp) DeviceNetworkType(deviceID string) (NetworkType, error) { 167 d, _, err := i.client.Devices.Get(deviceID) 168 if err != nil { 169 return NetworkUnknown, err 170 } 171 if d.Plan.Slug == "baremetal_0" || d.Plan.Slug == "baremetal_1" { 172 return NetworkL3, nil 173 } 174 if d.Plan.Slug == "baremetal_1e" { 175 return NetworkHybrid, nil 176 } 177 if len(d.NetworkPorts) < 1 { 178 // really? 179 return NetworkL2Individual, nil 180 } 181 if d.NetworkPorts[0].Data.Bonded { 182 if d.NetworkPorts[2].Data.Bonded { 183 for _, ip := range d.Network { 184 if ip.Management { 185 return NetworkL3, nil 186 } 187 } 188 return NetworkL2Bonded, nil 189 } else { 190 return NetworkHybrid, nil 191 } 192 } 193 return NetworkL2Individual, nil 194} 195 196func (i *DevicePortServiceOp) DeviceToLayerThree(deviceID string) (*Device, error) { 197 // hopefull all the VLANs are unassigned at this point 198 bond0, err := i.client.DevicePorts.GetBondPort(deviceID) 199 if err != nil { 200 return nil, err 201 } 202 203 bond0, _, err = i.client.DevicePorts.PortToLayerThree(bond0.ID) 204 if err != nil { 205 return nil, err 206 } 207 d, _, err := i.client.Devices.Get(deviceID) 208 return d, err 209} 210 211// DeviceToLayerTwo converts device to L2 networking. Use bond0 to attach VLAN. 212func (i *DevicePortServiceOp) DeviceToLayerTwo(deviceID string) (*Device, error) { 213 bond0, err := i.client.DevicePorts.GetBondPort(deviceID) 214 if err != nil { 215 return nil, err 216 } 217 218 bond0, _, err = i.client.DevicePorts.PortToLayerTwo(bond0.ID) 219 if err != nil { 220 return nil, err 221 } 222 d, _, err := i.client.Devices.Get(deviceID) 223 return d, err 224 225} 226