Пример #1
0
// RunPort is the handler for 'scw port'
func RunPort(ctx CommandContext, args PortArgs) error {
	serverID := ctx.API.GetServerID(args.Server)
	server, err := ctx.API.GetServer(serverID)
	if err != nil {
		return fmt.Errorf("failed to get server information for %s: %v", serverID, err)
	}

	// Resolve gateway
	if args.Gateway == "" {
		args.Gateway = ctx.Getenv("SCW_GATEWAY")
	}
	var gateway string
	if args.Gateway == serverID || args.Gateway == args.Server {
		gateway = ""
	} else {
		gateway, err = api.ResolveGateway(ctx.API, args.Gateway)
		if err != nil {
			return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
		}
	}

	command := []string{"netstat -lutn 2>/dev/null | grep LISTEN"}
	err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway)
	if err != nil {
		return fmt.Errorf("command execution failed: %v", err)
	}

	return nil
}
Пример #2
0
func waitSSHConnection(ctx CommandContext, args RunArgs, serverID string) (chan notifSSHConnection, string, error) {
	notif := make(chan notifSSHConnection)
	// Resolve gateway
	gateway, err := api.ResolveGateway(ctx.API, args.Gateway)
	if err != nil {
		return nil, "", fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
	}

	// waiting for server to be ready
	logrus.Debug("Waiting for server to be ready")
	// We wait for 30 seconds, which is the minimal amount of time needed by a server to boot
	go func() {
		server, err := api.WaitForServerReady(ctx.API, serverID, gateway)
		if err != nil {
			notif <- notifSSHConnection{
				err: fmt.Errorf("cannot get access to server %s: %v", serverID, err),
			}
			return
		}
		logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP)
		logrus.Info("Server is ready !")
		notif <- notifSSHConnection{
			server: server,
		}
	}()
	return notif, gateway, nil
}
Пример #3
0
// RunTop is the handler for 'scw top'
func RunTop(ctx CommandContext, args TopArgs) error {
	serverID := ctx.API.GetServerID(args.Server)
	command := "ps"
	server, err := ctx.API.GetServer(serverID)
	if err != nil {
		return fmt.Errorf("failed to get server information for %s: %v", serverID, err)
	}

	// Resolve gateway
	if args.Gateway == "" {
		args.Gateway = ctx.Getenv("SCW_GATEWAY")
	}
	var gateway string
	if args.Gateway == serverID || args.Gateway == args.Server {
		gateway = ""
	} else {
		gateway, err = api.ResolveGateway(ctx.API, args.Gateway)
		if err != nil {
			return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
		}
	}

	sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, []string{command}, gateway)
	logrus.Debugf("Executing: %s", sshCommand)
	out, err := exec.Command("ssh", sshCommand.Slice()[1:]...).CombinedOutput()
	fmt.Printf("%s", out)
	return err
}
Пример #4
0
// RunLogs is the handler for 'scw logs'
func RunLogs(ctx CommandContext, args LogsArgs) error {
	serverID, err := ctx.API.GetServerID(args.Server)
	if err != nil {
		return err
	}
	server, err := ctx.API.GetServer(serverID)
	if err != nil {
		return fmt.Errorf("failed to get server information for %s: %v", serverID, err)
	}

	// FIXME: switch to serial history when API is ready

	// Resolve gateway
	if args.Gateway == "" {
		args.Gateway = ctx.Getenv("SCW_GATEWAY")
	}
	var gateway string
	if args.Gateway == serverID || args.Gateway == args.Server {
		gateway = ""
	} else {
		gateway, err = api.ResolveGateway(ctx.API, args.Gateway)
		if err != nil {
			return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
		}
	}

	command := []string{"dmesg"}
	err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, command, true, gateway)
	if err != nil {
		return fmt.Errorf("command execution failed: %v", err)
	}
	return nil
}
Пример #5
0
// RunKill is the handler for 'scw kill'
func RunKill(ctx CommandContext, args KillArgs) error {
	serverID := ctx.API.GetServerID(args.Server)
	command := "halt"
	server, err := ctx.API.GetServer(serverID)
	if err != nil {
		return fmt.Errorf("failed to get server information for %s: %v", serverID, err)
	}

	// Resolve gateway
	if args.Gateway == "" {
		args.Gateway = ctx.Getenv("SCW_GATEWAY")
	}
	var gateway string
	if args.Gateway == serverID || args.Gateway == args.Server {
		gateway = ""
	} else {
		gateway, err = api.ResolveGateway(ctx.API, args.Gateway)
		if err != nil {
			return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
		}
	}

	sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, []string{command}, gateway)

	logrus.Debugf("Executing: %s", sshCommand)

	spawn := exec.Command("ssh", sshCommand.Slice()[1:]...)
	spawn.Stdout = ctx.Stdout
	spawn.Stdin = ctx.Stdin
	spawn.Stderr = ctx.Stderr

	return spawn.Run()
}
Пример #6
0
// TarFromSource creates a stream buffer with the tarballed content of the user source
func TarFromSource(ctx CommandContext, source string, gateway string) (*io.ReadCloser, error) {
	var tarOutputStream io.ReadCloser

	// source is a server address + path (scp-like uri)
	if strings.Contains(source, ":") {
		logrus.Debugf("Creating a tarball remotely and streaming it using SSH")
		serverParts := strings.Split(source, ":")
		if len(serverParts) != 2 {
			return nil, fmt.Errorf("invalid source uri, see 'scw cp -h' for usage")
		}

		serverID, err := ctx.API.GetServerID(serverParts[0])
		if err != nil {
			return nil, err
		}

		server, err := ctx.API.GetServer(serverID)
		if err != nil {
			return nil, err
		}

		dir, base := utils.PathToTARPathparts(serverParts[1])
		logrus.Debugf("Equivalent to 'scp root@%s:%s/%s ...'", server.PublicAddress.IP, dir, base)

		// remoteCommand is executed on the remote server
		// it streams a tarball raw content
		remoteCommand := []string{"tar"}
		remoteCommand = append(remoteCommand, "-C", dir)
		if ctx.Getenv("DEBUG") == "1" {
			remoteCommand = append(remoteCommand, "-v")
		}
		remoteCommand = append(remoteCommand, "-cf", "-")
		remoteCommand = append(remoteCommand, base)

		// Resolve gateway
		if gateway == "" {
			gateway = ctx.Getenv("SCW_GATEWAY")
		}

		if gateway == serverID || gateway == serverParts[0] {
			gateway = ""
		} else {
			gateway, err = api.ResolveGateway(ctx.API, gateway)
			if err != nil {
				return nil, fmt.Errorf("cannot resolve Gateway '%s': %v", gateway, err)
			}
		}

		// execCmd contains the ssh connection + the remoteCommand
		sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, remoteCommand, gateway)
		logrus.Debugf("Executing: %s", sshCommand)
		spawnSrc := exec.Command("ssh", sshCommand.Slice()[1:]...)

		tarOutputStream, err = spawnSrc.StdoutPipe()
		if err != nil {
			return nil, err
		}

		tarErrorStream, err := spawnSrc.StderrPipe()
		if err != nil {
			return nil, err
		}
		defer tarErrorStream.Close()
		io.Copy(ctx.Stderr, tarErrorStream)

		err = spawnSrc.Start()
		if err != nil {
			return nil, err
		}
		defer spawnSrc.Wait()

		return &tarOutputStream, nil
	}

	// source is stdin
	if source == "-" {
		logrus.Debugf("Streaming tarball from stdin")
		// FIXME: should be ctx.Stdin
		tarOutputStream = os.Stdin
		return &tarOutputStream, nil
	}

	// source is a path on localhost
	logrus.Debugf("Taring local path %s", source)
	path, err := filepath.Abs(source)
	if err != nil {
		return nil, err
	}
	path, err = filepath.EvalSymlinks(path)
	if err != nil {
		return nil, err
	}
	logrus.Debugf("Real local path is %s", path)

	dir, base := utils.PathToTARPathparts(path)

	tarOutputStream, err = archive.TarWithOptions(dir, &archive.TarOptions{
		Compression:  archive.Uncompressed,
		IncludeFiles: []string{base},
	})
	if err != nil {
		return nil, err
	}
	return &tarOutputStream, nil
}
Пример #7
0
// UntarToDest writes to user destination the streamed tarball in input
func UntarToDest(ctx CommandContext, sourceStream *io.ReadCloser, destination string, gateway string) error {
	// destination is a server address + path (scp-like uri)
	if strings.Contains(destination, ":") {
		logrus.Debugf("Streaming using ssh and untaring remotely")
		serverParts := strings.Split(destination, ":")
		if len(serverParts) != 2 {
			return fmt.Errorf("invalid destination uri, see 'scw cp -h' for usage")
		}

		serverID, err := ctx.API.GetServerID(serverParts[0])
		if err != nil {
			return err
		}

		server, err := ctx.API.GetServer(serverID)
		if err != nil {
			return err
		}

		// remoteCommand is executed on the remote server
		// it streams a tarball raw content
		remoteCommand := []string{"tar"}
		remoteCommand = append(remoteCommand, "-C", serverParts[1])
		if ctx.Getenv("DEBUG") == "1" {
			remoteCommand = append(remoteCommand, "-v")
		}
		remoteCommand = append(remoteCommand, "-xf", "-")

		// Resolve gateway
		if gateway == "" {
			gateway = ctx.Getenv("SCW_GATEWAY")
		}
		if gateway == serverID || gateway == serverParts[0] {
			gateway = ""
		} else {
			gateway, err = api.ResolveGateway(ctx.API, gateway)
			if err != nil {
				return fmt.Errorf("cannot resolve Gateway '%s': %v", gateway, err)
			}
		}

		// execCmd contains the ssh connection + the remoteCommand
		sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, remoteCommand, gateway)
		logrus.Debugf("Executing: %s", sshCommand)
		spawnDst := exec.Command("ssh", sshCommand.Slice()[1:]...)

		untarInputStream, err := spawnDst.StdinPipe()
		if err != nil {
			return err
		}
		defer untarInputStream.Close()

		// spawnDst.Stderr = ctx.Stderr
		// spawnDst.Stdout = ctx.Stdout

		err = spawnDst.Start()
		if err != nil {
			return err
		}

		_, err = io.Copy(untarInputStream, *sourceStream)
		return err
	}

	// destination is stdout
	if destination == "-" { // stdout
		logrus.Debugf("Writing sourceStream(%v) to ctx.Stdout(%v)", sourceStream, ctx.Stdout)
		_, err := io.Copy(ctx.Stdout, *sourceStream)
		return err
	}

	// destination is a path on localhost
	logrus.Debugf("Untaring to local path: %s", destination)
	err := archive.Untar(*sourceStream, destination, &archive.TarOptions{NoLchown: true})
	return err
}
Пример #8
0
// RunExec is the handler for 'scw exec'
func RunExec(ctx CommandContext, args ExecArgs) error {
	var fingerprints []string

	done := make(chan struct{})

	serverID, err := ctx.API.GetServerID(args.Server)
	if err != nil {
		return err
	}

	go func() {
		fingerprints = ctx.API.GetSSHFingerprintFromServer(serverID)
		close(done)
	}()
	// Resolve gateway
	if args.Gateway == "" {
		args.Gateway = ctx.Getenv("SCW_GATEWAY")
	}
	var gateway string

	if args.Gateway == serverID || args.Gateway == args.Server {
		logrus.Debugf("The server and the gateway are the same host, using direct access to the server")
		gateway = ""
	} else {
		gateway, err = api.ResolveGateway(ctx.API, args.Gateway)
		if err != nil {
			return fmt.Errorf("Cannot resolve Gateway '%s': %v", args.Gateway, err)
		}
		if gateway != "" {
			logrus.Debugf("The server will be accessed using the gateway '%s' as a SSH relay", gateway)
		}
	}

	var server *api.ScalewayServer
	if args.Wait {
		// --wait
		logrus.Debugf("Waiting for server to be ready")
		server, err = api.WaitForServerReady(ctx.API, serverID, gateway)
		if err != nil {
			return fmt.Errorf("Failed to wait for server to be ready, %v", err)
		}
	} else {
		// no --wait
		logrus.Debugf("scw won't wait for the server to be ready, if it is not, the command will fail")
		server, err = ctx.API.GetServer(serverID)
		if err != nil {
			rerr := fmt.Errorf("Failed to get server information for %s: %v", serverID, err)
			if err.Error() == `"`+serverID+`" not found` {
				return fmt.Errorf("%v\nmaybe try to flush the cache with : scw _flush-cache", rerr)
			}
			return rerr
		}
	}

	if server.PublicAddress.IP == "" && gateway == "" {
		logrus.Warn(`Your host has no public IP address, you should use '--gateway', see 'scw help exec'`)
	}

	// --timeout
	if args.Timeout > 0 {
		logrus.Debugf("Setting up a global timeout of %d seconds", args.Timeout)
		// FIXME: avoid use of log.Fatalf here
		go func() {
			time.Sleep(time.Duration(args.Timeout*1000) * time.Millisecond)
			logrus.Fatalf("Operation timed out")
		}()
	}

	<-done
	if len(fingerprints) > 0 {
		for i := range fingerprints {
			fmt.Fprintf(ctx.Stdout, "%s\n", fingerprints[i])
		}
	}
	logrus.Debugf("PublicDNS %s", serverID+api.URLPublicDNS)
	logrus.Debugf("PrivateDNS %s", serverID+api.URLPrivateDNS)
	if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, args.Command, !args.Wait, gateway); err != nil {
		return fmt.Errorf("Failed to run the command: %v", err)
	}

	logrus.Debugf("Command successfully executed")
	return nil
}
Пример #9
0
// Run is the handler for 'scw run'
func Run(ctx CommandContext, args RunArgs) error {
	if args.Gateway == "" {
		args.Gateway = ctx.Getenv("SCW_GATEWAY")
	}

	if args.TmpSSHKey {
		err := AddSSHKeyToTags(ctx, &args.Tags, args.Image)
		if err != nil {
			return err
		}
	}
	env := strings.Join(args.Tags, " ")
	volume := strings.Join(args.Volumes, " ")

	// create IMAGE
	logrus.Info("Server creation ...")
	dynamicIPRequired := args.Gateway == ""
	serverID, err := api.CreateServer(ctx.API, args.Image, args.Name, args.Bootscript, env, volume, dynamicIPRequired)
	if err != nil {
		return fmt.Errorf("failed to create server: %v", err)
	}
	logrus.Infof("Server created: %s", serverID)

	if args.AutoRemove {
		defer ctx.API.DeleteServerSafe(serverID)
	}

	// start SERVER
	logrus.Info("Server start requested ...")
	err = api.StartServer(ctx.API, serverID, false)
	if err != nil {
		return fmt.Errorf("failed to start server %s: %v", serverID, err)
	}
	logrus.Info("Server is starting, this may take up to a minute ...")

	if args.Detach {
		fmt.Fprintln(ctx.Stdout, serverID)
		return nil
	} else {
		// Sync cache on disk
		ctx.API.Sync()
	}

	if args.Attach {
		// Attach to server serial
		logrus.Info("Attaching to server console ...")
		err = utils.AttachToSerial(serverID, ctx.API.Token, true)
		if err != nil {
			return fmt.Errorf("cannot attach to server serial: %v", err)
		}
	} else {
		// Resolve gateway
		gateway, err := api.ResolveGateway(ctx.API, args.Gateway)
		if err != nil {
			return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
		}

		// waiting for server to be ready
		logrus.Debug("Waiting for server to be ready")
		// We wait for 30 seconds, which is the minimal amount of time needed by a server to boot
		server, err := api.WaitForServerReady(ctx.API, serverID, gateway)
		if err != nil {
			return fmt.Errorf("cannot get access to server %s: %v", serverID, err)
		}
		logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP)
		logrus.Info("Server is ready !")

		// exec -w SERVER COMMAND ARGS...
		if len(args.Command) < 1 {
			logrus.Info("Connecting to server ...")
			err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway)
		} else {
			logrus.Infof("Executing command: %s ...", args.Command)
			err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway)
		}
		if err != nil {
			return fmt.Errorf("command execution failed: %v", err)
		}
		logrus.Info("Command successfuly executed")
	}
	return nil
}