func doHistory(c *cli.Context) { if len(c.Args()) == 0 { displayWrongNumOfArgsAndExit(c) } vename := c.Args().Get(0) path := "/ve/" + vename + "/history/" if len(c.String("from")) > 0 && len(c.String("to")) > 0 { _, err := lib.ParseArgTimestampFormat(c.String("from")) assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format") _, err = lib.ParseArgTimestampFormat(c.String("to")) assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format") path += c.String("from") + "/" + c.String("to") } else if c.Int("num-records") > 0 { path += strconv.Itoa(c.Int("num-records")) } else { displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments or --num-records flag argument. Please see '" + c.App.Name + " help " + c.Command.Name + "'") } resp, err := client.SendRequest("GET", path, nil) assert(err) if resp.StatusCode >= 400 { displayErrorAndExit(string(resp.Body)) } hst := lib.VeHistory{} assert(xml.Unmarshal(resp.Body, &hst)) assert(err) outputResult(c, hst, func(format string) { if c.Bool("verbose") { lib.PrintXMLStruct(hst) } else { tbl, err := prettytable.NewTable([]prettytable.Column{ {Header: "DATETIME"}, {Header: "CPU", AlignRight: true}, {Header: "MEMORY", AlignRight: true}, {Header: "DISK", AlignRight: true}, {Header: "BANDWIDTH", AlignRight: true}, {Header: "PUB_IPS", AlignRight: true}, {Header: "STATUS"}, }...) assert(err) if c.Bool("no-header") { tbl.NoHeader = true } for _, e := range hst.VeSnapshot { ts, _ := e.EventTimestamp.MarshalText() tbl.AddRow(ts, e.CPU, e.RAM, e.LocalDisk, e.Bandwidth, e.NoOfPublicIP, e.State) } tbl.Print() } }) }
func doUsage(c *cli.Context) { if len(c.Args()) == 0 { displayWrongNumOfArgsAndExit(c) } vename := c.Args().Get(0) if len(c.String("from")) == 0 || len(c.String("to")) == 0 { displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments. Please see '" + c.App.Name + " help " + c.Command.Name + "'") } path := "/ve/" + vename + "/usage/" from, err := lib.ParseArgTimestampFormat(c.String("from")) assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format") to, err := lib.ParseArgTimestampFormat(c.String("to")) assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format") path += c.String("from") + "/" + c.String("to") resp, err := client.SendRequest("GET", path, nil) assert(err) if resp.StatusCode >= 400 { displayErrorAndExit(string(resp.Body)) } usage := lib.VeResourceUsageReport{} assert(xml.Unmarshal(resp.Body, &usage)) outputResult(c, usage, func(format string) { if c.Bool("verbose") { lib.PrintXMLStruct(usage) } else { fmt.Println("RESOURCE USAGE REPORT") fmt.Printf("Server: %s\n", usage.VeName) fmt.Printf(" From: %s\n", from.Format(lib.DataTimestampFormat)) fmt.Printf(" To: %s\n\n", to.Format(lib.DataTimestampFormat)) tbl, err := prettytable.NewTable([]prettytable.Column{ {Header: "RESOURCE_TYPE"}, {Header: "USAGE", AlignRight: true}, }...) assert(err) for _, e := range usage.ResourceUsage { name := e.ResourceType if len(e.ResourceUsageType) > 0 { name += "(" + e.ResourceUsageType + ")" } tbl.AddRow(name, e.Value) } for _, e := range usage.VeTraffic { tbl.AddRow(e.TrafficType, e.Used) } tbl.Print() } }) }
func doBackupList(c *cli.Context) { if len(c.Args()) == 0 { displayWrongNumOfArgsAndExit(c) } vename := c.Args().Get(0) if len(c.String("from")) == 0 || len(c.String("to")) == 0 { displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments. Please see '" + c.App.Name + " help " + c.Command.Name + "'") } path := "/ve/" + vename + "/backups/" from, err := lib.ParseArgTimestampFormat(c.String("from")) assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format") to, err := lib.ParseArgTimestampFormat(c.String("to")) assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format") path += c.String("from") + "/" + c.String("to") resp, err := client.SendRequest("GET", path, nil) assert(err) if resp.StatusCode >= 400 { displayErrorAndExit(string(resp.Body)) } backups := lib.VeBackups{} assert(xml.Unmarshal(resp.Body, &backups)) outputResult(c, backups, func(format string) { if c.Bool("verbose") { lib.PrintXMLStruct(backups) } else { fmt.Println("BACKUP LIST") fmt.Printf("Server: %s\n", vename) fmt.Printf(" From: %s\n", from.Format(lib.DataTimestampFormat)) fmt.Printf(" To: %s\n\n", to.Format(lib.DataTimestampFormat)) tbl, err := prettytable.NewTable([]prettytable.Column{ {Header: "ID"}, {Header: "SCHEDULE"}, {Header: "START"}, {Header: "END"}, {Header: "RESULT", AlignRight: true}, {Header: "SIZE(GB)", AlignRight: true}, {Header: "NODE"}, {Header: "DESCRIPTION"}, }...) assert(err) for _, e := range backups.Backup { schedule := "-" if len(e.ScheduleName) > 0 { schedule = e.ScheduleName } result := "fail" if e.Successful == true { result = "ok" } size := strconv.FormatFloat(float64(e.BackupSize)/(1<<30), 'f', 3, 64) tbl.AddRow(e.CloudBackupID, schedule, e.Started, e.Ended, result, size, e.BackupNodeName, e.Description) } tbl.Print() } }) }
func doAutoscaleHistory(c *cli.Context) { if len(c.Args()) == 0 { displayWrongNumOfArgsAndExit(c) } vename := c.Args().Get(0) path := "/ve/" + vename + "/autoscale/history/" if len(c.String("from")) > 0 && len(c.String("to")) > 0 { _, err := lib.ParseArgTimestampFormat(c.String("from")) assert(err, "'from' arg value must be in "+lib.ArgTimestampFormatStr()+" format") _, err = lib.ParseArgTimestampFormat(c.String("to")) assert(err, "'to' arg value must be in "+lib.ArgTimestampFormatStr()+" format") path += c.String("from") + "/" + c.String("to") var q []string if c.Int("average-period") > 0 { q = append(q, "average-period="+strconv.Itoa(c.Int("average-period"))) } if c.Int("tail") > 0 { q = append(q, "tail="+strconv.Itoa(c.Int("tail"))) } if len(q) > 0 { path += "?" + strings.Join(q, "&") } } else if c.Int("num-records") > 0 { path += strconv.Itoa(c.Int("num-records")) } else { displayErrorAndExit("This command must be used with a pair of --from and --to flags arguments or --num-records flag argument. Please see '" + c.App.Name + " help " + c.Command.Name + "'") } resp, err := client.SendRequest("GET", path, nil) assert(err) if resp.StatusCode >= 400 { displayErrorAndExit(string(resp.Body)) } hst := lib.ResourceConsumptionAndAutoscaleHistory{} assert(xml.Unmarshal(resp.Body, &hst)) assert(err) outputResult(c, hst, func(format string) { if c.Bool("verbose") { lib.PrintXMLStruct(hst) } else { if len(hst.AutoscaleRule) > 0 { fmt.Println("AUTOSCALE RULE HISTORY") tbl, err := prettytable.NewTable([]prettytable.Column{ {Header: "METRIC"}, {Header: "VERSION", AlignRight: true}, {Header: "UPDATED"}, {Header: "DELIVERED"}, {Header: "DELIVERED-OK"}, {Header: "MIGRATION"}, {Header: "RESTART"}, {Header: "MIN", AlignRight: true}, {Header: "MAX", AlignRight: true}, {Header: "STEP", AlignRight: true}, {Header: "UP_THRES", AlignRight: true}, {Header: "UP_PERIOD", AlignRight: true}, {Header: "DOWN_THRES", AlignRight: true}, {Header: "DOWN_PERIOD", AlignRight: true}, }...) assert(err) if c.Bool("no-header") { tbl.NoHeader = true } for _, e := range hst.AutoscaleRule { tbl.AddRow( e.Metric, *e.Version, *e.Updated, *e.UpdateDelivered, *e.UpdateDeliveredOk, *e.AllowMigration, *e.AllowRestart, e.Limits.Min, e.Limits.Max, e.Limits.Step, *e.Thresholds.Up.Threshold, e.Thresholds.Up.Period, *e.Thresholds.Down.Threshold, e.Thresholds.Down.Period, ) } tbl.Print() fmt.Println() } fmt.Println("RESOURCE CONSUMPTION") tbl, err := prettytable.NewTable([]prettytable.Column{ {Header: "CPU_USAGE", AlignRight: true}, {Header: "RAM_USAGE", AlignRight: true}, {Header: "PRIV_IN", AlignRight: true}, {Header: "PRIV_OUT", AlignRight: true}, {Header: "PUB_IN", AlignRight: true}, {Header: "PUB_OUT", AlignRight: true}, {Header: "DATETIME"}, {Header: "CPU", AlignRight: true}, {Header: "RAM", AlignRight: true}, {Header: "BANDWIDTH", AlignRight: true}, }...) assert(err) if c.Bool("no-header") { tbl.NoHeader = true } for _, e := range hst.ResourceConsumptionSample { tbl.AddRow( e.CPUUsage, e.RAMUsage, e.PrivateIncomingTraffic, e.PrivateOutgoingTraffic, e.PublicIncomingTraffic, e.PublicOutgoingTraffic, e.PaciTimestamp, e.CPU, e.RAM, e.Bandwidth, ) } tbl.Print() } }) }
} var noCustomNsFlag = cli.BoolFlag{ Name: "no-custom-ns", Usage: "Specify not to keep modification to name server\n\tsetting in the server", } var numRecordsFlag = cli.IntFlag{ Name: "num-records, n", Value: 10, Usage: "Specify a number of records API should return", } var fromDatetimeFlag = cli.StringFlag{ Name: "from, f", Usage: "Specify history start date and time in\n\t" + lib.ArgTimestampFormatStr() + " format", } var toDatetimeFlag = cli.StringFlag{ Name: "to, t", Usage: "Specify history end date and time in\n\t" + lib.ArgTimestampFormatStr() + " format", } var settingFlag = cli.StringFlag{ Name: "setting-file, s", Usage: "Specify a file path which contains server setting", } var subscriptionIDFlag = cli.IntFlag{ Name: "subscription-id, s", Usage: "Specify a subscription ID number",