// 2018 Rackspace, Inc. // // Licensed 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. package network import ( "fmt" "math" "strconv" "strings" "github.rackspace.com/DCM/migration/pkg/collection" "github.rackspace.com/DCM/migration/pkg/collection/mongo" "github.rackspace.com/gorax/clients/unipede" "github.rackspace.com/gorax/tools/util" "go.mongodb.org/mongo-driver/bson" ) var aggrReplace = strings.NewReplacer( "a.", "", "b.", "", "a-", "-", "b-", "-", "aggrit10", "aggrit", "aggrit1", "aggrit", "aggrit2", "aggrit", "agg-r1", "agg-r", "agg-r2", "agg-r", "colo1", "colo", "colo2", "colo", "ord1", "", "iad1", "", "iad2", "", "iad3", "", "iad60", "", "lon1", "", "lon2", "", "lon3", "", "lon4", "", "lon5", "", "lon6", "", "lon7", "", "dfw1", "", "dfw2", "", "dfw3", "", "syd2", "", "syd4", "", "fra1", "", "hkg1", "", "sin80", "", "hko1", "", "atl60", "", "atl61", "", "aggr", "", ".", "", ) // UpdateNetDeviceZones method will spawn a set of go routines to query Unipede and gather the // associated public zone for a given set of devices. func (c *Client) UpdateNetDeviceZones(nd []mongo.NetDevice, col string) (resp collection.UpdateResponse, err error) { chMissed := make(chan []collection.Missed) chInt := make(chan int) ch := chunkNetDevice(nd, routines) defer close(chInt) defer close(chMissed) for _, item := range ch { go runUnipedeNetDeviceRoutine(c, item, chInt, chMissed, col) } for range ch { resp.Missed = append(resp.Missed, <-chMissed...) resp.Updated += <-chInt } return } // runUnipedeNetDeviceRoutine is an internal function to kick off the UpdatePublicZoneData routines. func runUnipedeNetDeviceRoutine(c *Client, dl []mongo.NetDevice, chInt chan<- int, chMissed chan<- []collection.Missed, col string) { var r collection.UpdateResponse for _, item := range dl { id, _ := strconv.Atoi(item.ID) if item.PrimaryIP == "" || item.PrimaryIP == "0" || !util.IsRoutedIP(item.PrimaryIP) { if uErr := c.db.UpdateOne( col, bson.D{{"_id", item.ID}}, bson.D{{"$set", bson.D{{"public_zone", ""}}}}, false, ); uErr != nil { r.Missed = append(r.Missed, collection.Missed{Item: id, Details: uErr.Error()}) continue } continue } s, err := c.u.GetStaticRouteByIP(item.PrimaryIP, nil) if err != nil { r.Missed = append(r.Missed, collection.Missed{Item: id, Details: err.Error()}) continue } ip := item.PrimaryIP if s.Count != 0 { for _, dev := range s.Data { if dev.NextHopAddress != "" { ip = dev.NextHopAddress break } } } zone, err := getByConnectedRoute(c, ip, item.Datacenter) if err != nil { r.Missed = append(r.Missed, collection.Missed{Item: id, Details: err.Error()}) continue } if uErr := c.db.UpdateOne( col, bson.D{{"_id", item.ID}}, bson.D{{"$set", bson.D{{"public_zone", zone}}}}, false, ); uErr != nil { r.Missed = append(r.Missed, collection.Missed{Item: id, Details: uErr.Error()}) continue } r.Updated++ } chMissed <- r.Missed chInt <- r.Updated } func getByConnectedRoute(c *Client, address, dc string) (string, error) { var aggr unipede.UnipedeDeviceModel connected, err := c.u.GetConnectedRouteByIP(address, nil) if err != nil { return "", err } if connected.Count == 0 { return "", fmt.Errorf("no connected routes found") } for _, v := range connected.Data { aggr, err = c.u.UnipedeDeviceModel(v.UpDeviceID, nil) if err != nil { return "", err } for _, ag := range aggr.Data { // Check to make sure the switch we found is actually located in the correct DC. if strings.Contains(strings.ToLower(ag.Hostname), fmt.Sprintf(".%s", strings.ToLower(dc))) { return fmt.Sprintf("%s:Zone%v:%v", dc, strings.ToUpper(aggrReplace.Replace(ag.Hostname)), v.Interface), nil } } } return "", nil } // chunkNetDevice is a small internal function to break a list of Device types into // smaller chunks that we can send to go routines. func chunkNetDevice(devList []mongo.NetDevice, size int) (chunk [][]mongo.NetDevice) { float := float64(len(devList)) / float64(size) chunkSize := int(math.Ceil(float)) for i := 0; i < len(devList); i += chunkSize { end := i + chunkSize if end > len(devList) { end = len(devList) } chunk = append(chunk, devList[i:end]) } return }