package dcxSwitchapi import ( "encoding/json" "errors" "fmt" "strconv" "github.rackspace.com/gorax/tools/util" ) var vlanMap = map[string]string{"0": "0000", "1": "0001", "2": "0010", "3": "0011", "4": "0100", "5": "0101", "6": "0110", "7": "0111", "8": "1000", "9": "1001", "a": "1010", "b": "1011", "c": "1100", "d": "1101", "e": "1110", "f": "1111"} type ( SwitchApiInterfaces struct { Items []*SwitchApiInterface `json:"items"` } SwitchApiInterface struct { Admin string `json:"admin"` AggregatedTo *int `json:"aggregated_to"` Alias string `json:"alias"` Cdp string `json:"cdp"` Duplex string `json:"duplex"` HasConnector bool `json:"has_connector"` Id int `json:"id"` Link string `json:"link"` Links map[string]*SwitchApiLink `json:"links"` Lldp string `json:"lldp"` Name string `json:"name"` Port int `json:"port"` Security InterfaceSecurity `json:"secuirity"` Speed string `json:"speed"` Trunking InterfaceTrunk `json:"trunking"` Type string `json:"type"` VlanId int `json:"vlan_id"` SwName string `json:"switch_name"` InterfaceId int `json:"interface_id"` } SwitchApiLink struct { Href string `json:"href"` Rel string `json:"rel"` } InterfaceSecurity struct { Enabled bool `json:"enabled"` } InterfaceTrunk struct { Enabled bool `json:"enabled"` Encapsulation string `json:"encapsulation"` Native_vlan *int `json:"native_vlan"` Vlans_enabled []string `json:"vlans_enabled"` Vlans_transmitted []string `json:"vlans_transmitted"` Vlans_received []string `json:"vlans_received"` } switchApiInterface struct { Admin string `json:"admin"` AggregatedTo int `json:"aggregated_to"` Alias string `json:"alias"` Cdp string `json:"cdp"` Duplex string `json:"duplex"` HasConnector bool `json:"has_connector"` Id int `json:"id"` Link string `json:"link"` Links map[string]*SwitchApiLink `json:"links"` Lldp string `json:"lldp"` Name string `json:"name"` Port *int `json:"port"` Security InterfaceSecurity `json:"secuirity"` Type string `json:"type"` VlanId int `json:"vlan_id"` Speed json.RawMessage `json:"speed"` Trunking interfaceTrunk `json:"trunking"` SwName string `json:"switch_name"` InterfaceId *int `json:"interface_id"` } interfaceTrunk struct { Enabled bool `json:"enabled"` Encapsulation string `json:"encapsulation"` Native_vlan json.RawMessage `json:"native_vlan"` Vlans_enabled string `json:"vlans_enabled"` Vlans_transmitted string `json:"vlans_transmitted"` Vlans_received string `json:"vlans_received"` } switchApiInterfaces struct { Items []switchApiInterface `json:"items"` } ) // Method to return a port number, this is based on the switch port number func (s *Client) SwitchPort(swName string, port int) (*SwitchApiInterface, error) { body, err := s.get(fmt.Sprintf("%s/ports/%d", swName, port)) if err != nil { return nil, err } var sw switchApiInterface if err := json.Unmarshal(*body, &sw); err != nil { return nil, err } sw.SwName = swName p := sw.sanitize() p.Port = port return p, nil } // Method to return all ports, where the id is based on the switch port number func (s *Client) SwitchPorts(swName string) (*SwitchApiInterfaces, error) { body, err := s.get(swName + "/ports") if err != nil { return nil, err } // temporary switch to unmarshal raw json messages var sw switchApiInterfaces if err = json.Unmarshal(*body, &sw); err != nil { return nil, err } var Si SwitchApiInterfaces for _, si := range sw.Items { si.SwName = swName Si.Items = append(Si.Items, si.sanitize()) } return &Si, nil } // Method to return a port by switch api interface id func (s *Client) SwitchInterface(swName string, port int) (*SwitchApiInterface, error) { body, err := s.get(fmt.Sprintf("%s/interfaces/%d", swName, port)) if err != nil { return nil, err } var sw switchApiInterface if err := json.Unmarshal(*body, &sw); err != nil { return nil, err } sw.SwName = swName return sw.sanitize(), nil } // SwitchInterfaces returns all interfaces by switch api interface id func (s *Client) SwitchInterfaces(swName string) (*SwitchApiInterfaces, error) { body, err := s.get(swName + "/interfaces") if err != nil { return nil, err } // temporary switch to unmarshal raw json messages var sw switchApiInterfaces if err = json.Unmarshal(*body, &sw); err != nil { return nil, err } var Si SwitchApiInterfaces for _, si := range sw.Items { si.SwName = swName Si.Items = append(Si.Items, si.sanitize()) } return &Si, nil } // Method to return the aggregate interface, give a interface struct func (s *Client) AggregatePort(i *SwitchApiInterface) (*SwitchApiInterface, error) { if i.AggregatedTo == nil { return nil, nil } if i.SwName == "" { return nil, errors.New("unable to determine switch name.") } return s.SwitchInterface(i.SwName, *i.AggregatedTo) } // Method to return the aggregate interface, given a a port number func (s *Client) SwitchPortAggregate(swName string, port int) (*SwitchApiInterface, error) { i, err := s.SwitchPort(swName, port) if err != nil { return nil, err } return s.AggregatePort(i) } // Method to return the aggregate interface, give an switch api interface number func (s *Client) SwitchInterfaceAggregate(swName string, port int) (*SwitchApiInterface, error) { i, err := s.SwitchInterface(swName, port) if err != nil { return nil, err } return s.AggregatePort(i) } // Function to standardize speed and native vlan, due to int/string issues noticed on test devices func (i *switchApiInterface) sanitize() *SwitchApiInterface { return &SwitchApiInterface{ Admin: i.Admin, AggregatedTo: func() *int { if i.AggregatedTo == -1 { return nil } return &i.AggregatedTo }(), Alias: i.Alias, Cdp: i.Cdp, Duplex: i.Duplex, HasConnector: i.HasConnector, Id: i.Id, Link: i.Link, Links: i.Links, Lldp: i.Lldp, Name: i.Name, Port: func() int { if i.Port == nil { return i.Id } return *i.Port }(), InterfaceId: func() int { if i.InterfaceId == nil { return i.Id } return *i.InterfaceId }(), Security: i.Security, Speed: normalizeJson(&i.Speed), Trunking: InterfaceTrunk{ Enabled: i.Trunking.Enabled, Encapsulation: i.Trunking.Encapsulation, Native_vlan: func() *int { v := normalizeJson(&i.Trunking.Native_vlan) return util.AtoiPointer(v) }(), Vlans_enabled: VlanList(i.Trunking.Vlans_enabled), Vlans_transmitted: VlanList(i.Trunking.Vlans_transmitted), Vlans_received: VlanList(i.Trunking.Vlans_received), }, Type: i.Type, VlanId: i.VlanId, SwName: i.SwName, } } func normalizeJson(js *json.RawMessage) string { var i int if err := json.Unmarshal(*js, &i); err == nil { return strconv.Itoa(i) } var s string if err := json.Unmarshal(*js, &s); err == nil { return s } return "" } func VlanList(vl string) []string { return vlanList(vlanString(vl)) } func vlanString(vlStr string) (vl string) { for _, v := range vlStr { if data, ok := vlanMap[string(v)]; ok { vl += data } } return } func vlanList(vlStr string) (vl []string) { var tvl []int for i, v := range vlStr { if v == 49 { tvl = append(tvl, i) } } if len(tvl) == 0 { return } s := tvl[0] e := tvl[0] for _, v := range tvl[1:] { if e+1 == v { e = v continue } compareVlan(s, e, &vl) s, e = v, v } compareVlan(s, e, &vl) return } func compareVlan(s, e int, vl *[]string) { if s != e { if s-e == -1 { *vl = append(*vl, strconv.Itoa(s)) *vl = append(*vl, strconv.Itoa(e)) return } *vl = append(*vl, fmt.Sprintf("%d-%d", s, e)) return } *vl = append(*vl, strconv.Itoa(e)) }