func main() { var parentUUID string var parentGroup = flag.String("g", "", "UUID or Name (if unique and -l present) of the parent Hardware Group") var location = flag.String("l", "", "Data centre location to use for resolving -g <Group-Name>") var desc = flag.String("t", "", "Textual description of the new group") var acctAlias = flag.String("a", "", "Account alias to use") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <New Group Name>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *parentGroup == "" { flag.Usage() os.Exit(1) } /* parentGroup may be hex uuid or group name */ if _, err := hex.DecodeString(*parentGroup); err == nil { parentUUID = *parentGroup } else if *location == "" { exit.Errorf("Using -g <Group-Name> requires -l <Location> to be set") } client, err := clcv1.NewClient(log.New(os.Stdout, "", log.LstdFlags|log.Ltime)) if err != nil { exit.Fatal(err.Error()) } else if err := client.Logon("", ""); err != nil { exit.Fatalf("Login failed: %s", err) } if parentUUID == "" { if group, err := client.GetGroupByName(*parentGroup, *location, *acctAlias); err != nil { exit.Errorf("Failed to resolve group name %q: %s", *parentGroup, err) } else if group == nil { exit.Errorf("No group named %q was found on %s", *parentGroup, *location) } else { parentUUID = group.UUID } } g, err := client.CreateHardwareGroup(*acctAlias, parentUUID, flag.Arg(0), *desc) if err != nil { exit.Fatalf("Failed to create hardware group %q: %s", flag.Arg(0), err) } fmt.Println("New Group: ", g.Name) fmt.Println("UUID: ", g.UUID) }
func main() { var location = flag.String("l", "", "The location of the deployment to retrieve status for (required)") var pollIntvl = flag.Int("i", 1, "Poll interval in seconds (to monitor progress") var acctAlias = flag.String("a", "", "Account alias to use") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Request-ID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *location == "" { flag.Usage() os.Exit(1) } reqId, err := strconv.ParseUint(flag.Arg(0), 10, 32) if err != nil { exit.Errorf("Invalid Request ID %q: %s", flag.Arg(0), err) } client, err := clcv1.NewClient(log.New(os.Stdout, "", log.LstdFlags|log.Ltime)) if err != nil { exit.Fatal(err.Error()) } else if err := client.Logon("", ""); err != nil { exit.Fatalf("Login failed: %s", err) } err = client.PollDeploymentStatus(int(reqId), *location, *acctAlias, *pollIntvl) if err != nil { exit.Fatalf("Failed to poll status of request ID %d: %s", reqId, err) } }
func main() { var location = flag.String("l", "", "Alias of the data centre the server resides in") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <IP Address>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *location == "" { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } iad, err := client.GetNetworkDetailsByIp(flag.Arg(0), *location) if err != nil { exit.Fatalf("failed to look up %s: %s", flag.Arg(0), err) } else if iad == nil { exit.Errorf("No match found for %s in %s", flag.Arg(0), *location) } // The 'Server' field is not necessarily filled in, hence we need to test here. if iad.Server != "" { fmt.Printf("%s is used by %s.\n", iad.Address, iad.Server) } else { fmt.Printf("%s is in %s use in %s, but the server name is not disclosed.\n", iad.Address, iad.Type, *location) } }
func main() { var size = flag.Uint("size", 0, "New size of the disk in GB") // Allow the same ID types as in disk_remove.go var reMajMin = regexp.MustCompile(`^\d+:\d+$`) var reMin = regexp.MustCompile(`^\d+$`) var id string flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Server-Name> <Disk-ID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 2 || *size == 0 { flag.Usage() os.Exit(1) } else if reMajMin.MatchString(flag.Arg(1)) { id = flag.Arg(1) } else if reMin.MatchString(flag.Arg(1)) { id = fmt.Sprintf("0:%s", flag.Arg(1)) } else { exit.Errorf("invalid disk ID %q", flag.Arg(1)) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } server, err := client.GetServer(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list details of server %q: %s", flag.Arg(0), err) } disks := make([]clcv2.ServerAdditionalDisk, len(server.Details.Disks)) for i := range server.Details.Disks { disks[i] = clcv2.ServerAdditionalDisk{ Id: server.Details.Disks[i].Id, SizeGB: server.Details.Disks[i].SizeGB, } if disks[i].Id == id { // The API does not allow to reduce the size of an existing disk. if uint32(*size) <= disks[i].SizeGB { fmt.Printf("Disk %s size is already at %d GB.\n", id, disks[i].SizeGB) os.Exit(0) } fmt.Printf("Changing disk %s size from %d to %d GB ...\n", id, disks[i].SizeGB, *size) disks[i].SizeGB = uint32(*size) } } reqID, err := client.ServerSetDisks(flag.Arg(0), disks) if err != nil { exit.Fatalf("failed to update the disk configuration on %q: %s", flag.Arg(0), err) } log.Printf("Status Id for resizing the disk on %s: %s", flag.Arg(0), reqID) client.PollStatus(reqID, 10*time.Second) }
func main() { var parentGroup = flag.String("g", "", "UUID or Name (if unique and -l present) of the parent Hardware Group") var location = flag.String("l", "", "Data centre location to use for resolving -g <Group-Name>") var desc = flag.String("t", "", "Textual description of the new group") var parentUUID string flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <New Group Name>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *parentGroup == "" { flag.Usage() os.Exit(1) } /* parentGroup may be hex uuid or group name */ if _, err := hex.DecodeString(*parentGroup); err == nil { parentUUID = *parentGroup } else if *location == "" { exit.Errorf("Using -g <Group-Name> requires -l <Location> to be set") } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if parentUUID == "" { /* resolve group name */ if group, err := client.GetGroupByName(*parentGroup, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", *parentGroup, err) } else if group == nil { exit.Errorf("No group named %q was found in %s", *parentGroup, *location) } else { parentUUID = group.Id } } g, err := client.CreateGroup(flag.Arg(0), parentUUID, *desc, []clcv2.SimpleCustomField{}) if err != nil { exit.Fatalf("failed to create hardware group %q: %s", flag.Arg(0), err) } fmt.Println("New Group: ", g.Name) fmt.Println("UUID: ", g.Id) }
func main() { // Allow two types of ID: (a) <major>:<minor> syntax, (b) <minor> syntax var reMajMin = regexp.MustCompile(`^\d+:\d+$`) var reMin = regexp.MustCompile(`^\d+$`) var ids []string flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Server Name> <diskId> [<diskId> ...]\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() < 2 { flag.Usage() os.Exit(1) } for i := 1; i < flag.NArg(); i++ { if reMajMin.MatchString(flag.Arg(i)) { ids = append(ids, flag.Arg(i)) } else if reMin.MatchString(flag.Arg(i)) { ids = append(ids, fmt.Sprintf("0:%s", flag.Arg(i))) } else { exit.Errorf("invalid disk ID %q", flag.Arg(i)) } } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } server, err := client.GetServer(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list details of server %q: %s", flag.Arg(0), err) } disks := make([]clcv2.ServerAdditionalDisk, 0) for i := range server.Details.Disks { if inStringArray(server.Details.Disks[i].Id, ids...) { fmt.Printf("Deleting disk %s (%d GB) ...\n", server.Details.Disks[i].Id, server.Details.Disks[i].SizeGB) } else { disks = append(disks, clcv2.ServerAdditionalDisk{ Id: server.Details.Disks[i].Id, SizeGB: server.Details.Disks[i].SizeGB, }) } } reqID, err := client.ServerSetDisks(flag.Arg(0), disks) if err != nil { exit.Fatalf("failed to update the disk configuration on %q: %s", flag.Arg(0), err) } log.Printf("Status Id for updating the disks on %s: %s", flag.Arg(0), reqID) client.PollStatus(reqID, 5*time.Second) }
func main() { var hwGroup = flag.String("g", "", "UUID or name (if unique) of the HW group to restore this group to") var location = flag.String("l", "", "Data centre alias (to resolve group and/or network ID)") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <HW Group UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *hwGroup == "" { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } /* hwGroup may be hex uuid or group name */ if _, err := hex.DecodeString(*hwGroup); err == nil { /* already looks like a HEX ID */ } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using a HW Group UUID (%s)", *hwGroup) } else { fmt.Printf("Resolving ID of Hardware Group %q ...\n", *hwGroup) if group, err := client.GetGroupByName(*hwGroup, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", *hwGroup, err) } else if group == nil { exit.Errorf("No group named %q was found in %s", *hwGroup, *location) } else { *hwGroup = group.Id } } statusId, err := client.RestoreGroup(flag.Arg(0), *hwGroup) if err != nil { exit.Fatalf("failed to restore group %s: %s", flag.Arg(0), err) } fmt.Println("Request ID for restoring group:", statusId) }
func main() { var uuid string /* UUID of the HW group to delete */ var location = flag.String("l", "", "Data center location if using HW Group-Name") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <HW Group-Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } /* If the first argument decodes as a hex value, assume it is a Hardware Group UUID */ if _, err := hex.DecodeString(flag.Arg(0)); err == nil { uuid = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location (-l argument) when not using a HW Group UUID") } else { fmt.Printf("Resolving group UUID of %s in %s ...\n", flag.Arg(0), *location) if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { uuid = grp.Id } } reqId, err := client.DeleteGroup(uuid) if err != nil { exit.Fatalf("failed to delete hardware group: %s", err) } fmt.Printf("Status ID for group deletion: %s\n", reqId) }
func main() { var ( query = flag.String("q", "none", "Filter IP addresses; one of 'none', 'claimed', 'free', or 'all'") location = flag.String("l", os.Getenv("CLC_LOCATION"), "Data centre alias (needed to resolve IDs)") simple = flag.Bool("simple", false, "Use simple (debugging) output format") ) flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] -l <Location> <Network-ID (hex)>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() /* Location is required (despite hex id), an empty location leads to a "404 Not Found" response. */ if flag.NArg() != 1 || *location == "" { flag.Usage() os.Exit(1) } else if !inStringArray(*query, "none", "claimed", "free", "all") { exit.Errorf("Invalid IP query %q. Try -h") } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } details, err := client.GetNetworkDetails(*location, flag.Arg(0), *query) if err != nil { exit.Fatalf("failed to query network details of %s: %s", flag.Arg(0), err) } if *simple { pretty.Println(details) } else { fmt.Printf("Details of %s (%s):\n", details.Name, details.Description) fmt.Printf("CIDR: %s\n", details.Cidr) fmt.Printf("Gateway: %s\n", details.Gateway) fmt.Printf("Type: %s\n", details.Type) fmt.Printf("VLAN: %d\n", details.Vlan) if len(details.IpAddresses) > 0 { table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(false) table.SetHeader([]string{"Address", "Claimed", "Server", "Type"}) for _, i := range details.IpAddresses { table.Append([]string{i.Address, fmt.Sprint(i.Claimed), i.Server, i.Type}) } table.Render() } } }
func main() { var group = flag.String("g", "", "UUID or name of the new parent group") var location = flag.String("l", "", "Location to use if -g refers to a Group-Name") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <server-name>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *group == "" { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(*group); err == nil { /* Looks like a Group UUID */ } else if *location == "" { exit.Errorf("Need a location argument (-l) if -g (%s) is not a UUID", *group) } else { if grp, err := client.GetGroupByName(*group, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", *group, err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", *group, *location) } else { *group = grp.Id } } err = client.ServerSetGroup(flag.Arg(0), *group) if err != nil { exit.Fatalf("failed to change the parent group on %q: %s", flag.Arg(0), err) } fmt.Printf("Successfully changed the parent group of %s to %s.\n", flag.Arg(0), *group) }
func main() { var location = flag.String("l", "", "Location to use if using a Group-Name instead of a UUID") var uuid string flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(flag.Arg(0)); err == nil { uuid = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { uuid = grp.Id } } statusId, err := client.ArchiveGroup(uuid) if err != nil { exit.Fatalf("failed to archive group %s: %s", flag.Arg(0), err) } fmt.Println("Request ID for archiving group:", statusId) }
func main() { var group string /* UUID of the group to change */ var newName = flag.String("n", "", "New name for the group") var location = flag.String("l", "", "Location to use if using a Group-Name instead of a UUID") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *newName == "" { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(flag.Arg(0)); err == nil { group = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { group = grp.Id } } if err = client.GroupSetName(group, *newName); err != nil { exit.Fatalf("failed to change the name of %q: %s", flag.Arg(0), err) } fmt.Printf("Successfully changed the name of %s to %q.\n", flag.Arg(0), *newName) }
// Collapse an unsorted array @in of IPv4 addresses into sorted ranges in @out. func CollapseIpRanges(in []string) (out []string) { var start, end, prev net.IP var ips []net.IP for _, ip_string := range in { ip := net.ParseIP(ip_string) if ip == nil { exit.Errorf("Invalid IP address %q", ip_string) } ip = ip.To4() if ip == nil { exit.Errorf("Not an IPv4 address: %q", ip_string) } ips = append(ips, ip) } sort.Stable(byIPv4Address(ips)) for _, ip := range ips { if prev != nil && reflect.DeepEqual(ip[:3], prev[:3]) && ip[3] == prev[3]+1 { end = ip } else { if end != nil { out = append(out, fmt.Sprintf("%s-%d", start, end[3])) end = nil } else if prev != nil { out = append(out, prev.String()) } start = ip } prev = ip } if end != nil { out = append(out, fmt.Sprintf("%s-%d", start, end[3])) } return out }
func main() { var child string /* UUID of the group to relocate */ var parent = flag.String("g", "", "UUID or name of the new parent group") var location = flag.String("l", "", "Location to use if using Group Name instead of UUID") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *parent == "" { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(flag.Arg(0)); err == nil { child = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { child = grp.Id } } if _, err := hex.DecodeString(*parent); err == nil { /* Looks like a Group UUID */ } else if *location == "" { exit.Errorf("Need a location argument (-l) if parent (-g %s) is not a UUID", *parent) } else { if grp, err := client.GetGroupByName(*parent, *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", *parent, err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", *parent, *location) } else { *parent = grp.Id } } err = client.GroupSetParent(child, *parent) if err != nil { exit.Fatalf("failed to change the parent group of %q: %s", flag.Arg(0), err) } fmt.Printf("Successfully changed the parent group of %s to %s.\n", flag.Arg(0), *parent) }
func main() { var acctAlias = flag.String("a", "", "Account alias of the account in question") var location = flag.String("l", "", "Data center location of @Group-Name") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group-Name>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 || *location == "" { flag.Usage() os.Exit(1) } client, err := clcv1.NewClient(log.New(os.Stdout, "", log.LstdFlags|log.Ltime)) if err != nil { exit.Fatal(err.Error()) } else if err := client.Logon("", ""); err != nil { exit.Fatalf("Login failed: %s", err) } groups, err := client.GetGroups(*location, *acctAlias) if err != nil { exit.Fatalf("Failed to obtain hardware groups: %s", err) } if len(groups) == 0 { exit.Errorf("Empty result.") } table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(true) table.SetHeader([]string{"Name", "UUID", "Parent UUID", "System Group?"}) for _, g := range groups { if g.Name == flag.Arg(0) { table.Append([]string{g.Name, g.UUID, g.ParentUUID, fmt.Sprint(g.IsSystemGroup)}) } } table.Render() }
// Show group details // @client: authenticated CLCv1 Client // @uuid: hardware group UUID to use // @acctAlias: account alias to use (leave blank to use default) // @location: data centre location (needed to resolve @uuid) func showGroup(client *clcv1.Client, uuid, acctAlias, location string) { if location == "" { exit.Errorf("Location is required in order to show the group hierarchy starting at %s", uuid) } root, err := client.GetGroupHierarchy(location, acctAlias, true) if err != nil { exit.Fatalf("Failed to look up groups at %s: %s", location, err) } start := root if uuid != "" { start = clcv1.FindGroupNode(root, func(g *clcv1.GroupNode) bool { return g.UUID == uuid }) if start == nil { exit.Fatalf("Failed to look up UUID %s at %s", uuid, location) } } clcv1.PrintGroupHierarchy(start, "") }
func main() { var uuid string var simple = flag.Bool("simple", false, "Use simple (debugging) output format") var location = flag.String("l", "", "Location to use if using a Group-Name instead of a UUID") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(flag.Arg(0)); err == nil { uuid = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { uuid = grp.Id } } bd, err := client.GetGroupBillingDetails(uuid) if err != nil { exit.Fatalf("failed to query billing details of group %s: %s", flag.Arg(0), err) } if *simple { pretty.Println(bd) } else { var totalMonthTod, totalMonthEst float64 if rootGroup, ok := bd.Groups[uuid]; !ok { exit.Fatalf("Query result does not contain queried group %s", uuid) } else { fmt.Printf("Billing details of %s as of %s:\n", rootGroup.Name, bd.Date.Format("Monday, 2 Jan 2006, 15:04 MST")) } for k, v := range bd.Groups { if k == uuid || len(v.Servers) == 0 { continue } fmt.Printf("\nServer details of %q (%s):\n", v.Name, k) table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(true) table.SetHeader([]string{"Server", "Template Cost", "Archive Cost", "Current Hour", "Month to Date", "Monthly Estimate"}) for s, sbd := range v.Servers { table.Append([]string{strings.ToUpper(s), fmt.Sprintf("$%.2f", sbd.TemplateCost), fmt.Sprintf("$%.2f", sbd.ArchiveCost), fmt.Sprintf("$%.2f", sbd.CurrentHour), fmt.Sprintf("$%.2f", sbd.MonthToDate), fmt.Sprintf("$%.2f", sbd.MonthlyEstimate), }) totalMonthTod += sbd.MonthToDate totalMonthEst += sbd.MonthlyEstimate } table.Render() } fmt.Printf("\nTotal month to date: $%.2f\n", totalMonthTod) fmt.Printf("Total monthly estimate: $%.2f\n", totalMonthEst) } }
func main() { var uuid string var simple = flag.Bool("simple", false, "Use simple (debugging) output format") var location = flag.String("l", "", "Location to use if using a Group-Name instead of a UUID") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(flag.Arg(0)); err == nil { uuid = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { uuid = grp.Id } } rootNode, err := client.GetGroup(uuid) if err != nil { exit.Fatalf("failed to query HW group %s: %s", flag.Arg(0), err) } if *simple { pretty.Println(rootNode) } else { fmt.Printf("Group %q in %s:\n", rootNode.Name, rootNode.LocationId) fmt.Printf("ID: %s\n", rootNode.Id) fmt.Printf("Description: %s\n", rootNode.Description) fmt.Printf("Type: %s\n", rootNode.Type) fmt.Printf("Status: %s\n", rootNode.Status) if len(rootNode.CustomFields) > 0 { fmt.Println("Custom fields:", rootNode.CustomFields) } // ChangeInfo createdStr := humanize.Time(rootNode.ChangeInfo.CreatedDate) /* The CreatedBy field can be an email address, or an API Key (hex string) */ if _, err := hex.DecodeString(rootNode.ChangeInfo.CreatedBy); err == nil { createdStr += " via API Key" } else { createdStr += " by " + rootNode.ChangeInfo.CreatedBy } fmt.Printf("Created: %s\n", createdStr) modifiedStr := humanize.Time(rootNode.ChangeInfo.ModifiedDate) /* The ModifiedBy field can be an email address, or an API Key (hex string) */ if _, err := hex.DecodeString(rootNode.ChangeInfo.ModifiedBy); err == nil { modifiedStr += " via API Key" } else { modifiedStr += " by " + rootNode.ChangeInfo.ModifiedBy } fmt.Printf("Modified: %s\n", modifiedStr) // Servers fmt.Printf("#Servers: %d\n", rootNode.Serverscount) if rootNode.Serverscount > 0 { var servers []string if sl := clcv2.ExtractLinks(rootNode.Links, "server"); len(sl) > 0 { for _, s := range sl { servers = append(servers, s.Id) } fmt.Printf("Servers: %s\n", strings.Join(servers, ", ")) } } // Sub-groups if len(rootNode.Groups) > 0 { fmt.Printf("\nGroups of %s:\n", rootNode.Name) table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(true) table.SetHeader([]string{"Name", "UUID", "Description", "#Servers", "Type"}) for _, g := range rootNode.Groups { table.Append([]string{g.Name, g.Id, g.Description, fmt.Sprint(g.Serverscount), g.Type}) } table.Render() } else { fmt.Printf("Sub-groups: none\n") } } }
func main() { var net = flag.String("net", "", "ID or name of the Network to use (if different from source)") var hwGroup = flag.String("g", "", "UUID or name (if unique) of the HW group to clone this server into") var primDNS = flag.String("dns1", "8.8.8.8", "Primary DNS to use") var secDNS = flag.String("dns2", "8.8.4.4", "Secondary DNS to use") var numCpu = flag.Int("cpu", 0, "Number of Cpus to use (if different from source VM)") var memGB = flag.Int("memory", 0, "Amount of memory in GB (if different from source VM") var seed = flag.String("name", "", "The 4-6 character seed for the name of the cloned server") var desc = flag.String("desc", "", "Description of the cloned server") var ttl = flag.Duration("ttl", 0, "Time span (counting from time of creation) until server gets deleted") var extraDrv = flag.Int("drive", 0, "Extra storage (in GB) to add to server as a raw disk") var wasStopped bool var maxAttempts = 1 var url, reqID string flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Source-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()) } // First get the details of the source server log.Printf("Obtaining details of source server %s ...", flag.Arg(0)) src, err := client.GetServer(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list details of source server %q: %s", flag.Arg(0), err) } if wasStopped = src.Details.PowerState == "stopped"; wasStopped { // The source server must be powered on log.Printf("%s is powered-off - powering on ...", src.Name) reqID, err := client.PowerOnServer(src.Name) if err != nil { exit.Fatalf("failed to power on source server %s: %s", src.Name, err) } log.Printf("Waiting for %s to power on (status ID: %s) ...", src.Name, reqID) if _, err = client.AwaitCompletion(reqID); err != nil { exit.Fatalf("failed to await completion of %s: %s", reqID, err) } // When the server is being powered on, it can take up to 5 minutes until // the backend is able to clone it; it requires the server to be fully booted. maxAttempts = 5 time.Sleep(1 * time.Minute) } // We need the credentials, too log.Printf("Obtaining %s credentials ...", src.Name) credentials, err := client.GetServerCredentials(src.Name) if err != nil { exit.Fatalf("failed to obtain the credentials of server %q: %s", src.Name, err) } req := clcv2.CreateServerReq{ Name: *seed, Cpu: src.Details.Cpu, MemoryGB: src.Details.MemoryMb >> 10, GroupId: src.GroupId, SourceServerId: src.Name, PrimaryDns: *primDNS, SecondaryDns: *secDNS, Password: credentials.Password, SourceServerPassword: credentials.Password, Type: src.Type, } if *seed == "" { if l := len(src.Name); l > 10 { // use same naming as original by default req.Name = src.Name[7 : l-1] } else { req.Name = "CLONE" } } if *numCpu != 0 { req.Cpu = *numCpu } if *memGB != 0 { req.MemoryGB = *memGB } if *desc != "" { req.Description = *desc } else if src.Description == "" { req.Description = fmt.Sprintf("Clone of %s", src.Name) } else { req.Description = fmt.Sprintf("%s (cloned from %s)", src.Description, src.Name) } if *extraDrv != 0 { req.AdditionalDisks = append(req.AdditionalDisks, clcv2.ServerAdditionalDisk{SizeGB: uint32(*extraDrv), Type: "raw"}) } if *ttl != 0 { /* Date/time that the server should be deleted. */ req.Ttl = new(time.Time) *req.Ttl = time.Now().Add(*ttl) } /* hwGroup may be hex uuid or group name */ if *hwGroup != "" { req.GroupId = *hwGroup if _, err := hex.DecodeString(*hwGroup); err != nil { log.Printf("Resolving ID of Hardware Group %q in %s ...", *hwGroup, src.LocationId) if group, err := client.GetGroupByName(*hwGroup, src.LocationId); err != nil { exit.Fatalf("failed to resolve group name %q: %s", *hwGroup, err) } else if group == nil { exit.Errorf("No group named %q was found in %s", *hwGroup, src.LocationId) } else { req.GroupId = group.Id } } } /* net is supposed to be a (hex) ID, but allow network names, too */ if *net == "" { log.Printf("Determining network ID used by %s ...", src.Name) if nets, err := client.GetServerNets(src); err != nil { exit.Fatalf("failed to query networks of %s: %s", src.Name, err) } else if len(nets) == 0 { // No network information found for the server, even though it has an IP. // This can happen when the server is owned by a sub-account, and uses a // network that is owned by the parent account. In this case, the sub-account // is prevented from querying details of the parent account, due to insufficient // permission. log.Printf("Unable to determine network details - querying %s deployable networks ...", src.LocationId) capa, err := client.GetDeploymentCapabilities(src.LocationId) if err != nil { exit.Fatalf("failed to determine %s Deployment Capabilities: %s", src.LocationId, err) } fmt.Println("Please specify the network ID for the clone manually via -net, using this information:") table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(false) table.SetHeader([]string{"Name", "Type", "Account", "Network ID"}) for _, net := range capa.DeployableNetworks { table.Append([]string{net.Name, net.Type, net.AccountID, net.NetworkId}) } table.Render() os.Exit(0) } else if len(nets) != 1 { // FIXME: print server networks exit.Errorf("please specify which network to use (%s uses %d)", src.Name, len(nets)) } else { req.NetworkId = nets[0].Id } } else if _, err := hex.DecodeString(*net); err != nil { // not a HEX ID, treat as group name log.Printf("Resolving network ID of %q in %s ...", *net, src.LocationId) if netw, err := client.GetNetworkIdByName(*net, src.LocationId); err != nil { exit.Fatalf("failed to resolve network name %q: %s", *net, err) } else if netw == nil { exit.Fatalf("unable to resolve network name %q in %s - maybe use hex ID?", *net, src.LocationId) } else { req.NetworkId = netw.Id } } else { // HEX ID, use directoy req.NetworkId = *net } log.Printf("Cloning %s ...", src.Name) for i := 1; ; i++ { url, reqID, err = client.CreateServer(&req) if err == nil || i == maxAttempts || strings.Index(err.Error(), "body.sourceServerId") > 0 { break } log.Printf("attempt %d/%d failed (%s) - retrying ...", i, maxAttempts, strings.TrimSpace(err.Error())) time.Sleep(1 * time.Minute) } if err != nil { exit.Fatalf("failed to create server: %s", err) } log.Printf("Status Id: %s\n", reqID) status, err := client.PollStatus(reqID, 5*time.Second) if err != nil { exit.Fatalf("failed to poll %s status: %s", reqID, err) } server, err := client.GetServerByURI(url) if err != nil { log.Fatalf("failed to query server details at %s: %s", url, err) } else if status == clcv2.Failed { exit.Fatalf("failed to clone %s (will show up as 'under construction')", server.Name) } log.Printf("New server name: %s\n", server.Name) log.Printf("Server Password: \"%s\"\n", credentials.Password) }
func main() { var net = flag.String("net", "", "ID or name of the Network to use (required)") var location = flag.String("l", "", "Data centre alias (to resolve network name if not using hex ID)") var ip = flag.String("ip", "", "IP address on -net (optional, default is automatic assignment)") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <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()) } /* net is supposed to be a (hex) ID, but allow network names, too */ if *net != "" { if _, err := hex.DecodeString(*net); err == nil { /* already looks like a HEX ID */ } else { fmt.Printf("Resolving network id of %q ...\n", *net) if *location == "" { fmt.Printf("Querying location details of %s ...\n", flag.Arg(0)) src, err := client.GetServer(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list details of server %q: %s", flag.Arg(0), err) } *location = src.LocationId } if netw, err := client.GetNetworkIdByName(*net, *location); err != nil { exit.Errorf("failed to resolve network name %q: %s", *net, err) } else if netw == nil { exit.Errorf("no network named %q was found in %s", *net, *location) } else { *net = netw.Id } } } else { /* Network ID is mandatory for this request to complete. */ var IPs []string fmt.Println("This request requires a network ID via -net:") fmt.Printf("Querying details of %s ...\n", flag.Arg(0)) src, err := client.GetServer(flag.Arg(0)) if err != nil { exit.Fatalf("failed to list details of server %q: %s", flag.Arg(0), err) } *location = src.LocationId for _, ip := range src.Details.IpAddresses { if ip.Internal != "" { IPs = append(IPs, ip.Internal) } } fmt.Printf("%s current IP configuration: %s\n", flag.Arg(0), strings.Join(IPs, ", ")) fmt.Printf("Querying available networks in %s ...\n", *location) capa, err := client.GetDeploymentCapabilities(*location) if err != nil { exit.Fatalf("failed to determine deployable networks in %s: %s", *location, err) } fmt.Printf("These are the networks deployable in %s:\n", *location) table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(false) table.SetHeader([]string{"Name", "Type", "Account", "Network ID"}) for _, net := range capa.DeployableNetworks { table.Append([]string{net.Name, net.Type, net.AccountID, net.NetworkId}) } table.Render() exit.Errorf("please specify a network ID via -net (using the selection above).") } if err = client.ServerAddNic(flag.Arg(0), *net, *ip); err != nil { exit.Fatalf("failed to add NIC to %s: %s", flag.Arg(0), err) } fmt.Printf("Successfully added a secondary NIC to %s.\n", flag.Arg(0)) }
func main() { var group string /* UUID of the group to set defaults of */ var location = flag.String("l", "", "Location to use if using a Group-Name instead of a UUID") var template = flag.String("t", "", "Name of the template to use as the source") var numCpu = flag.Int("cpu", 1, "Number of Cpus to use (1-16)") var memGB = flag.Int("mem", 4, "Amount of memory in GB (1-128)") var net = flag.String("net", "", "Name of the Network to use") var primDNS = flag.String("dns1", "8.8.8.8", "Primary DNS to use") var secDNS = flag.String("dns2", "8.8.4.4", "Secondary DNS to use") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\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 _, err := hex.DecodeString(flag.Arg(0)); err == nil { group = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { fmt.Printf("Resolving group id of %q ...\n", flag.Arg(0)) if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { group = grp.Id } } if *net != "" { if _, err := hex.DecodeString(*net); err == nil { /* already looks like a HEX ID */ } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using a network ID (%s)", *net) } else { fmt.Printf("Resolving network id of %q ...\n", *net) if netw, err := client.GetNetworkIdByName(*net, *location); err != nil { exit.Errorf("failed to resolve network name %q: %s", *net, err) } else if netw == nil { exit.Errorf("No network named %q was found in %s", *net, *location) } else { *net = netw.Id } } } req := clcv2.GroupDefaults{ Cpu: *numCpu, MemoryGB: *memGB, NetworkId: *net, PrimaryDns: *primDNS, SecondaryDns: *secDNS, TemplateName: *template, } settings, err := client.SetGroupDefaults(group, &req) if err != nil { exit.Fatalf("failed to set group defaults of %s: %s", flag.Arg(0), err) } table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(false) table.SetHeader([]string{"Default", "Value", "Inherited"}) for k, v := range settings { table.Append([]string{strings.Title(k), fmt.Sprint(v.Value), fmt.Sprint(v.Inherited)}) } table.Render() }
func main() { var hwGroup = flag.String("g", "", "UUID or name (if unique) of the HW group to add this server to") var location = flag.String("l", "", "Data centre alias") var acctAlias = flag.String("a", "", "Account alias to use") var template = flag.String("t", "", "The name of the template to create the server from") var seed = flag.String("s", "AUTO", "The seed for the server name (max 6 characters)") var desc = flag.String("D", "", "Description of the server") var net = flag.String("net", "", "Name of the Network to use") var primDNS = flag.String("dns1", "8.8.8.8", "Primary DNS to use") var secDNS = flag.String("dns2", "8.8.4.4", "Secondary DNS to use") var password = flag.String("pass", "", "Desired password. Leave blank to auto-generate") var extraDrv = flag.Int("drive", 0, "Extra drive (in GB) to add to server. Set to 0 to leave out") var numCpu = flag.Int("cpu", 1, "Number of Cpus to use") var memGB = flag.Int("memory", 4, "Amount of memory in GB") var serverType = flag.Int("type", 1, "The type of server to create (1: Standard, 2: Enterprise)") var servLevel = flag.Int("level", 2, "Data storage service level (1: Premium, 2: Standard)") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options]\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if *hwGroup == "" || *location == "" || *template == "" || *seed == "" || *net == "" { flag.Usage() os.Exit(0) } client, err := clcv1.NewClient(log.New(os.Stdout, "", log.LstdFlags|log.Ltime)) if err != nil { exit.Fatal(err.Error()) } else if err := client.Logon("", ""); err != nil { exit.Fatalf("Login failed: %s", err) } req := clcv1.CreateServerReq{ // The alias of the account to own the server. // If not provided it will assume the account to which the API user is mapped. // Providing this value gives you the ability to create servers in your sub accounts. (optional) AccountAlias: *acctAlias, // The alias of the data center in which to create the server. // If not provided, will default to the API user's default data center. // NOTE: empty value can cause error if location is not the same as HWUUID's LocationAlias: *location, // The name of the template to create the server from (required) Template: *template, // The alias for the server. Limit 6 charcters (required) Alias: *seed, // An optional description for the server. If none is supplied the server name will be used. (optional) Description: *desc, // The unique identifier of the Hardware Group to add this server to (required) HardwareGroupUUID: *hwGroup, //The type of server to create (required) ServerType: *serverType, // The service level/performance for the underlying data store (required) ServiceLevel: *servLevel, // The number of processors to configure the server with (required) Cpu: *numCpu, // The number of GB of memory to configure the server with (required) MemoryGB: *memGB, // The size in GB of an additional drive to add to the server (required). // If no additional drive is needed, pass in a 0 value. ExtraDriveGB: *extraDrv, // The primary DNS to set on the server (optional) // If not supplied the default value set on the account will be used. PrimaryDns: *primDNS, // The secondary DNS to set on the server (optional) // If not supplied the default value set on the account will be used. SecondaryDns: *secDNS, // The name of the network to which to deploy the server. // If your account has not yet been assigned a network, leave this blank and one will be assigned automatically. // If one or more networks are available, the network name is required. Network: *net, // The desired Admin/Root password (optional). // Please note the password must meet the password strength policy. // Leave blank to have the system generate a password Password: *password, // A list of Custom Fields associated to this server // FIXME: not supported yet CustomFields: nil, } /* hwGroup may be hex uuid or group name */ if _, err := hex.DecodeString(*hwGroup); err != nil { if group, err := client.GetGroupByName(*hwGroup, *location, *acctAlias); err != nil { exit.Errorf("Failed to resolve group name %q: %s", *hwGroup, err) } else if group == nil { exit.Errorf("No group named %q was found on %s", *hwGroup, *location) } else { req.HardwareGroupUUID = group.UUID } } reqId, err := client.CreateServer(&req) if err != nil { exit.Fatalf("Failed to create server: %s", err) } fmt.Println("Request ID for server creation:", reqId) }
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) } }
func main() { var location = flag.String("l", "", "Location to use for <Group-Name>") var acctAlias = flag.String("a", "", "Account alias to use (to override default)") var serverAction bool var action, where string flag.Usage = usage flag.Parse() if flag.NArg() == 2 { action, where = flag.Arg(0), flag.Arg(1) } else if flag.NArg() == 1 && flag.Arg(0) == "show" { if *location == "" { exit.Errorf("Showing group details requires location (-l) argument.") } action = flag.Arg(0) } else { usage() } client, err := clcv1.NewClient(log.New(os.Stdout, "", log.LstdFlags|log.Ltime)) if err != nil { exit.Fatal(err.Error()) } else if err := client.Logon("", ""); err != nil { exit.Fatalf("Login failed: %s", err) } /* If the first argument decodes as a hex value, assume it is a Hardware Group UUID */ if _, err := hex.DecodeString(where); err == nil { serverAction = false } else if utils.LooksLikeServerName(where) { serverAction = true if *location != "" { fmt.Fprintf(os.Stderr, "WARNING: location (%s) ignored for %s\n", *location, where) } } else if *location != "" && where != "" { if group, err := client.GetGroupByName(where, *location, *acctAlias); 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 on %s", where, *location) } else { where = group.UUID } } else { serverAction = true } switch action { case "show": if serverAction { showServer(client, where, *acctAlias) } else { showGroup(client, where, *acctAlias, *location) } os.Exit(0) case "help": usage() } /* Long-running commands that return a RequestID */ handler, ok := actionMap(serverAction, client)[action] if !ok { exit.Fatalf("Unsupported action %s", action) } reqID, err := handler(where, *acctAlias) if err != nil { exit.Fatalf("Command %q failed: %s", action, err) } fmt.Printf("Request ID for %q action: %d\n", action, reqID) locationStr := *location if serverAction { locationStr = utils.ExtractLocationFromServerName(where) } client.PollDeploymentStatus(reqID, locationStr, *acctAlias, 1) }
func main() { var uuid string var simple = flag.Bool("simple", false, "Use simple (debugging) output format") var location = flag.String("l", "", "Location to use if using a Group-Name instead of a UUID") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Group Name or UUID>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if flag.NArg() != 1 { flag.Usage() os.Exit(1) } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } if _, err := hex.DecodeString(flag.Arg(0)); err == nil { uuid = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using Group UUID (%s)", flag.Arg(0)) } else { if grp, err := client.GetGroupByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve group name %q: %s", flag.Arg(0), err) } else if grp == nil { exit.Errorf("No group named %q was found in %s", flag.Arg(0), *location) } else { uuid = grp.Id } } sa, err := client.GetGroupScheduledActivities(uuid) if err != nil { exit.Fatalf("failed to query billing details of group %s: %s", flag.Arg(0), err) } if *simple { pretty.Println(sa) } else { table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(false) table.SetHeader([]string{"Type", "On?", "Exp?", "Repeat", "Expire", "Begin", "Next", "#Count", "Days", "Modified", }) for _, s := range sa { var beginStr, nextStr string modifiedStr := humanize.Time(s.ChangeInfo.ModifiedDate) /* The ModifiedBy field can be an email address, or an API Key (hex string) */ if _, err := hex.DecodeString(s.ChangeInfo.ModifiedBy); err == nil { modifiedStr += " via API Key" } else { modifiedStr += " by " + s.ChangeInfo.ModifiedBy } if s.BeginDateUtc.IsZero() { beginStr = "never" } else { beginStr = s.BeginDateUtc.In(time.Local).Format("Mon 2 Jan 15:04 MST") } if s.NextOccurrenceDateUtc.IsZero() { nextStr = "never" } else { nextStr = s.NextOccurrenceDateUtc.In(time.Local).Format("Mon 2 Jan 15:04 MST") } table.Append([]string{ s.Type, s.Status, fmt.Sprint(s.IsExpired), s.Repeat, s.Expire, beginStr, nextStr, fmt.Sprint(s.OccurrenceCount), strings.Join(s.CustomWeeklyDays, "/"), modifiedStr, }) } table.Render() } }
func main() { var netw string /* The network ID, name or CIDR to query */ var query = flag.String("q", "free", "Filter IP addresses; one of 'claimed', 'free', or 'all'") var location = flag.String("l", "", "Data centre alias of the network (required)") var simple = flag.Bool("simple", false, "Use simple (debugging) output format") flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: %s [options] <Network-ID|Network-Name|Network-CIDR>)>\n", path.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() /* It seems that Location is always required, even if using the hex ID of the network. */ if flag.NArg() != 1 || *location == "" { flag.Usage() os.Exit(1) } else if !inStringArray(*query, "claimed", "free", "all") { exit.Errorf("Invalid IP query %q. Try -h") } client, err := clcv2.NewCLIClient() if err != nil { exit.Fatal(err.Error()) } /* Allow argument to be one of hex-ID, CIDR, or network name. */ if _, err := hex.DecodeString(flag.Arg(0)); err == nil { netw = flag.Arg(0) } else if *location == "" { exit.Errorf("Need a location argument (-l) if not using a network ID (%s)", flag.Arg(0)) } else if _, _, err := net.ParseCIDR(flag.Arg(0)); err == nil { if network, err := client.GetNetworkIdByCIDR(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve network %s: %s", flag.Arg(0), err) } else if network == nil { exit.Errorf("No network of type %s was found in %s", flag.Arg(0), *location) } else { netw = network.Id } } else { if network, err := client.GetNetworkIdByName(flag.Arg(0), *location); err != nil { exit.Errorf("failed to resolve network name %q: %s", flag.Arg(0), err) } else if network == nil { exit.Errorf("No network named %q was found in %s", flag.Arg(0), *location) } else { netw = network.Id } } // Note: re-using the 'Get Network' call here. There seems to be no dedicated 'Get IP Address List' call. details, err := client.GetNetworkDetails(*location, netw, *query) if err != nil { exit.Fatalf("failed to query network details of %s: %s", netw, err) } if len(details.IpAddresses) == 0 { println("Empty result.") } else if *simple { pretty.Println(details) } else if *query == "free" { var freeIPs = clcv2.ExtractIPs(details.IpAddresses) fmt.Printf("%d free IP addresses on %s:\n", len(freeIPs), details.Cidr) for _, rng := range utils.CollapseIpRanges(freeIPs) { fmt.Println(rng) } } else { table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(false) switch *query { case "claimed": table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetHeader([]string{"Address", "Server"}) for _, i := range details.IpAddresses { table.Append([]string{i.Address, i.Server}) } case "all": table.SetHeader([]string{"Address", "Claimed", "Server", "Type"}) for _, i := range details.IpAddresses { table.Append([]string{i.Address, fmt.Sprint(i.Claimed), i.Server, i.Type}) } } table.Render() } }