func main() { var policies []clcv2.SBSServerPolicy var day = time.Now() var date = flag.String("start", day.Format("2006-01-02"), "Day to query storage usage for") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Server-Policy-ID | Server-Name>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(0) } day, err := time.Parse("2006-01-02", *date) if err != nil { exit.Error("invalid backup query date %s (expected format: YYYY-MM-DD)", *date) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } // First look up the corresponding Server Policy or Policies, since the query needs the Account Policy ID. if utils.LooksLikeServerName(flag.Arg(0)) { policies, err = client.SBSgetServerPolicyDetails(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list SBS policies for server %s: %s", flag.Arg(0), err) } } else { p, err := client.SBSgetServerPolicy(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list SBS Server Policy %s: %s", flag.Arg(0), err) } policies = []clcv2.SBSServerPolicy{*p} } table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_CENTRE) table.SetAutoWrapText(false) table.SetHeader([]string{"Server", fmt.Sprintf("Usage on %s", day.Format("Mon, Jan 2 2006")), "Server Policy ID", "Account Policy ID", }) for _, p := range policies { usage, err := client.SBSgetServerStorageUsage(p.AccountPolicyID, p.ID, day) if err != nil { exit.Fatalf("failed to obtain server %s storage use on %s: %s", p.ServerID, day.Format("2006-01-02"), err) } table.Append([]string{p.ServerID, humanize.Bytes(usage), p.ID, p.AccountPolicyID}) } table.Render() }
func main() { var policies []clcv2.SBSServerPolicy flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Server-Policy-ID | Server-Name>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(0) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if utils.LooksLikeServerName(flag.Arg(0)) { // Note: when using the server name instead of the Server Policy ID, sometimes the Status field is empty. policies, err = client.SBSgetServerPolicyDetails(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list SBS policies for server %s: %s", flag.Arg(0), err) } } else { // Query by Server Policy ID p, err := client.SBSgetServerPolicy(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list SBS Server Policy %s: %s", flag.Arg(0), err) } policies = []clcv2.SBSServerPolicy{*p} } if len(policies) == 0 { fmt.Printf("Nothing found for %s.\n", flag.Arg(0)) } else { table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(false) table.SetHeader([]string{"Server", "Server Policy ID", "Account Policy ID", "Status", "Region", "Account", "Unsubscribe Date", "Expiration Date"}) for _, p := range policies { table.Append([]string{p.ServerID, p.ID, p.AccountPolicyID, p.Status, p.StorageRegion, p.ClcAccountAlias, fmt.Sprint(p.UnsubscribedDate), fmt.Sprint(p.ExpirationDate)}) } table.Render() } }
func main() { var ( location = flag.String("l", os.Getenv("CLC_LOCATION"), "Data centre alias (needed to resolve IDs)") intvl = flag.Duration("i", 1*time.Second, "Poll interval for status updates (use 0 to disable)") handlingServer bool // what to act on action, where string // what to do and where reqID string // request ID of the action ) /* * Argument Validation */ flag.Usage = usage flag.Parse() if flag.NArg() >= 1 { action = flag.Arg(0) if flag.NArg() > 1 { where = flag.Arg(1) } } else { usage() } switch action { case "help": usage() case "networks", "templates", "show": // Omit location warning here, will be displayed after client is initialized. case "credentials": handlingServer = true case "memory": handlingServer = true if flag.NArg() != 3 { exit.Errorf("usage: password <serverName> <memoryGB>") } case "password": handlingServer = true if flag.NArg() < 2 { exit.Errorf("usage: password <serverName> [<new-password>]") } case "description": handlingServer = true if flag.NArg() < 2 { exit.Errorf("usage: description <serverName> <descriptive-text") } case "rawdisk": handlingServer = true if flag.NArg() != 3 { exit.Errorf("usage: rawdisk <serverName> <diskGB>") } case "mv": if flag.NArg() != 3 { exit.Errorf("usage: mv <server|group> <new-Group>") } case "mkdir": if flag.NArg() != 3 { exit.Errorf("usage: mkdir <parentGroup> <newGroupName>") } case "rename": if flag.NArg() != 3 { exit.Errorf("usage: rename <oldGroupName> <newGroupName>") } case "ip", "on", "start", "off", "shutdown", "stop", "pause", "reset", "reboot", "snapshot", "delsnapshot", "revert", "archive", "delete", "remove", "wait": /* FIXME: use map for usage, and use keys here, i.e. _, ok := map[action] */ if where == "" { exit.Errorf("Action %q requires an argument (try -h).", action) } default: exit.Errorf("Unsupported action %q", action) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if *location == "" { if action == "networks" || action == "show" || action == "templates" { fmt.Fprintf(os.Stderr, "Note: no location argument (-l) given, defaulting to %s.\n", client.LocationAlias) } *location = client.LocationAlias } if !handlingServer && action != "wait" { /* * Decide if arguments refer to a server or a hardware group. */ if _, err := hex.DecodeString(where); err == nil { /* If the first argument decodes as a hex value, assume it is a Hardware Group UUID */ } else if utils.LooksLikeServerName(where) { /* Starts with a location identifier and is not hex ... */ where = strings.ToUpper(where) handlingServer = true } else if *location != "" && where != "" { if group, err := client.GetGroupByName(where, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", where, err) } else if group == nil { exit.Errorf("No group named %q was found in %s", where, *location) } else { where = group.Id } } else if *location == "" { exit.Errorf("%q looks like a group name - need a location (-l argument) to resolve it.", where) } else { exit.Errorf("Unable to determine whether %q is a server or a group", where) } } if action == "templates" { /* where="" - neither server nor group action; print regional templates */ showTemplates(client, *location) os.Exit(0) } else if action == "networks" { /* similar, neither server nor group action; print regional networks */ showNetworks(client, *location) os.Exit(0) } else if action == "wait" { reqID = flag.Arg(1) } else if handlingServer { /* Server Action */ switch action { case "ip": printServerIP(client, where) os.Exit(0) case "show": // FIXME: deal with multiple servers if flag.NArg() == 2 { showServer(client, where) } else { showServers(client, flag.Args()[1:]...) } os.Exit(0) case "mv": var newParent = flag.Arg(2) if _, err := hex.DecodeString(newParent); err == nil { /* Looks like a Group UUID */ } else if *location == "" { exit.Errorf("Need a location argument (-l) if destination group (%s) is not a UUID", newParent) } else { if grp, err := client.GetGroupByName(newParent, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", newParent, err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", newParent, *location) } else { newParent = grp.Id } } if err = client.ServerSetGroup(where, newParent); err != nil { exit.Fatalf("failed to change the parent group on %q: %s", where, err) } fmt.Printf("Successfully changed the parent group of %s to %s.\n", where, flag.Arg(2)) os.Exit(0) case "memory": fmt.Printf("Setting %s memory to %s GB ...\n", where, flag.Arg(2)) reqID, err = client.ServerSetMemory(where, flag.Arg(2)) if err != nil { exit.Fatalf("failed to change the amount of Memory on %q: %s", where, err) } case "description": fmt.Printf("Setting %s description to to %q.\n", where, flag.Arg(2)) if err = client.ServerSetDescription(where, flag.Arg(2)); err != nil { exit.Fatalf("failed to change the description of %q: %s", where, err) } case "password": var newPassword string log.Printf("Looking up existing password of %s", where) credentials, err := client.GetServerCredentials(where) if err != nil { exit.Fatalf("failed to obtain the credentials of %q: %s", where, err) } log.Printf("Existing %s password: %q", where, credentials.Password) if flag.NArg() == 3 { newPassword = flag.Arg(2) } else if newPassword, err = garbler.NewPassword(&garbler.Paranoid); err != nil { exit.Fatalf("failed to generate new 'garbler' password: %s", err) } else { // The 'Paranoid' mode in garbler more than satisfies CLC requirements. // However, the symbols may contain unsupported characters. newPassword = strings.Map(func(r rune) rune { if strings.Index(clcv2.InvalidPasswordCharacters, string(r)) > -1 { return '@' } return r }, newPassword) log.Printf("New paranoid 'garbler' password: %q", newPassword) } if newPassword == credentials.Password { log.Printf("%s password is already set to %q", where, newPassword) os.Exit(0) } reqID, err = client.ServerChangePassword(where, credentials.Password, newPassword) if err != nil { exit.Fatalf("failed to change the password on %q: %s", where, err) } case "credentials": credentials, err := client.GetServerCredentials(where) if err != nil { exit.Fatalf("failed to obtain the credentials of server %q: %s", where, err) } fmt.Printf("Credentials for %s:\n", where) fmt.Printf("User: %s\n", credentials.Username) fmt.Printf("Password: \"%s\"\n", credentials.Password) os.Exit(0) case "rawdisk": diskGB, err := strconv.ParseUint(flag.Arg(2), 10, 32) if err != nil { exit.Errorf("rawdisk: invalid disk size in GB %q for %s", flag.Arg(2), where) } reqID = addRawDisk(client, where, uint32(diskGB)) default: var serverAction = map[string]func(string) (string, error){ "on": client.PowerOnServer, "start": client.PowerOnServer, // Alias "off": client.PowerOffServer, "pause": client.PauseServer, "reset": client.ResetServer, "reboot": client.RebootServer, "shutdown": client.ShutdownServer, "stop": client.ShutdownServer, // Alias "archive": client.ArchiveServer, "delete": client.DeleteServer, "remove": client.DeleteServer, // Alias "snapshot": client.SnapshotServer, "delsnapshot": client.DeleteSnapshot, "revert": client.RevertToSnapshot, } /* Long-running commands that return a RequestID */ handler, ok := serverAction[action] if !ok { exit.Fatalf("Unsupported server action %s", action) } reqID, err = handler(where) if err != nil { exit.Fatalf("Server command %q failed: %s", action, err) } } } else if action == "show" || action == "ip" { /* Printing group trees: requires to resolve the root first. */ var start *clcv2.Group if *location == "" { exit.Errorf("Location argument (-l) is required in order to traverse nested groups.") } root, err := client.GetGroups(*location) if err != nil { exit.Fatalf("failed to look up groups at %s: %s", *location, err) } start = &root if where != "" { start = clcv2.FindGroupNode(start, func(g *clcv2.Group) bool { return g.Id == where }) if start == nil { exit.Fatalf("failed to look up UUID %s in %s - is this the correct value?", where, *location) } } switch action { case "show": showGroup(client, start) case "ip": printGroupIPs(client, start) } os.Exit(0) } else { /* Other Group Action */ switch action { case "archive": reqID, err = client.ArchiveGroup(where) case "mkdir": g, err := client.CreateGroup(flag.Arg(2), where, flag.Arg(2), nil) if err == nil { fmt.Printf("New subfolder of %s: %q (UUID: %s)\n", flag.Arg(1), g.Name, g.Id) } case "delete", "remove": reqID, err = client.DeleteGroup(where) case "mv": var newParent = flag.Arg(2) if _, err := hex.DecodeString(newParent); err == nil { /* Looks like a Group UUID */ } else if *location == "" { exit.Errorf("Need a location argument (-l) if destination group (%s) is not a UUID", newParent) } else { if grp, err := client.GetGroupByName(newParent, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", newParent, err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", newParent, *location) } else { newParent = grp.Id } } if err = client.GroupSetParent(where, newParent); err != nil { exit.Fatalf("failed to change the parent group on %q: %s", where, err) } fmt.Printf("Successfully changed the parent group of %s to %s.\n", where, flag.Arg(2)) os.Exit(0) case "rename": if err = client.GroupSetName(where, flag.Arg(2)); err == nil { fmt.Println("OK") } default: exit.Errorf("Unsupported group action %q", action) } if err != nil { exit.Fatalf("Group command %q failed: %s", action, err) } } if reqID != "" { client.PollStatus(reqID, *intvl) } }