// addRawDisk adds storage in form of a raw disk to a server // @client: authenticated CLCv2 client // @servname: server name // @diskGB: amount of storage in GB to add to @servname func addRawDisk(client *clcv2.CLIClient, servname string, diskGB uint32) (statusId string) { /* First get the list of disks */ server, err := client.GetServer(servname) if err != nil { exit.Fatalf("failed to list details of server %q: %s", servname, 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, } } statusId, err = client.ServerSetDisks(servname, append(disks, clcv2.ServerAdditionalDisk{ SizeGB: diskGB, Type: "raw", })) if err != nil { exit.Fatalf("failed to update the disk configuration on %q: %s", servname, err) } return statusId }
// Print group hierarchy starting at @g, using initial indentation @indent. func printGroupIPs(client *clcv2.CLIClient, root *clcv2.Group) { var serverPrinter = func(g *clcv2.Group, arg interface{}) interface{} { var indent = arg.(string) if g.Type == "default" { fmt.Printf("%s%s/\n", indent, g.Name) } else { fmt.Printf("%s[%s]/\n", indent, g.Name) } for _, l := range g.Links { if l.Rel == "server" { ips, err := client.GetServerIPs(l.Id) if err != nil { exit.Fatalf("failed to get IPs of %q in %s: %s", l.Id, g.Name, err) } servLine := fmt.Sprintf("%s%s", indent+" ", l.Id) fmt.Printf("%-50s %s\n", servLine, strings.Join(ips, ", ")) } } return indent + " " } clcv2.VisitGroupHierarchy(root, serverPrinter, "") }
// Print server IP(s) // @client: authenticated CLCv2 Client // @servname: server name func printServerIP(client *clcv2.CLIClient, servname string) { ips, err := client.GetServerIPs(servname) if err != nil { exit.Fatalf("failed get server %q IPs: %s", servname, err) } fmt.Printf("%-20s %s\n", servname+":", strings.Join(ips, ", ")) }
// showTemplates prints the templates available in @region func showTemplates(client *clcv2.CLIClient, region string) { capa, err := client.GetDeploymentCapabilities(region) if err != nil { exit.Fatalf("failed to query deployment capabilities of %s: %s", region, err) } table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(false) /* Note: not displaying ReservedDrivePaths and DrivePathLength here, I don't understand their use. */ /* Note: not listing Capabilities here, since the table gets too large for a single screen */ table.SetHeader([]string{"Template Name", "Description", "OS", "Storage"}) for _, tpl := range capa.Templates { table.Append([]string{tpl.Name, tpl.Description, tpl.OsType, fmt.Sprintf("%d GB", tpl.StorageSizeGB)}) } table.Render() }
// showNetworks shows available networks in data centre location @location. func showNetworks(client *clcv2.CLIClient, location string) { networks, err := client.GetNetworks(location) if err != nil { exit.Fatalf("failed to list networks in %s: %s", location, err) } if len(networks) == 0 { println("Empty result.") } else { table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(false) table.SetHeader([]string{"CIDR", "Gateway", "VLAN", "Name", "Description", "Type", "ID"}) for _, l := range networks { table.Append([]string{l.Cidr, l.Gateway, fmt.Sprint(l.Vlan), l.Name, l.Description, l.Type, l.Id}) } table.Render() } }
// Show condensed details of multiple servers // @client: authenticated CLCv2 Client // @servnames: server names func showServers(client *clcv2.CLIClient, servnames ...string) { var truncate = func(s string, maxlen int) string { if len(s) >= maxlen { s = s[:maxlen] } return s } table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(true) table.SetHeader([]string{ "Name", "Group", "Description", "OS", "IP", "CPU", "Mem", "Storage", "Status", "Last Change", }) for _, servname := range servnames { server, err := client.GetServer(servname) if err != nil { fmt.Fprintf(os.Stderr, "Failed to list details of server %q: %s", servname, err) continue } grp, err := client.GetGroup(server.GroupId) if err != nil { exit.Fatalf("failed to resolve %s group UUID: %s", servname, err) } IPs := []string{} for _, ip := range server.Details.IpAddresses { if ip.Public != "" { IPs = append(IPs, ip.Public) } if ip.Internal != "" { IPs = append(IPs, ip.Internal) } } status := server.Details.PowerState if server.Details.InMaintenanceMode { status = "MAINTENANCE" } else if server.Status != "active" { status = server.Status } desc := server.Description if server.IsTemplate { desc = "TPL: " + desc } modifiedStr := humanize.Time(server.ChangeInfo.ModifiedDate) /* The ModifiedBy field can be an email address, or an API Key (hex string) */ if _, err := hex.DecodeString(server.ChangeInfo.ModifiedBy); err == nil { modifiedStr += " via API Key" } else { modifiedStr += " by " + truncate(server.ChangeInfo.ModifiedBy, 6) } // Append a tilde (~) to indicate it has snapshots serverName := server.Name if len(server.Details.Snapshots) > 0 { serverName += "~" } table.Append([]string{ serverName, grp.Name, truncate(desc, 30), truncate(server.OsType, 15), strings.Join(IPs, " "), fmt.Sprint(server.Details.Cpu), fmt.Sprintf("%d G", server.Details.MemoryMb/1024), fmt.Sprintf("%d G", server.Details.StorageGb), status, modifiedStr, }) } table.Render() }
// Show details of a single server // @client: authenticated CLCv2 Client // @servname: server name func showServer(client *clcv2.CLIClient, servname string) { server, err := client.GetServer(servname) if err != nil { exit.Fatalf("failed to list details of server %q: %s", servname, err) } grp, err := client.GetGroup(server.GroupId) if err != nil { exit.Fatalf("failed to resolve group UUID: %s", err) } /* First public, then private */ IPs := []string{} for _, ip := range server.Details.IpAddresses { if ip.Public != "" { IPs = append(IPs, ip.Public) } } for _, ip := range server.Details.IpAddresses { if ip.Internal != "" { IPs = append(IPs, ip.Internal) } } table := tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(true) // CPU, Memory, IP and Power status are not filled in until the server reaches 'active' state. if server.Status == "active" { table.SetHeader([]string{ "Name", "Group", "Description", "OS", "CPU", "Mem", "IP", "Power", "Last Change", }) } else { table.SetHeader([]string{ "Name", "Group", "Description", "OS", "Status", "Owner", "Last Change", }) } modifiedStr := humanize.Time(server.ChangeInfo.ModifiedDate) /* The ModifiedBy field can be an email address, or an API Key (hex string) */ if _, err := hex.DecodeString(server.ChangeInfo.ModifiedBy); err == nil { modifiedStr += " via API Key" } else if len(server.ChangeInfo.ModifiedBy) > 6 { modifiedStr += " by " + server.ChangeInfo.ModifiedBy[:6] } else { modifiedStr += " by " + server.ChangeInfo.ModifiedBy } if server.Status == "active" { table.Append([]string{ server.Name, grp.Name, server.Description, server.OsType, fmt.Sprint(server.Details.Cpu), fmt.Sprintf("%d G", server.Details.MemoryMb/1024), strings.Join(IPs, " "), server.Details.PowerState, modifiedStr, }) } else { table.Append([]string{ server.Name, grp.Name, server.Description, server.OsType, server.Status, server.ChangeInfo.CreatedBy, modifiedStr, }) } table.Render() // Disks if len(server.Details.Disks) > 0 { fmt.Printf("\nDisks of %s (total storage: %d GB)\n", server.Name, server.Details.StorageGb) table = tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(true) table.SetHeader([]string{"Disk ID", "Disk Size/GB", "Paths"}) for _, d := range server.Details.Disks { table.Append([]string{d.Id, fmt.Sprint(d.SizeGB), strings.Join(d.PartitionPaths, ", ")}) } table.Render() } // Partitions if len(server.Details.Partitions) > 0 { fmt.Printf("\nPartitions of %s:\n", server.Name) table = tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetAutoWrapText(true) table.SetHeader([]string{"Partition Path", "Partition Size/GB"}) for _, p := range server.Details.Partitions { table.Append([]string{p.Path, fmt.Sprintf("%.1f", p.SizeGB)}) } table.Render() } // Snapshots if len(server.Details.Snapshots) > 0 { fmt.Println() table = tablewriter.NewWriter(os.Stdout) table.SetAutoFormatHeaders(false) table.SetAlignment(tablewriter.ALIGN_CENTRE) table.SetAutoWrapText(true) table.SetHeader([]string{fmt.Sprintf("Snapshots of %s", server.Name)}) for _, s := range server.Details.Snapshots { table.Append([]string{s.Name}) } table.Render() } }