// 2017 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 mongo is the interface into the MigrationDB collection and updates. package mongo import ( "context" "fmt" "math" "net/http" "strings" "time" "github.rackspace.com/DCM/tools/migMeta" "github.rackspace.com/DCM/tools" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "github.com/sirupsen/logrus" "github.rackspace.com/gorax/clients/mongodbAPI" ) const ( database = "migration" ) // CollectByDC is used to determine if the collection should source it's data // from the DC designation in CORE. var CollectByDC = []string{ "lon7", "hkg1", } // ValidNetDeviceCollections is a list of active collections in the NetDevicesDB that // are allowed to run actions against. Any new collections need to be added here. var ValidNetDeviceCollections = []string{ "adx", "alertlogic", "asa", "css", "f5", "firepower", "imperva", "juniper", "netscaler", "pix", "palo_alto", "routers", "rsa", } // WafNetDevice types are a list of make_models that are eligible to // be connected to a WAF. var WafNetDevice = []string{ "Load-Balancer", "Cisco ASA", "Cisco Pix 506", "Cisco Pix 515R", "Cisco Pix 515URLL", "Firewall - Web Application", } // DeletedNETrue is the mongo3 query value for {"deleted": {"$ne": true}} var DeletedNETrue = bson.E{"deleted", bson.D{{"$ne", true}}} // Container type is the representation of a datacenter cabinet within the // migration database. // swagger:model container type Container struct { ID string `json:"_id" bson:"_id"` Utilization ContainerUtilization `json:"utilization" bson:"utilization"` MoveGroups []string `json:"move_groups" bson:"move_groups"` Switches []struct { Hardware string `json:"hardware" bson:"hardware"` Name string `json:"name" bson:"name"` } `json:"switches" bson:"switches"` } // ContainerUtilization type is the total utilization statistics for the container. // swagger:model containerUtilization type ContainerUtilization struct { Name string TotalPorts string `json:"total_ports" bson:"total_ports"` InUse string `json:"in_use" bson:"in_use"` PercentUp string `json:"percent_up" bson:"percent_up"` PortsUp []string `json:"ports_up" bson:"ports_up"` Devices []string `json:"devices" bson:"devices"` } type ( // Client type represents client references to third-party resources required // for the methods within this package. // swagger:ignore Client struct { db *mongodbAPI.Client db3 *mongo.Client hideDeleted bool table string collection *mongo.Collection migrationMetadata migMeta.Migration } // MigratedEnvironment defines an entry in the environmentsMigrated table // // swagger:ignore MigratedEnvironment struct { ID string `json:"_id" bson:"_id"` Migrated bool `json:"migrated" bson:"migrated"` } // NagiosSnapshot type defines the ID and content of a snapshot from the // nagios Snapshots collection // swagger:ignore NagiosSnapshot struct { ID string `bson:"_id" json:"_id"` Content nagiosSnapshotContent `bson:"Content" json:"Content"` } nagiosSnapshotContent struct { Accnt []nagiosSnapshotAccnt `bson:"Accnt" json:"Accnt"` List map[string]nagiosSnapshotListItem `bson:"List" json:"List"` Summary struct { Crit int `bson:"Crit" json:"Crit"` Dis int `bson:"Dis" json:"Dis"` Total int `bson:"Total" json:"Total"` Up int `bson:"Up" json:"Up"` Warn int `bson:"Warn" json:"Warn"` } `bson:"Summary" json:"Summary"` } nagiosSnapshotListItem struct { CustomerManaged bool DNPO bool Decom bool Drac string Icon string Public string TextColor string } nagiosSnapshotAccnt struct { ID string LinkName string Name string Padding string Hosts []struct { CustomerManaged bool DNPO bool DatapipeID string Decom bool ID string Icon string Svcs []struct { Datacenter string Desc string IPAddress string LastChecked string Output string Service string State struct { Color string Name string } SvcAbbr string } } } // ProcessMap type represents the logic used to determine the process os_type // for a given set of devices. // // swagger:model ProcessMap struct { // in:body ProcessType string `json:"process_os_type" bson:"process_os_type"` Order int `json:"order" bson:"order"` Where []processEntry `json:"where" bson:"where"` } // ProcessMapDB type represents the logic used to determine the process os_type // for a given set of devices with the hashed unique ID. ProcessMapDB struct { ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` Order int `json:"order" bson:"order"` ProcessType string `json:"process_os_type" bson:"process_os_type"` Where []processEntry `json:"where" bson:"where"` } processEntry struct { Name string `json:"name" bson:"name"` Value string `json:"value" bson:"value"` } // UpdateOne is the return type for a Mongo update // response. UpdateOne struct { MatchedCount int `json:"matched_count" bson:"matched_count"` } //ZoneMap defines an entry in the ZoneMapping table; _id is string "aggr:Vlan<##>" // swagger:ignore ZoneMap struct { ID string `json:"_id" bson:"_id"` SourceZone string `json:"source_zone" bson:"source_zone"` SourceVLAN int `json:"source_vlan" bson:"source_vlan"` MigrationZone string `json:"migration_zone" bson:"migration_zone"` } //ZoneVlan defines an entry in the vlanTranslationExcluded table // swagger:ignore ZoneVlan struct { ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` ZoneName string `json:"zone_name" bson:"zone_name"` VlanNumber int `json:"vlan_number" bson:"vlan_number"` } // findNetDevice type represents the response // data type returned from a Mongo Find query. findNetDevice struct { Result []NetDevice `json:"result" bson:"result"` } // NetDevice type represents an abstracted device type pulled from the netdevices DB NetDevice struct { ID string `json:"_id" bson:"_id"` Account struct { AccountExec string `json:"account_exec" bson:"account_exec"` IsInternal bool `json:"is_internal" bson:"is_internal"` Name string `json:"name" bson:"name"` NetSecTeam string `json:"netsec_team" bson:"netsec_team"` Number string `json:"number" bson:"number"` PrimaryLeadTech interface{} `json:"primary_lead_tech" bson:"primary_lead_tech"` SegmentName string `json:"segment_name" bson:"segment_name"` ServiceLevel string `json:"service_level" bson:"service_level"` SKUs []string `json:"skus" bson:"skus"` Status string `json:"status" bson:"status"` SupportTeam string `json:"support_team" bson:"support_team"` } `json:"account" bson:"account"` BaseRegistrationKey string `json:"base_registration_key,omitempty" bson:"base_registration_key,omitempty"` ActivationKey string `json:"activation_key,omitempty" bson:"activation_key,omitempty"` AnyConnect struct { Enabled bool `json:"enabled" bson:"enabled"` ImageList []string `json:"image_list" bson:"image_list"` } `json:"anyconnect,omitempty" bson:"anyconnect,omitempty"` AnyConnectEssentials bool `json:"anyconnect_essentials,omitempty" bson:"anyconnect_essentials,omitempty"` AnyConnectPremiumPeers string `json:"anyconnect_premium_peers,omitempty" bson:"anyconnect_premium_peers,omitempty"` Audits struct { ConsecutiveErrors string `json:"consecutive_errors" bson:"consecutive_errors"` LastCompletedDate string `json:"last_completed_date" bson:"last_completed_date"` LastCompletedTime string `json:"last_completed_time" bson:"last_completed_time"` LastResults struct { CommandAuth string `json:"commandauth,omitempty" bson:"commandauth,omitempty"` SysInfo string `json:"sysinfo" bson:"sysinfo"` VerifyHA string `json:"verifyHA" bson:"verifyHA"` ConfigSync string `json:"configsync,omitempty" bson:"configsync,omitempty"` DiskSpace string `json:"diskspace,omitempty" bson:"diskspace,omitempty"` } `json:"last_results" bson:"last_results"` } `json:"audits" bson:"audits"` ChassisSerial string `json:"chassis_serial" bson:"chassis_serial"` ChassisVid string `json:"chassis_vid" bson:"chassis_vid"` Context bool `json:"context" bson:"context"` Datacenter string `json:"datacenter" bson:"datacenter"` DracGateway interface{} `json:"drac_gateway" bson:"drac_gateway"` DracIP interface{} `json:"drac_ip" bson:"drac_ip"` FailoverDevice struct { FailoverID interface{} `json:"failover_id" bson:"failover_id"` PrimaryIP interface{} `json:"primary_ip" bson:"primary_ip"` } `json:"failover_device" bson:"failover_device"` Flash struct { Files []struct { Date string `json:"date,omitempty" bson:"date,omitempty"` FileName string `json:"file name,omitempty"` Permisions string `json:"permisions,omitempty" bson:"permisions,omitempty"` Size string `json:"size,omitempty" bson:"size,omitempty"` } `json:"files,omitempty" bson:"files,omitempty"` FreeBytes string `json:"free_bytes,omitempty" bson:"free_bytes,omitempty"` TotalBytes string `json:"total_bytes,omitempty" bson:"total_bytes,omitempty"` } `json:"flash,omitempty" bson:"flash,omitempty"` Gateway string `json:"gateway" bson:"gateway"` IKEv1Enabled bool `json:"ikev1_enabled,omitempty" bson:"ikev1_enabled,omitempty"` IKEv2Enabled bool `json:"ikev2_enabled,omitempty" bson:"ikev2_enabled,omitempty"` IsUkAccount bool `json:"is_uk_account" bson:"is_uk_account"` LastCoreImport string `json:"last_core_import" bson:"last_core_import"` License string `json:"license" bson:"license"` Name string `json:"name" bson:"name"` PlatformModel string `json:"platform_model" bson:"platform_model"` PlatformName string `json:"platform_name" bson:"platform_name"` PrimaryIP string `json:"primary_ip" bson:"primary_ip"` RAM string `json:"ram" bson:"ram"` Serial string `json:"serial" bson:"serial"` SKUs []string `json:"skus" bson:"skus"` Status string `json:"status" bson:"status"` UpTime string `json:"uptime" bson:"uptime"` Version string `json:"version" bson:"version"` Edition string `json:"edition,omitempty" bson:"edition,omitempty"` LicensedOn string `json:"licensed_on,omitempty" bson:"licensed_on,omitempty"` ModulesEnabled []string `json:"modules_enabled,omitempty" bson:"modules_enabled,omitempty"` ServiceCheckDate string `json:"service_check_date,omitempty" bson:"service_check_date,omitempty"` } // EBIFilters is a local definition of ebi.Filters to prevent a circular import EBIFilters struct { primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` Value string `json:"value" bson:"value"` Type string `json:"type" bson:"type"` } ) // New function will take the direct references to the clients required for this package. // This is under the assumption that you have initiated your own client and are passing by // reference. func New(db *mongodbAPI.Client, db3 *mongo.Client) *Client { return &Client{ db: db, db3: db3, } } // NewContext function will take a pointer to a Request, and pull the client references // from the Context() offered within the default net/http package. func NewContext(r *http.Request) *Client { return &Client{ db: mongodbAPI.FromContext(r.Context()), db3: tools.MongoFromContext(r.Context()), } } // Chunk is a small internal function to break a list of Device types into // smaller chunks that we can send to go routines. func Chunk(devList []tools.Device, size int) (chunk [][]tools.Device) { 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 } // CollectionDC will return the datacenter from the set migrationMetadata func (c *Client) CollectionDC() string { return c.migrationMetadata.DataCenter } // CollectionType will return the type from the set migrationMetadata func (c *Client) CollectionType() string { return c.migrationMetadata.Type } // HideDeleted method will set the private hideDeleted flag so that // the calls to the MigrationDB will not include migrated or CNLA devices. func (c *Client) HideDeleted() { c.hideDeleted = true } // ShowDeleted method will set the private hideDeleted flag to FALSE so that // the calls to the MigrationDB will include migrated or CNLA devices. func (c *Client) ShowDeleted() { c.hideDeleted = false } // SetCollection method will set the collection table name if the collection is one of the // ValidCollections func (c *Client) SetCollection(name string) error { name = strings.ToLower(name) if m := c.ValidCollection(name); m != nil { logrus.Infof("using collection %s", name) c.table = name c.collection = c.db3.Database(database).Collection(name) c.migrationMetadata = *m return nil } for _, vc := range ValidNetDeviceCollections { if name == vc { logrus.Infof("using collection %s", vc) c.table = name return nil } } return fmt.Errorf("%s is not a valid collection", name) } // Platform will return the device platform based on config-type, make-model, // or other various aspects. func Platform(d tools.Device) string { configType := strings.ToLower(d.Device.ComponentConfigType) makeModel := strings.ToLower(d.Device.MakeModel) switch { case strings.Contains(configType, "cisco asa"): return "asa" case strings.Contains(configType, "asa 55"): return "asa" case strings.Contains(configType, "firepower"): return "firepower" case strings.Contains(configType, "cisco pix"): return "pix" case strings.Contains(configType, "cisco css"): return "css" case strings.Contains(configType, "brocade adx"): return "adx" case strings.Contains(configType, "f5"): return "f5" case strings.Contains(makeModel, "load balancer (virtual)"): return "netscaler" case strings.Contains(configType, "threat manager"): return "ids" case strings.Contains(configType, "web application firewall") || strings.Contains(configType, "imperva waf"): return "waf" } return "unsupported" } // ValidCollection will verify the collection matches an active collection name and will // return a pointer to the migrationMetadata, or nil func (c *Client) ValidCollection(col string) *migMeta.Migration { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() m := new(migMeta.Migration) if err := c.db3.Database(database).Collection(migMeta.Collection).FindOne( ctx, bson.D{{"_id", strings.ToLower(col)}, {"active", true}}, ).Decode(m); err != nil { logrus.Errorf("mongo.ValidCollection(%s): %s", col, err) return nil } return m }