shamrickus commented on a change in pull request #4700:
URL: https://github.com/apache/trafficcontrol/pull/4700#discussion_r428147596
##########
File path: lib/go-tc/servers.go
##########
@@ -49,6 +64,157 @@ type ServersV1DetailResponse struct {
Alerts
}
+// ServerIpAddress is the data associated with a server's interface's IP
address.
+type ServerIpAddress struct {
+ Address string `json:"address" db:"address"`
+ Gateway *string `json:"gateway" db:"gateway"`
+ ServiceAddress bool `json:"serviceAddress" db:"service_address"`
+}
+
+// ServerInterfaceInfo is the data associated with a server's interface.
+type ServerInterfaceInfo struct {
+ IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ip_addresses"`
+ MaxBandwidth *uint64 `json:"maxBandwidth" db:"max_bandwidth"`
+ Monitor bool `json:"monitor" db:"monitor"`
+ MTU *uint64 `json:"mtu" db:"mtu"`
+ Name string `json:"name" db:"name"`
+}
+
+// Value implements the driver.Valuer interface
+// marshals struct to json to pass back as a json.RawMessage
+func (sii *ServerInterfaceInfo) Value() (driver.Value, error) {
+ b, err := json.Marshal(sii)
+ return b, err
+}
+
+// Scan implements the sql.Scanner interface
+// expects json.RawMessage and unmarshals to a deliveryservice struct
+func (sii *ServerInterfaceInfo) Scan(src interface{}) error {
+ b, ok := src.([]byte)
+ if !ok {
+ return fmt.Errorf("expected deliveryservice in byte array form;
got %T", src)
+ }
+
+ return json.Unmarshal([]byte(b), sii)
+}
+
+// LegacyInterfaceDetails is the details for interfaces on servers for API v1
and v2.
+type LegacyInterfaceDetails struct {
+ InterfaceMtu *int `json:"interfaceMtu" db:"interface_mtu"`
+ InterfaceName *string `json:"interfaceName" db:"interface_name"`
+ IP6Address *string `json:"ip6Address" db:"ip6_address"`
+ IP6Gateway *string `json:"ip6Gateway" db:"ip6_gateway"`
+ IPAddress *string `json:"ipAddress" db:"ip_address"`
+ IPGateway *string `json:"ipGateway" db:"ip_gateway"`
+ IPNetmask *string `json:"ipNetmask" db:"ip_netmask"`
+}
+
+// ToInterfaces converts a LegacyInterfaceDetails to a slice of
+// ServerInterfaceInfo structures. No interfaces will be marked for monitoring,
+// and it will generate service addresses according to the passed indicators
+// for each address family.
+func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService
bool) ([]ServerInterfaceInfo, error) {
+ var iface ServerInterfaceInfo
+ if lid.InterfaceMtu == nil {
+ return nil, errors.New("interfaceMtu is null")
+ }
+ mtu := uint64(*lid.InterfaceMtu)
+ iface.MTU = &mtu
+
+ if lid.InterfaceName == nil {
+ return nil, errors.New("interfaceName is null")
+ }
+ iface.Name = *lid.InterfaceName
+
+ var ips []ServerIpAddress
+ if lid.IPAddress != nil && *lid.IPAddress != "" {
+ if lid.IPGateway != nil && *lid.IPGateway == "" {
+ lid.IPGateway = nil
+ }
+
+ ipStr := *lid.IPAddress
+ if lid.IPNetmask != nil && *lid.IPNetmask != "" {
+ mask := net.ParseIP(*lid.IPNetmask).To4()
+ if mask == nil {
+ return nil, fmt.Errorf("Failed to parse netmask
'%s'", *lid.IPNetmask)
+ }
+ cidr, _ := net.IPv4Mask(mask[0], mask[1], mask[2],
mask[3]).Size()
+ ipStr = fmt.Sprintf("%s/%d", ipStr, cidr)
+ }
+
+ ips = append(ips, ServerIpAddress{
+ Address: ipStr,
+ Gateway: lid.IPGateway,
+ ServiceAddress: ipv4IsService,
+ })
+ }
+
+ if lid.IP6Address != nil && *lid.IP6Address != "" {
+ if lid.IP6Gateway != nil && *lid.IP6Gateway == "" {
+ lid.IP6Gateway = nil
+ }
+ ips = append(ips, ServerIpAddress{
+ Address: *lid.IP6Address,
+ Gateway: lid.IP6Gateway,
+ ServiceAddress: ipv6IsService,
+ })
+ }
+
+ iface.IPAddresses = ips
+ return []ServerInterfaceInfo{iface}, nil
+}
+
+// InterfaceInfoToLegacyInterfaces converts a ServerInterfaceInfo to an
+// equivalent LegacyInterfaceDetails structure. It does this by creating the
+// IP address fields using the "service" interface's IP addresses. All others
+// are discarded, as the legacy format is incapable of representing them.
+func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo)
(LegacyInterfaceDetails, error) {
+ var legacyDetails LegacyInterfaceDetails
+
+ for _, intFace := range serverInterfaces {
+
+ for _, addr := range intFace.IPAddresses {
+ if !addr.ServiceAddress {
+ continue
+ }
+
+ address := addr.Address
+ gateway := addr.Gateway
+
+ var parsedIp net.IP
+ var mask *net.IPNet
+ var err error
+ parsedIp, mask, err = net.ParseCIDR(address)
+ if err != nil {
+ parsedIp = net.ParseIP(address)
+ if parsedIp == nil {
+ return legacyDetails,
fmt.Errorf("Failed to parse '%s' as network or CIDR string: %v", address, err)
+ }
+ }
+
+ if parsedIp.To4() == nil {
+ legacyDetails.IP6Address = &address
+ legacyDetails.IP6Gateway = gateway
+ } else if mask != nil {
+ legacyDetails.IPAddress =
util.StrPtr(parsedIp.String())
+ legacyDetails.IPGateway = gateway
+ legacyDetails.IPNetmask =
util.StrPtr(fmt.Sprintf("%d.%d.%d.%d", mask.Mask[0], mask.Mask[1],
mask.Mask[2], mask.Mask[3]))
Review comment:
Wouldn't it be possible for the legacy interface to have the netmask
field set for a different address/gateway?
E.g.
```
cache
eth0
addr: x.y.w.z
gateway: x.y.w.z
netmask: x.y.w.z
lo:
addr: i,j,k,l
gateway: i,j,k,l
```
resulting in a legacy interface that has the `lo` addr/gateway with the
`eth0` netmask.
It seems to me that we should unset the IPNetmask in the else below.
##########
File path: lib/go-tc/servers.go
##########
@@ -25,7 +30,17 @@ import (
* under the License.
*/
-// ServersResponse is a list of Servers as a response.
+// ServersResponsev3 is the format of a response to a GET request for /servers.
+type ServersResponsev3 struct {
Review comment:
`v3` should probably be capitalized.
##########
File path: lib/go-tc/servers.go
##########
@@ -49,6 +64,157 @@ type ServersV1DetailResponse struct {
Alerts
}
+// ServerIpAddress is the data associated with a server's interface's IP
address.
+type ServerIpAddress struct {
Review comment:
`Ip` should be capitalized
##########
File path:
traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go
##########
@@ -181,16 +182,23 @@ func InvalidDeliveryServicesRequiredCapabilityAddition(t
*testing.T) {
}
// First assign current capabilities to edge server so we can assign it
to the DS
- servers, _, err := TOSession.GetServerByHostName("atlanta-edge-01")
+ // TODO: DON'T hard-code hostnames!
Review comment:
TODO
`testData.Servers[0].HostName`?
##########
File path: traffic_ops/testing/api/v3/deliveryserviceservers_test.go
##########
@@ -113,8 +119,10 @@ func CreateTestMSODSServerWithReqCap(t *testing.T) {
}
// Associate origin server to msods1 even though it does not have req
cap
-
- servers, _, err := TOSession.GetServerByHostName("denver-mso-org-01")
+ // TODO: DON'T hard-code server hostnames!
Review comment:
TODO
##########
File path: lib/go-tc/servers.go
##########
@@ -49,6 +64,157 @@ type ServersV1DetailResponse struct {
Alerts
}
+// ServerIpAddress is the data associated with a server's interface's IP
address.
+type ServerIpAddress struct {
+ Address string `json:"address" db:"address"`
+ Gateway *string `json:"gateway" db:"gateway"`
+ ServiceAddress bool `json:"serviceAddress" db:"service_address"`
+}
+
+// ServerInterfaceInfo is the data associated with a server's interface.
+type ServerInterfaceInfo struct {
+ IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ip_addresses"`
+ MaxBandwidth *uint64 `json:"maxBandwidth" db:"max_bandwidth"`
+ Monitor bool `json:"monitor" db:"monitor"`
+ MTU *uint64 `json:"mtu" db:"mtu"`
+ Name string `json:"name" db:"name"`
+}
+
+// Value implements the driver.Valuer interface
+// marshals struct to json to pass back as a json.RawMessage
+func (sii *ServerInterfaceInfo) Value() (driver.Value, error) {
+ b, err := json.Marshal(sii)
+ return b, err
+}
+
+// Scan implements the sql.Scanner interface
+// expects json.RawMessage and unmarshals to a deliveryservice struct
+func (sii *ServerInterfaceInfo) Scan(src interface{}) error {
+ b, ok := src.([]byte)
+ if !ok {
+ return fmt.Errorf("expected deliveryservice in byte array form;
got %T", src)
+ }
+
+ return json.Unmarshal([]byte(b), sii)
+}
+
+// LegacyInterfaceDetails is the details for interfaces on servers for API v1
and v2.
+type LegacyInterfaceDetails struct {
+ InterfaceMtu *int `json:"interfaceMtu" db:"interface_mtu"`
Review comment:
`Mtu` should be capitalized
##########
File path: lib/go-tc/servers_test.go
##########
@@ -0,0 +1,58 @@
+package tc
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import "fmt"
+
+func ExampleLegacyInterfaceDetails_ToInterfaces() {
Review comment:
This isn't a test
##########
File path: lib/go-tc/servers.go
##########
@@ -49,6 +64,157 @@ type ServersV1DetailResponse struct {
Alerts
}
+// ServerIpAddress is the data associated with a server's interface's IP
address.
+type ServerIpAddress struct {
+ Address string `json:"address" db:"address"`
+ Gateway *string `json:"gateway" db:"gateway"`
+ ServiceAddress bool `json:"serviceAddress" db:"service_address"`
+}
+
+// ServerInterfaceInfo is the data associated with a server's interface.
+type ServerInterfaceInfo struct {
+ IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ip_addresses"`
+ MaxBandwidth *uint64 `json:"maxBandwidth" db:"max_bandwidth"`
+ Monitor bool `json:"monitor" db:"monitor"`
+ MTU *uint64 `json:"mtu" db:"mtu"`
+ Name string `json:"name" db:"name"`
+}
+
+// Value implements the driver.Valuer interface
+// marshals struct to json to pass back as a json.RawMessage
+func (sii *ServerInterfaceInfo) Value() (driver.Value, error) {
+ b, err := json.Marshal(sii)
+ return b, err
+}
+
+// Scan implements the sql.Scanner interface
+// expects json.RawMessage and unmarshals to a deliveryservice struct
+func (sii *ServerInterfaceInfo) Scan(src interface{}) error {
+ b, ok := src.([]byte)
+ if !ok {
+ return fmt.Errorf("expected deliveryservice in byte array form;
got %T", src)
+ }
+
+ return json.Unmarshal([]byte(b), sii)
+}
+
+// LegacyInterfaceDetails is the details for interfaces on servers for API v1
and v2.
+type LegacyInterfaceDetails struct {
+ InterfaceMtu *int `json:"interfaceMtu" db:"interface_mtu"`
+ InterfaceName *string `json:"interfaceName" db:"interface_name"`
+ IP6Address *string `json:"ip6Address" db:"ip6_address"`
+ IP6Gateway *string `json:"ip6Gateway" db:"ip6_gateway"`
+ IPAddress *string `json:"ipAddress" db:"ip_address"`
+ IPGateway *string `json:"ipGateway" db:"ip_gateway"`
+ IPNetmask *string `json:"ipNetmask" db:"ip_netmask"`
+}
+
+// ToInterfaces converts a LegacyInterfaceDetails to a slice of
+// ServerInterfaceInfo structures. No interfaces will be marked for monitoring,
+// and it will generate service addresses according to the passed indicators
+// for each address family.
+func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService
bool) ([]ServerInterfaceInfo, error) {
+ var iface ServerInterfaceInfo
+ if lid.InterfaceMtu == nil {
+ return nil, errors.New("interfaceMtu is null")
+ }
+ mtu := uint64(*lid.InterfaceMtu)
+ iface.MTU = &mtu
+
+ if lid.InterfaceName == nil {
+ return nil, errors.New("interfaceName is null")
+ }
+ iface.Name = *lid.InterfaceName
+
+ var ips []ServerIpAddress
+ if lid.IPAddress != nil && *lid.IPAddress != "" {
+ if lid.IPGateway != nil && *lid.IPGateway == "" {
+ lid.IPGateway = nil
+ }
+
+ ipStr := *lid.IPAddress
+ if lid.IPNetmask != nil && *lid.IPNetmask != "" {
+ mask := net.ParseIP(*lid.IPNetmask).To4()
+ if mask == nil {
+ return nil, fmt.Errorf("Failed to parse netmask
'%s'", *lid.IPNetmask)
+ }
+ cidr, _ := net.IPv4Mask(mask[0], mask[1], mask[2],
mask[3]).Size()
+ ipStr = fmt.Sprintf("%s/%d", ipStr, cidr)
+ }
+
+ ips = append(ips, ServerIpAddress{
+ Address: ipStr,
+ Gateway: lid.IPGateway,
+ ServiceAddress: ipv4IsService,
+ })
+ }
+
+ if lid.IP6Address != nil && *lid.IP6Address != "" {
+ if lid.IP6Gateway != nil && *lid.IP6Gateway == "" {
+ lid.IP6Gateway = nil
+ }
+ ips = append(ips, ServerIpAddress{
+ Address: *lid.IP6Address,
+ Gateway: lid.IP6Gateway,
+ ServiceAddress: ipv6IsService,
+ })
+ }
+
+ iface.IPAddresses = ips
+ return []ServerInterfaceInfo{iface}, nil
+}
+
+// InterfaceInfoToLegacyInterfaces converts a ServerInterfaceInfo to an
+// equivalent LegacyInterfaceDetails structure. It does this by creating the
+// IP address fields using the "service" interface's IP addresses. All others
+// are discarded, as the legacy format is incapable of representing them.
+func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo)
(LegacyInterfaceDetails, error) {
+ var legacyDetails LegacyInterfaceDetails
+
+ for _, intFace := range serverInterfaces {
+
+ for _, addr := range intFace.IPAddresses {
+ if !addr.ServiceAddress {
+ continue
+ }
+
+ address := addr.Address
+ gateway := addr.Gateway
+
+ var parsedIp net.IP
+ var mask *net.IPNet
+ var err error
+ parsedIp, mask, err = net.ParseCIDR(address)
+ if err != nil {
+ parsedIp = net.ParseIP(address)
+ if parsedIp == nil {
+ return legacyDetails,
fmt.Errorf("Failed to parse '%s' as network or CIDR string: %v", address, err)
+ }
+ }
+
+ if parsedIp.To4() == nil {
+ legacyDetails.IP6Address = &address
+ legacyDetails.IP6Gateway = gateway
+ } else if mask != nil {
+ legacyDetails.IPAddress =
util.StrPtr(parsedIp.String())
+ legacyDetails.IPGateway = gateway
+ legacyDetails.IPNetmask =
util.StrPtr(fmt.Sprintf("%d.%d.%d.%d", mask.Mask[0], mask.Mask[1],
mask.Mask[2], mask.Mask[3]))
+ } else {
+ legacyDetails.IPAddress =
util.StrPtr(parsedIp.String())
+ legacyDetails.IPGateway = gateway
+ }
+
+ if intFace.MTU != nil {
+ legacyDetails.InterfaceMtu =
util.IntPtr(int(*intFace.MTU))
+ }
+
+ legacyDetails.InterfaceName = &intFace.Name
Review comment:
It might not be worth the effort, but once we have gathered the minimum
"full" interface we could short circuit the return here as to prevent useless
iterations.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]