// 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 }
// 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() }
// 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 }
// 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 }