示例#1
0
// RunRestart is the handler for 'scw restart'
func RunRestart(ctx CommandContext, args RestartArgs) error {
	if args.Wait && args.Timeout > 0 {
		go func() {
			time.Sleep(time.Duration(args.Timeout*1000) * time.Millisecond)
			// FIXME: avoid use of fatalf
			logrus.Fatalf("Operation timed out")
		}()
	}

	cr := make(chan string)
	go restartIdentifiers(ctx, args.Wait, args.Servers, cr)
	done := false
	hasError := false

	for !done {
		select {
		case uuid, more := <-cr:
			if !more {
				done = true
				break
			}
			if len(uuid) > 0 {
				fmt.Fprintln(ctx.Stdout, uuid)
			} else {
				hasError = true
			}
		}
	}

	if hasError {
		return fmt.Errorf("at least 1 server failed to restart")
	}
	return nil
}
示例#2
0
文件: main.go 项目: ebfe/scaleway-cli
func main() {
	ec, err := cli.Start(os.Args[1:], nil)
	if err != nil {
		logrus.Fatalf("%s", err)
	}
	os.Exit(ec)
}
示例#3
0
// GetBootscriptID returns exactly one bootscript matching or dies
func (s *ScalewayAPI) GetBootscriptID(needle string) string {
	// Parses optional type prefix, i.e: "bootscript:name" -> "name"
	_, needle = parseNeedle(needle)

	bootscripts, err := s.ResolveBootscript(needle)
	if err != nil {
		log.Fatalf("Unable to resolve bootscript %s: %s", needle, err)
	}
	if len(bootscripts) == 1 {
		return bootscripts[0].Identifier
	}
	if len(bootscripts) == 0 {
		log.Fatalf("No such bootscript: %s", needle)
	}

	showResolverResults(needle, bootscripts)
	os.Exit(1)
	return ""
}
示例#4
0
// GetSnapshotID returns exactly one snapshot matching or dies
func (s *ScalewayAPI) GetSnapshotID(needle string) string {
	// Parses optional type prefix, i.e: "snapshot:name" -> "name"
	_, needle = parseNeedle(needle)

	snapshots, err := s.ResolveSnapshot(needle)
	if err != nil {
		log.Fatalf("Unable to resolve snapshot %s: %s", needle, err)
	}
	if len(snapshots) == 1 {
		return snapshots[0].Identifier
	}
	if len(snapshots) == 0 {
		log.Fatalf("No such snapshot: %s", needle)
	}

	showResolverResults(needle, snapshots)
	os.Exit(1)
	return ""
}
示例#5
0
// GetImageID returns exactly one image matching or dies
func (s *ScalewayAPI) GetImageID(needle string, exitIfMissing bool) string {
	// Parses optional type prefix, i.e: "image:name" -> "name"
	_, needle = parseNeedle(needle)

	images, err := s.ResolveImage(needle)
	if err != nil {
		log.Fatalf("Unable to resolve image %s: %s", needle, err)
	}
	if len(images) == 1 {
		return images[0].Identifier
	}
	if len(images) == 0 {
		if exitIfMissing {
			log.Fatalf("No such image: %s", needle)
		} else {
			return ""
		}
	}

	showResolverResults(needle, images)
	os.Exit(1)
	return ""
}
示例#6
0
func promptUser(prompt string, output *string, echo bool) {
	// FIXME: should use stdin/stdout from command context
	fmt.Fprintf(os.Stdout, prompt)
	os.Stdout.Sync()

	if !echo {
		b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
		if err != nil {
			logrus.Fatalf("Unable to prompt for password: %s", err)
		}
		*output = string(b)
		fmt.Fprintf(os.Stdout, "\n")
	} else {
		reader := bufio.NewReader(os.Stdin)
		*output, _ = reader.ReadString('\n')
	}
}
示例#7
0
// GetIdentifier returns a an identifier if the resolved needles only match one element, else, it exists the program
func GetIdentifier(api *ScalewayAPI, needle string) *ScalewayResolverResult {
	idents := ResolveIdentifier(api, needle)

	if len(idents) == 1 {
		return &idents[0]
	}
	if len(idents) == 0 {
		log.Fatalf("No such identifier: %s", needle)
	}
	log.Errorf("Too many candidates for %s (%d)", needle, len(idents))

	sort.Sort(idents)
	for _, identifier := range idents {
		// FIXME: also print the name
		fmt.Fprintf(os.Stderr, "- %s\n", identifier.Identifier)
	}
	os.Exit(1)
	return nil
}
示例#8
0
// RunStart is the handler for 'scw start'
func RunStart(ctx CommandContext, args StartArgs) error {
	hasError := false
	errChan := make(chan error)
	successChan := make(chan bool)
	remainingItems := len(args.Servers)

	for _, needle := range args.Servers {
		go api.StartServerOnce(ctx.API, needle, args.Wait, successChan, errChan)
	}

	if args.Timeout > 0 {
		go func() {
			time.Sleep(time.Duration(args.Timeout*1000) * time.Millisecond)
			// FIXME: avoid use of fatalf
			logrus.Fatalf("Operation timed out")
		}()
	}

	for {
		select {
		case _ = <-successChan:
			remainingItems--
		case err := <-errChan:
			logrus.Errorf(fmt.Sprintf("%s", err))
			remainingItems--
			hasError = true
		}

		if remainingItems == 0 {
			break
		}
	}
	if hasError {
		return fmt.Errorf("at least 1 server failed to start")
	}
	return nil
}
示例#9
0
func runHelp(cmd *Command, rawArgs []string) error {
	if waitHelp {
		return cmd.PrintUsage()
	}
	if len(rawArgs) > 1 {
		return cmd.PrintShortUsage()
	}

	if len(rawArgs) == 1 {
		name := rawArgs[0]
		for _, command := range Commands {
			if command.Name() == name {
				return command.PrintUsage()
			}
		}
		logrus.Fatalf("Unknown help topic `%s`.  Run 'scw help'.", name)
	} else {
		t := template.New("top")
		template.Must(t.Parse(helpTemplate))
		ctx := cmd.GetContext(rawArgs)
		return t.Execute(ctx.Stdout, Commands)
	}
	return nil
}
示例#10
0
func runPatch(cmd *Command, args []string) error {
	if patchHelp {
		return cmd.PrintUsage()
	}
	if len(args) != 2 {
		return cmd.PrintShortUsage()
	}

	// Parsing FIELD=VALUE
	updateParts := strings.SplitN(args[1], "=", 2)
	if len(updateParts) != 2 {
		return cmd.PrintShortUsage()
	}
	fieldName := updateParts[0]
	newValue := updateParts[1]

	changes := 0

	ident := api.GetIdentifier(cmd.API, args[0])
	switch ident.Type {
	case api.IdentifierServer:
		currentServer, err := cmd.API.GetServer(ident.Identifier)
		if err != nil {
			log.Fatalf("Cannot get server %s: %v", ident.Identifier, err)
		}

		var payload api.ScalewayServerPatchDefinition

		switch fieldName {
		case "state_detail":
			log.Debugf("%s=%s  =>  %s=%s", fieldName, currentServer.StateDetail, fieldName, newValue)
			if currentServer.StateDetail != newValue {
				changes++
				payload.StateDetail = &newValue
			}
		case "name":
			log.Warnf("To rename a server, Use 'scw rename'")
			log.Debugf("%s=%s  =>  %s=%s", fieldName, currentServer.StateDetail, fieldName, newValue)
			if currentServer.Name != newValue {
				changes++
				payload.Name = &newValue
			}
		case "bootscript":
			log.Debugf("%s=%s  =>  %s=%s", fieldName, currentServer.Bootscript.Identifier, fieldName, newValue)
			if currentServer.Bootscript.Identifier != newValue {
				changes++
				payload.Bootscript.Identifier = newValue
			}
		case "security_group":
			log.Debugf("%s=%s  =>  %s=%s", fieldName, currentServer.SecurityGroup.Identifier, fieldName, newValue)
			if currentServer.SecurityGroup.Identifier != newValue {
				changes++
				payload.SecurityGroup.Identifier = newValue
			}
		case "tags":
			newTags := strings.Split(newValue, " ")
			log.Debugf("%s=%s  =>  %s=%s", fieldName, currentServer.Tags, fieldName, newTags)
			// fixme test equality with reflect.DeepEqual ?
			changes++
			payload.Tags = &newTags
		default:
			log.Fatalf("'_patch server %s=' not implemented", fieldName)
		}
		// FIXME: volumes, tags, dynamic_ip_required

		if changes > 0 {
			log.Debugf("updating server: %d change(s)", changes)
			err = cmd.API.PatchServer(ident.Identifier, payload)
		} else {
			log.Debugf("no changes, not updating server")
		}
		if err != nil {
			log.Fatalf("Cannot update server: %v", err)
		}
	default:
		log.Fatalf("_patch not implemented for this kind of object")
	}
	fmt.Println(ident.Identifier)

	return nil
}
示例#11
0
// RunImages is the handler for 'scw images'
func RunImages(ctx CommandContext, args ImagesArgs) error {
	wg := sync.WaitGroup{}
	chEntries := make(chan api.ScalewayImageInterface)
	var entries = []api.ScalewayImageInterface{}

	filterType := args.Filters["type"]

	// FIXME: remove log.Fatalf in routines

	if filterType == "" || filterType == "image" {
		wg.Add(1)
		go func() {
			defer wg.Done()
			images, err := ctx.API.GetImages()
			if err != nil {
				logrus.Fatalf("unable to fetch images from the Scaleway API: %v", err)
			}
			for _, val := range *images {
				creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate)
				if err != nil {
					logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err)
				}
				chEntries <- api.ScalewayImageInterface{
					Type:         "image",
					CreationDate: creationDate,
					Identifier:   val.Identifier,
					Name:         val.Name,
					Public:       val.Public,
					Tag:          "latest",
					VirtualSize:  float64(val.RootVolume.Size),
					Organization: val.Organization,
				}
			}
		}()
	}

	if args.All || filterType != "" {
		if filterType == "" || filterType == "snapshot" {
			wg.Add(1)
			go func() {
				defer wg.Done()
				snapshots, err := ctx.API.GetSnapshots()
				if err != nil {
					logrus.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err)
				}
				for _, val := range *snapshots {
					creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate)
					if err != nil {
						logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err)
					}
					chEntries <- api.ScalewayImageInterface{
						Type:         "snapshot",
						CreationDate: creationDate,
						Identifier:   val.Identifier,
						Name:         val.Name,
						Tag:          "<snapshot>",
						VirtualSize:  float64(val.Size),
						Public:       false,
						Organization: val.Organization,
					}
				}
			}()
		}

		if filterType == "" || filterType == "bootscript" {
			wg.Add(1)
			go func() {
				defer wg.Done()
				bootscripts, err := ctx.API.GetBootscripts()
				if err != nil {
					logrus.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err)
				}
				for _, val := range *bootscripts {
					chEntries <- api.ScalewayImageInterface{
						Type:       "bootscript",
						Identifier: val.Identifier,
						Name:       val.Title,
						Tag:        "<bootscript>",
						Public:     false,
					}
				}
			}()
		}

		if filterType == "" || filterType == "volume" {
			wg.Add(1)
			go func() {
				defer wg.Done()
				volumes, err := ctx.API.GetVolumes()
				if err != nil {
					logrus.Fatalf("unable to fetch volumes from the Scaleway API: %v", err)
				}
				for _, val := range *volumes {
					creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate)
					if err != nil {
						logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err)
					}
					chEntries <- api.ScalewayImageInterface{
						Type:         "volume",
						CreationDate: creationDate,
						Identifier:   val.Identifier,
						Name:         val.Name,
						Tag:          "<volume>",
						VirtualSize:  float64(val.Size),
						Public:       false,
						Organization: val.Organization,
					}
				}
			}()
		}
	}

	go func() {
		wg.Wait()
		close(chEntries)
	}()

	done := false
	for {
		select {
		case entry, ok := <-chEntries:
			if !ok {
				done = true
				break
			}
			entries = append(entries, entry)
		}
		if done {
			break
		}
	}

	for key, value := range args.Filters {
		switch key {
		case "organization", "type", "name", "public":
			continue
		default:
			logrus.Warnf("Unknown filter: '%s=%s'", key, value)
		}
	}

	w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0)
	defer w.Flush()
	if !args.Quiet {
		fmt.Fprintf(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE\n")
	}
	sort.Sort(api.ByCreationDate(entries))
	for _, image := range entries {

		for key, value := range args.Filters {
			switch key {
			case "type":
				if value != image.Type {
					goto skipimage
				}
			case "organization":
				switch value {
				case "me":
					value = ctx.API.Organization
				case "official-distribs":
					value = "a283af0b-d13e-42e1-a43f-855ffbf281ab"
				case "official-apps":
					value = "c3884e19-7a3e-4b69-9db8-50e7f902aafc"
				}
				if image.Organization != value {
					goto skipimage
				}
			case "name":
				if fuzzy.RankMatch(strings.ToLower(value), strings.ToLower(image.Name)) == -1 {
					goto skipimage
				}
			case "public":
				if (value == "true" && !image.Public) || (value == "false" && image.Public) {
					goto skipimage
				}
			}
		}

		if args.Quiet {
			fmt.Fprintf(ctx.Stdout, "%s\n", image.Identifier)
		} else {
			tag := image.Tag
			shortID := utils.TruncIf(image.Identifier, 8, !args.NoTrunc)
			name := utils.Wordify(image.Name)
			if !image.Public && image.Type == "image" {
				name = "user/" + name
			}
			shortName := utils.TruncIf(name, 25, !args.NoTrunc)
			var creationDate, virtualSize string
			if image.CreationDate.IsZero() {
				creationDate = "n/a"
			} else {
				creationDate = units.HumanDuration(time.Now().UTC().Sub(image.CreationDate))
			}
			if image.VirtualSize == 0 {
				virtualSize = "n/a"
			} else {
				virtualSize = units.HumanSize(image.VirtualSize)
			}
			fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", shortName, tag, shortID, creationDate, virtualSize)
		}

	skipimage:
		continue
	}
	return nil
}
示例#12
0
func runCompletion(cmd *Command, args []string) error {
	if completionHelp {
		return cmd.PrintUsage()
	}
	if len(args) != 1 {
		return cmd.PrintShortUsage()
	}

	category := args[0]

	elements := []string{}

	switch category {
	case "servers-all":
		for identifier, name := range cmd.API.Cache.Servers {
			elements = append(elements, identifier, wordifyName(name, "server"))
		}
	case "servers-names":
		for _, name := range cmd.API.Cache.Servers {
			elements = append(elements, wordifyName(name, "server"))
		}
	case "images-all":
		for identifier, name := range cmd.API.Cache.Images {
			elements = append(elements, identifier, wordifyName(name, "image"))
		}
	case "images-names":
		for _, name := range cmd.API.Cache.Images {
			elements = append(elements, wordifyName(name, "image"))
		}
	case "volumes-all":
		for identifier, name := range cmd.API.Cache.Volumes {
			elements = append(elements, identifier, wordifyName(name, "volume"))
		}
	case "volumes-names":
		for _, name := range cmd.API.Cache.Volumes {
			elements = append(elements, wordifyName(name, "volume"))
		}
	case "snapshots-all":
		for identifier, name := range cmd.API.Cache.Snapshots {
			elements = append(elements, identifier, wordifyName(name, "snapshot"))
		}
	case "snapshots-names":
		for _, name := range cmd.API.Cache.Snapshots {
			elements = append(elements, wordifyName(name, "snapshot"))
		}
	case "bootscripts-all":
		for identifier, name := range cmd.API.Cache.Bootscripts {
			elements = append(elements, identifier, wordifyName(name, "bootscript"))
		}
	case "bootscripts-names":
		for _, name := range cmd.API.Cache.Bootscripts {
			elements = append(elements, wordifyName(name, "bootscript"))
		}
	default:
		logrus.Fatalf("Unhandled category of completion: %s", category)
	}

	sort.Strings(elements)
	fmt.Println(strings.Join(utils.RemoveDuplicates(elements), "\n"))

	return nil
}