Example #1
0
// restartIdentifiers resolves server IDs, restarts, and waits for them to be ready (-w)
func restartIdentifiers(ctx CommandContext, wait bool, servers []string, cr chan string) {
	var wg sync.WaitGroup
	for _, needle := range servers {
		wg.Add(1)
		go func(needle string) {
			defer wg.Done()
			server := ctx.API.GetServerID(needle)
			res := server
			err := ctx.API.PostServerAction(server, "reboot")
			if err != nil {
				if err.Error() != "server is being stopped or rebooted" {
					logrus.Errorf("failed to restart server %s: %s", server, err)
				}
				res = ""
			} else {
				if wait {
					// FIXME: handle gateway
					api.WaitForServerReady(ctx.API, server, "")
				}
			}
			cr <- res
		}(needle)
	}
	wg.Wait()
	close(cr)
}
Example #2
0
// GetTotalUsedFds Returns the number of used File Descriptors by
// reading it via /proc filesystem.
func GetTotalUsedFds() int {
	if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
		logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
	} else {
		return len(fds)
	}
	return -1
}
Example #3
0
// DeleteServerSafe tries to delete a server using multiple ways
func (a *ScalewayAPI) DeleteServerSafe(serverID string) error {
	// FIXME: also delete attached volumes and ip address
	err := a.DeleteServer(serverID)
	if err == nil {
		logrus.Infof("Server '%s' successfuly deleted", serverID)
		return nil
	}

	err = a.PostServerAction(serverID, "terminate")
	if err == nil {
		logrus.Infof("Server '%s' successfuly terminated", serverID)
		return nil
	}

	logrus.Errorf("Failed to delete server %s", serverID)
	logrus.Errorf("Try to run 'scw rm %s' later", serverID)
	return err
}
Example #4
0
func showResolverResults(needle string, results ScalewayResolverResults) error {
	log.Errorf("Too many candidates for %s (%d)", needle, len(results))

	w := tabwriter.NewWriter(os.Stderr, 20, 1, 3, ' ', 0)
	defer w.Flush()
	sort.Sort(results)
	for _, result := range results {
		fmt.Fprintf(w, "- %s\t%s\t%s\n", result.TruncIdentifier(), result.CodeName(), result.Name)
	}
	return nil
}
Example #5
0
// DeleteServerSafe tries to delete a server using multiple ways
func (a *ScalewayAPI) DeleteServerSafe(serverID string) error {
	// FIXME: also delete attached volumes and ip address
	// FIXME: call delete and stop -t in parallel to speed up process
	err := a.DeleteServer(serverID)
	if err == nil {
		logrus.Infof("Server '%s' successfuly deleted", serverID)
		return nil
	}

	err = a.PostServerAction(serverID, "terminate")
	if err == nil {
		logrus.Infof("Server '%s' successfuly terminated", serverID)
		return nil
	}

	// FIXME: retry in a loop until timeout or Control+C
	logrus.Errorf("Failed to delete server %s", serverID)
	logrus.Errorf("Try to run 'scw rm -f %s' later", serverID)
	return err
}
Example #6
0
// uploadSSHKeys uploads an SSH Key
func uploadSSHKeys(apiConnection *api.ScalewayAPI, newKey string) {
	user, err := apiConnection.GetUser()
	if err != nil {
		logrus.Errorf("Unable to contact ScalewayAPI: %s", err)
	} else {
		user.SSHPublicKeys = append(user.SSHPublicKeys, api.ScalewayKeyDefinition{Key: strings.Trim(newKey, "\n")})

		SSHKeys := api.ScalewayUserPatchSSHKeyDefinition{
			SSHPublicKeys: user.SSHPublicKeys,
		}

		userID, err := apiConnection.GetUserID()
		if err != nil {
			logrus.Errorf("Unable to get userID: %s", err)
		} else {
			if err = apiConnection.PatchUserSSHKey(userID, SSHKeys); err != nil {
				logrus.Errorf("Unable to patch SSHkey: %v", err)
			}
		}
	}
}
Example #7
0
// RunRmi is the handler for 'scw rmi'
func RunRmi(ctx CommandContext, args RmiArgs) error {
	hasError := false
	for _, needle := range args.Images {
		image := ctx.API.GetImageID(needle, true)
		err := ctx.API.DeleteImage(image)
		if err != nil {
			logrus.Errorf("failed to delete image %s: %s", image, err)
			hasError = true
		} else {
			fmt.Fprintln(ctx.Stdout, needle)
		}
	}
	if hasError {
		return fmt.Errorf("at least 1 image failed to be removed")
	}
	return nil
}
Example #8
0
// RunRm is the handler for 'scw rm'
func RunRm(ctx CommandContext, args RmArgs) error {
	hasError := false
	for _, needle := range args.Servers {
		server := ctx.API.GetServerID(needle)
		err := ctx.API.DeleteServer(server)
		if err != nil {
			logrus.Errorf("failed to delete server %s: %s", server, err)
			hasError = true
		} else {
			fmt.Fprintln(ctx.Stdout, needle)
		}
	}
	if hasError {
		return fmt.Errorf("at least 1 server failed to be removed")
	}
	return nil
}
Example #9
0
// RunWait is the handler for 'scw wait'
func RunWait(ctx CommandContext, args WaitArgs) error {
	hasError := false
	for _, needle := range args.Servers {
		serverIdentifier := ctx.API.GetServerID(needle)

		_, err := api.WaitForServerStopped(ctx.API, serverIdentifier)
		if err != nil {
			logrus.Errorf("failed to wait for server %s: %v", serverIdentifier, err)
			hasError = true
		}
	}

	if hasError {
		return fmt.Errorf("at least 1 server failed to be stopped")
	}
	return nil
}
Example #10
0
// RunRestart is the handler for 'scw restart'
func RunRestart(ctx CommandContext, args RestartArgs) error {
	hasError := false
	for _, needle := range args.Servers {
		server := ctx.API.GetServerID(needle)
		err := ctx.API.PostServerAction(server, "reboot")
		if err != nil {
			if err.Error() != "server is being stopped or rebooted" {
				logrus.Errorf("failed to restart server %s: %s", server, err)
				hasError = true
			}
		} else {
			fmt.Fprintln(ctx.Stdout, needle)
		}
		if hasError {
			return fmt.Errorf("at least 1 server failed to restart")
		}
	}
	return nil
}
Example #11
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
}
Example #12
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
}
Example #13
0
// RunStop is the handler for 'scw stop'
func RunStop(ctx CommandContext, args StopArgs) error {
	// FIXME: parallelize stop when stopping multiple servers
	hasError := false
	for _, needle := range args.Servers {
		serverID := ctx.API.GetServerID(needle)
		action := "poweroff"
		if args.Terminate {
			action = "terminate"
		}
		err := ctx.API.PostServerAction(serverID, action)
		if err != nil {
			if err.Error() != "server should be running" && err.Error() != "server is being stopped or rebooted" {
				logrus.Warningf("failed to stop server %s: %s", serverID, err)
				hasError = true
			}
		} else {
			if args.Wait {
				// We wait for 10 seconds which is the minimal amount of time needed for a server to stop
				time.Sleep(10 * time.Second)
				_, err = api.WaitForServerStopped(ctx.API, serverID)
				if err != nil {
					logrus.Errorf("failed to wait for server %s: %v", serverID, err)
					hasError = true
				}
			}
			if args.Terminate {
				ctx.API.Cache.RemoveServer(serverID)
			}
			fmt.Fprintln(ctx.Stdout, needle)
		}
	}

	if hasError {
		return fmt.Errorf("at least 1 server failed to be stopped")
	}
	return nil
}
Example #14
0
// RunLogin is the handler for 'scw login'
func RunLogin(ctx CommandContext, args LoginArgs) error {
	if args.Organization == "" || args.Token == "" {
		var err error

		args.Organization, args.Token, err = connectAPI()
		if err != nil {
			return err
		}
	}

	cfg := &config.Config{
		ComputeAPI:   api.ComputeAPI,
		AccountAPI:   api.AccountAPI,
		Organization: strings.Trim(args.Organization, "\n"),
		Token:        strings.Trim(args.Token, "\n"),
	}

	apiConnection, err := api.NewScalewayAPI(cfg.ComputeAPI, cfg.AccountAPI, cfg.Organization, cfg.Token)
	if err != nil {
		return fmt.Errorf("Unable to create ScalewayAPI: %s", err)
	}
	err = apiConnection.CheckCredentials()
	if err != nil {
		return fmt.Errorf("Unable to contact ScalewayAPI: %s", err)
	}
	if !args.SkipSSHKey {
		if err := selectKey(&args); err != nil {
			logrus.Errorf("Unable to select a key: %v", err)
		} else {
			if args.SSHKey != "" {
				uploadSSHKeys(apiConnection, args.SSHKey)
			}
		}
	}
	return cfg.Save()
}
Example #15
0
// InspectIdentifiers inspects identifiers concurrently
func InspectIdentifiers(api *ScalewayAPI, ci chan ScalewayResolvedIdentifier, cj chan InspectIdentifierResult) {
	var wg sync.WaitGroup
	for {
		idents, ok := <-ci
		if !ok {
			break
		}
		if len(idents.Identifiers) != 1 {
			if len(idents.Identifiers) == 0 {
				log.Errorf("Unable to resolve identifier %s", idents.Needle)
			} else {
				showResolverResults(idents.Needle, idents.Identifiers)
			}
		} else {
			ident := idents.Identifiers[0]
			wg.Add(1)
			go func() {
				if ident.Type == IdentifierServer {
					server, err := api.GetServer(ident.Identifier)
					if err == nil {
						cj <- InspectIdentifierResult{
							Type:   ident.Type,
							Object: server,
						}
					}
				} else if ident.Type == IdentifierImage {
					image, err := api.GetImage(ident.Identifier)
					if err == nil {
						cj <- InspectIdentifierResult{
							Type:   ident.Type,
							Object: image,
						}
					}
				} else if ident.Type == IdentifierSnapshot {
					snap, err := api.GetSnapshot(ident.Identifier)
					if err == nil {
						cj <- InspectIdentifierResult{
							Type:   ident.Type,
							Object: snap,
						}
					}
				} else if ident.Type == IdentifierVolume {
					volume, err := api.GetVolume(ident.Identifier)
					if err == nil {
						cj <- InspectIdentifierResult{
							Type:   ident.Type,
							Object: volume,
						}
					}
				} else if ident.Type == IdentifierBootscript {
					bootscript, err := api.GetBootscript(ident.Identifier)
					if err == nil {
						cj <- InspectIdentifierResult{
							Type:   ident.Type,
							Object: bootscript,
						}
					}
				}
				wg.Done()
			}()
		}
	}
	wg.Wait()
	close(cj)
}
Example #16
0
// RunInspect is the handler for 'scw inspect'
func RunInspect(ctx CommandContext, args InspectArgs) error {
	nbInspected := 0
	ci := make(chan api.ScalewayResolvedIdentifier)
	cj := make(chan api.InspectIdentifierResult)
	go api.ResolveIdentifiers(ctx.API, args.Identifiers, ci)
	go api.InspectIdentifiers(ctx.API, ci, cj)

	if args.Browser {
		// --browser will open links in the browser
		for {
			data, isOpen := <-cj
			if !isOpen {
				break
			}

			switch data.Type {
			case api.IdentifierServer:
				err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/servers/%s", data.Object.(*api.ScalewayServer).Identifier))
				if err != nil {
					return fmt.Errorf("cannot open browser: %v", err)
				}
				nbInspected++
			case api.IdentifierImage:
				err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/images/%s", data.Object.(*api.ScalewayImage).Identifier))
				if err != nil {
					return fmt.Errorf("cannot open browser: %v", err)
				}
				nbInspected++
			case api.IdentifierVolume:
				err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/volumes/%s", data.Object.(*api.ScalewayVolume).Identifier))
				if err != nil {
					return fmt.Errorf("cannot open browser: %v", err)
				}
				nbInspected++
			case api.IdentifierSnapshot:
				logrus.Errorf("Cannot use '--browser' option for snapshots")
			case api.IdentifierBootscript:
				logrus.Errorf("Cannot use '--browser' option for bootscripts")
			}
		}

	} else {
		// without --browser option, inspect will print object info to the terminal
		res := "["
		for {
			data, isOpen := <-cj
			if !isOpen {
				break
			}
			if args.Format == "" {
				dataB, err := json.MarshalIndent(data.Object, "", "  ")
				if err == nil {
					if nbInspected != 0 {
						res += ",\n"
					}
					res += string(dataB)
					nbInspected++
				}
			} else {
				tmpl, err := template.New("").Funcs(api.FuncMap).Parse(args.Format)
				if err != nil {
					return fmt.Errorf("format parsing error: %v", err)
				}

				err = tmpl.Execute(ctx.Stdout, data.Object)
				if err != nil {
					return fmt.Errorf("format execution error: %v", err)
				}
				fmt.Fprint(ctx.Stdout, "\n")
				nbInspected++
			}
		}
		res += "]"

		if args.Format == "" {
			if ctx.Getenv("SCW_SENSITIVE") != "1" {
				res = ctx.API.HideAPICredentials(res)
			}
			fmt.Fprintln(ctx.Stdout, res)
		}
	}

	if len(args.Identifiers) != nbInspected {
		return fmt.Errorf("at least 1 item failed to be inspected")
	}
	return nil
}