// 2020 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 shutdown import ( "fmt" "log" "os" "strconv" "github.com/davecgh/go-spew/spew" "github.com/sirupsen/logrus" "github.rackspace.com/DCM/gomigrate/shared" migShutdown "github.rackspace.com/DCM/migration/pkg/shutdown" "github.rackspace.com/DCM/tools" "github.rackspace.com/gorax/clients/migrationAPI" "github.rackspace.com/gorax/gokeys" ) type ( client struct { device int coreToken string identityToken string } ) func pluginInit(cfg gokeys.Settings) *client { if args[argDevice] == nil || *args[argDevice].(*int) == 0 { log.Fatal("device required") } // Set all the key from the arg parser c := client{ device: *args[argDevice].(*int), } // Pull an identity token from the users gokeys keychain key, err := cfg.Identity(false) if err != nil { log.Fatal(err) } c.identityToken = key.Password // Pull a core token from the gokeys keychain coreKey, err := cfg.Core(false) if err != nil { log.Fatal(err) } c.coreToken = coreKey.Password return &c } // pluginFunc function is executed from the gomigrate caller func pluginFunc(cfg gokeys.Settings) { c := pluginInit(cfg) // Get the device list from a list of move-groups or devices. devices, err := shared.MongoDevices([]string{}, nil, []int{c.device}, "", c.coreToken, make(map[string]interface{})) if err != nil { logrus.Fatal(err) } // Stop here if we did not find any devices. if len(devices) == 0 { logrus.Fatalf("no DB devices found in devices:(%v)", c.device) } device := devices[0] migapi := migrationAPI.New(c.identityToken, false) payload := migShutdown.Options{ ID: c.device, FullConfig: checkFlag(argFullConfig), LiveConfig: checkFlag(argLiveConfig), MgmtIP: func() string { if args[argMgmtIP] == nil { return "" } return *args[argMgmtIP].(*string) }(), MgmtInfo: mgmtInfo(device), PublicInfo: publicInfo(device), SkipBackup: checkFlag(argSkipBackup), SkipRevert: checkFlag(argSkipRevert), UpdateDevice: checkFlag(argUpdate), VerifyOnly: checkFlag(argVerifyOnly), VlanMap: vlanMap(device), } if checkFlag(argTest) { spew.Dump(payload) return } resp, err := migapi.ShutdownPrep(payload) pPrint(c.device, resp, err) if checkFlag(argFullConfig) { f := filename(c.device) //nolint:gosec // G306: Expect WriteFile permissions to be 0600 or less err = os.WriteFile(f, []byte(resp.Config.Data), 0644) if err == nil { fmt.Printf("full config saved as: %s\n", f) } else { logrus.Errorln(err.Error()) } } } func checkFlag(key string) bool { if args[key] == nil { return false } return *args[key].(*bool) } func filename(device int) string { if args[argOutputFile] == nil || *args[argOutputFile].(*string) == "" { return fmt.Sprintf("%d-config.txt", device) } return *args[argOutputFile].(*string) } func mgmtInfo(device tools.Device) *migShutdown.IPInfo { if len(device.Network.Address.DracIPs.Source) == 0 || len(device.Network.Address.DracIPs.Migration) == 0 { return nil } return &migShutdown.IPInfo{ IP: migShutdown.InfoItem{ Old: device.Network.Address.DracIPs.Source[0].IPAddress, New: device.Network.Address.DracIPs.Migration[0].IPAddress, }, Netmask: migShutdown.InfoItem{ Old: device.Network.Address.DracIPs.Source[0].Netmask, New: device.Network.Address.DracIPs.Migration[0].Netmask, }, Gateway: migShutdown.InfoItem{ Old: device.Network.Address.DracIPs.Source[0].Gateway, New: device.Network.Address.DracIPs.Migration[0].Gateway, }, } } // TODO: something func publicInfo(_ tools.Device) *migShutdown.IPInfo { return nil } func vlanMap(device tools.Device) map[string]string { if len(device.Network.Vlans) == 0 { return nil } ret := make(map[string]string) for _, vlan := range device.Network.Vlans { if vlan.Source.VlanNumber == 0 || vlan.Migration.VlanNumber == 0 { continue } ret[strconv.Itoa(vlan.Source.VlanNumber)] = strconv.Itoa(vlan.Migration.VlanNumber) } return ret } // pPrint func will take a structured type of response data and render a table // output to stdout. func pPrint(device int, resp *migShutdown.Response, err error) { fmt.Printf("%d Results:\n", device) fmt.Println("-------------------------") if err != nil { fmt.Printf("Error: %s\n", err) return } fmt.Printf("Response Msg: %s\n", resp.Result) fmt.Printf("Updated Device: %s\n", strconv.FormatBool(resp.UpdatedDevice)) fmt.Printf("Used Peer Config: %s\n", strconv.FormatBool(resp.UsedPeerConfig)) fmt.Printf("Diff:\n%s", resp.Diff) fmt.Print("\n") }