// 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 linkeddevices import ( "fmt" "log" "os" "time" "github.rackspace.com/gorax/clients/migrationAPI" "github.com/jokelyo/argparse" "github.com/360EntSecGroup-Skylar/excelize" "github.com/jedib0t/go-pretty/v6/table" "github.com/sirupsen/logrus" "github.rackspace.com/DCM/gomigrate/core" "github.rackspace.com/DCM/gomigrate/shared" "github.rackspace.com/gorax/gokeys" ) const httpTimeout = 600 * time.Second var ( moveGroup *string csvFlag *bool ) // SubPlugin function will return a argparse.Command type back to the parent parser // nolint:typecheck func SubPlugin(p *argparse.Command) core.Plugin { // Create a command and argument for the colo trunks cmd := p.NewCommand("linked_devices", "Checks for sync issues between NSI and linked DB") moveGroup = shared.ArgMoveGroup(cmd) csvFlag = shared.ArgFlag(cmd, "csv", "Create a CSV results file") return core.Plugin{CMD: cmd, Func: pluginFunc} } // pluginFunc function will take a move group and return devices // that are in NSI but are no in environment manager func pluginFunc(cfg gokeys.Settings) { // Pull an identity token from the users gokeys keychain identKey, err := cfg.Identity(false) if err != nil { log.Fatalf("gokeys.Identity:%s", err) } if moveGroup == nil { log.Fatal("must specify a move-group") } c := migrationAPI.New(identKey.Password, false) coloResp := make([]migrationAPI.AuditResponse, 0) resp, err := c.AuditLinkedDevices( shared.GetCollection(*moveGroup), migrationAPI.NewOptions().SetHTTPTimeout(httpTimeout), ) if err != nil || resp == nil { logrus.Fatal(err) } coloResp = append(coloResp, *resp) pPrint(resp) if *csvFlag { if err := csv(coloResp, "Linked_Device_Audit", "Sheet1"); err != nil { logrus.Error(err) } } } // pPrint func will take a structured type of response data and render a table // output to stdout. func pPrint(data *migrationAPI.AuditResponse) { t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.AppendHeader(table.Row{"ID", "Account", "Reason"}) for _, d := range data.Data { t.AppendRow(table.Row{d.ID, d.AccountID, d.Reason}) } t.SortBy([]table.SortBy{{Name: "ID", Mode: table.AscNumeric}}) t.Render() } // Function to create a CSV of data on demands func csv(results []migrationAPI.AuditResponse, fileName, sheetName string) error { file := excelize.NewFile() index := file.NewSheet(sheetName) file.SetCellValue(sheetName, "A1", "Device ID") file.SetCellValue(sheetName, "B1", "Account Number") file.SetCellValue(sheetName, "C1", "Reason") row := 2 for _, r := range results { for _, v := range r.Data { file.SetCellValue(sheetName, fmt.Sprintf("A%d", row), v.ID) file.SetCellValue(sheetName, fmt.Sprintf("B%d", row), v.AccountID) file.SetCellValue(sheetName, fmt.Sprintf("C%d", row), v.Reason) row = row + 1 } } file.SetActiveSheet(index) if err := file.SaveAs(fmt.Sprintf("%s.xlsx", fileName)); err != nil { return err } logrus.Infof("csv file written to %s", fmt.Sprintf("%s.xlsx", fileName)) return nil }