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()
}
Beispiel #2
0
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()
	}
}
Beispiel #3
0
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)
	}
}