diff --git a/pkg/api/api.go b/pkg/api/api.go index 3abe038283..d89b465c5f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -31,6 +31,8 @@ var ( AccountAPI = "https://account.scaleway.com/" MetadataAPI = "http://169.254.42.42/" MarketplaceAPI = "https://api-marketplace.scaleway.com" + URLPublicDNS = ".pub.cloud.scaleway.com" + URLPrivateDNS = ".priv.cloud.scaleway.com" ) func init() { @@ -529,6 +531,10 @@ type ScalewayServer struct { IPV6 *ScalewayIPV6Definition `json:"ipv6,omitempty"` EnableIPV6 bool `json:"enable_ipv6,omitempty"` + + // This fields are not returned by the API, we generate it + DNSPublic string `json:"dns_public,omitempty"` + DNSPrivate string `json:"dns_private,omitempty"` } // ScalewayIPV6Definition represents a Scaleway ipv6 @@ -1043,8 +1049,10 @@ func (s *ScalewayAPI) GetServers(all bool, limit int) (*[]ScalewayServer, error) if err = json.Unmarshal(body, &servers); err != nil { return nil, err } - for _, server := range servers.Servers { + for i, server := range servers.Servers { // FIXME region, arch, owner, title + servers.Servers[i].DNSPublic = server.Identifier + URLPublicDNS + servers.Servers[i].DNSPrivate = server.Identifier + URLPrivateDNS s.Cache.InsertServer(server.Identifier, "fr-1", server.Arch, server.Organization, server.Name) } // FIXME: when API limit is ready, remove the following code @@ -1092,6 +1100,8 @@ func (s *ScalewayAPI) GetServer(serverID string) (*ScalewayServer, error) { return nil, err } // FIXME region, arch, owner, title + oneServer.Server.DNSPublic = oneServer.Server.Identifier + URLPublicDNS + oneServer.Server.DNSPrivate = oneServer.Server.Identifier + URLPrivateDNS s.Cache.InsertServer(oneServer.Server.Identifier, "fr-1", oneServer.Server.Arch, oneServer.Server.Organization, oneServer.Server.Name) return &oneServer.Server, nil } diff --git a/pkg/api/helpers.go b/pkg/api/helpers.go index dd8bc92709..68bff87970 100644 --- a/pkg/api/helpers.go +++ b/pkg/api/helpers.go @@ -482,7 +482,7 @@ func WaitForServerState(api *ScalewayAPI, serverID string, targetState string) ( } // WaitForServerReady wait for a server state to be running, then wait for the SSH port to be available -func WaitForServerReady(api *ScalewayAPI, serverID string, gateway string) (*ScalewayServer, error) { +func WaitForServerReady(api *ScalewayAPI, serverID, gateway string) (*ScalewayServer, error) { promise := make(chan bool) var server *ScalewayServer var err error @@ -513,25 +513,48 @@ func WaitForServerReady(api *ScalewayAPI, serverID string, gateway string) (*Sca } if gateway == "" { - log.Debugf("Waiting for server SSH port") dest := fmt.Sprintf("%s:22", server.PublicAddress.IP) + log.Debugf("Waiting for server SSH port %s", dest) err = utils.WaitForTCPPortOpen(dest) if err != nil { promise <- false return } } else { - log.Debugf("Waiting for gateway SSH port") dest := fmt.Sprintf("%s:22", gateway) + log.Debugf("Waiting for server SSH port %s", dest) err = utils.WaitForTCPPortOpen(dest) if err != nil { promise <- false return } + timeout := time.Tick(120 * time.Second) + for { + select { + case <-timeout: + err = fmt.Errorf("Timeout: unable to ping %s", server.PrivateIP) + fmt.Println("timeout") + goto OUT + default: + if utils.SSHExec("", server.PrivateIP, "root", 22, []string{ + "nc", + "-z", + "-w", + "1", + server.PrivateIP, + "22", + }, false, gateway) == nil { + goto OUT + } + } + } + OUT: + if err != nil { + promise <- false + return + } + log.Debugf("Check for SSH port through the gateway: %s", server.PrivateIP) - log.Debugf("Waiting 30 more seconds, for SSH to be ready") - time.Sleep(30 * time.Second) - // FIXME: check for SSH port through the gateway } promise <- true }() diff --git a/pkg/cli/cmd_cp.go b/pkg/cli/cmd_cp.go index 940f2ab613..ad88f766a3 100644 --- a/pkg/cli/cmd_cp.go +++ b/pkg/cli/cmd_cp.go @@ -31,11 +31,15 @@ var cmdCp = &Command{ func init() { cmdCp.Flag.BoolVar(&cpHelp, []string{"h", "-help"}, false, "Print usage") cmdCp.Flag.StringVar(&cpGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") + cmdCp.Flag.StringVar(&cpSSHUser, []string{"u", "-user"}, "root", "Specify SSH user") + cmdCp.Flag.IntVar(&cpSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") } // Flags var cpHelp bool // -h, --help flag var cpGateway string // -g, --gateway flag +var cpSSHUser string // -u, --user flag +var cpSSHPort int // -p, --port flag func runCp(cmd *Command, rawArgs []string) error { if cpHelp { @@ -49,6 +53,8 @@ func runCp(cmd *Command, rawArgs []string) error { Gateway: cpGateway, Source: rawArgs[0], Destination: rawArgs[1], + SSHUser: cpSSHUser, + SSHPort: cpSSHPort, } ctx := cmd.GetContext(rawArgs) return commands.RunCp(ctx, args) diff --git a/pkg/cli/cmd_exec.go b/pkg/cli/cmd_exec.go index 071f9b6122..7c710a4011 100644 --- a/pkg/cli/cmd_exec.go +++ b/pkg/cli/cmd_exec.go @@ -30,6 +30,8 @@ func init() { cmdExec.Flag.Float64Var(&execTimeout, []string{"T", "-timeout"}, 0, "Set timeout values to seconds") cmdExec.Flag.BoolVar(&execW, []string{"w", "-wait"}, false, "Wait for SSH to be ready") cmdExec.Flag.StringVar(&execGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") + cmdExec.Flag.StringVar(&execSSHUser, []string{"u", "-user"}, "root", "Specify SSH user") + cmdExec.Flag.IntVar(&execSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") } // Flags @@ -37,6 +39,8 @@ var execW bool // -w, --wait flag var execTimeout float64 // -T flag var execHelp bool // -h, --help flag var execGateway string // -g, --gateway flag +var execSSHUser string // -u, --user flag +var execSSHPort int // -p, --port flag func runExec(cmd *Command, rawArgs []string) error { if execHelp { @@ -52,6 +56,8 @@ func runExec(cmd *Command, rawArgs []string) error { Gateway: execGateway, Server: rawArgs[0], Command: rawArgs[1:], + SSHUser: execSSHUser, + SSHPort: execSSHPort, } ctx := cmd.GetContext(rawArgs) return commands.RunExec(ctx, args) diff --git a/pkg/cli/cmd_kill.go b/pkg/cli/cmd_kill.go index 8e8898e815..28b26e4126 100644 --- a/pkg/cli/cmd_kill.go +++ b/pkg/cli/cmd_kill.go @@ -16,12 +16,16 @@ var cmdKill = &Command{ func init() { cmdKill.Flag.BoolVar(&killHelp, []string{"h", "-help"}, false, "Print usage") cmdKill.Flag.StringVar(&killGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") + cmdKill.Flag.StringVar(&killSSHUser, []string{"u", "-user"}, "root", "Specify SSH user") + cmdKill.Flag.IntVar(&killSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") // FIXME: add --signal option } // Flags var killHelp bool // -h, --help flag var killGateway string // -g, --gateway flag +var killSSHUser string // -u, --user flag +var killSSHPort int // -p, --port flag func runKill(cmd *Command, rawArgs []string) error { if killHelp { @@ -34,6 +38,8 @@ func runKill(cmd *Command, rawArgs []string) error { args := commands.KillArgs{ Gateway: killGateway, Server: rawArgs[0], + SSHUser: killSSHUser, + SSHPort: killSSHPort, } ctx := cmd.GetContext(rawArgs) return commands.RunKill(ctx, args) diff --git a/pkg/cli/cmd_logs.go b/pkg/cli/cmd_logs.go index d55c5125e6..6031064f1c 100644 --- a/pkg/cli/cmd_logs.go +++ b/pkg/cli/cmd_logs.go @@ -16,11 +16,15 @@ var cmdLogs = &Command{ func init() { cmdLogs.Flag.BoolVar(&logsHelp, []string{"h", "-help"}, false, "Print usage") cmdLogs.Flag.StringVar(&logsGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") + cmdLogs.Flag.StringVar(&logsSSHUser, []string{"u", "-user"}, "root", "Specify SSH root") + cmdLogs.Flag.IntVar(&logsSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") } // FLags var logsHelp bool // -h, --help flag var logsGateway string // -g, --gateway flag +var logsSSHUser string // -u, --user flag +var logsSSHPort int // -p, --port flag func runLogs(cmd *Command, rawArgs []string) error { if logsHelp { @@ -33,6 +37,8 @@ func runLogs(cmd *Command, rawArgs []string) error { args := commands.LogsArgs{ Gateway: logsGateway, Server: rawArgs[0], + SSHUser: logsSSHUser, + SSHPort: logsSSHPort, } ctx := cmd.GetContext(rawArgs) return commands.RunLogs(ctx, args) diff --git a/pkg/cli/cmd_port.go b/pkg/cli/cmd_port.go index 6fa379a25f..49262bfeab 100644 --- a/pkg/cli/cmd_port.go +++ b/pkg/cli/cmd_port.go @@ -16,11 +16,15 @@ var cmdPort = &Command{ func init() { cmdPort.Flag.BoolVar(&portHelp, []string{"h", "-help"}, false, "Print usage") cmdPort.Flag.StringVar(&portGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") + cmdPort.Flag.StringVar(&portSSHUser, []string{"u", "-user"}, "root", "Specify SSH user") + cmdPort.Flag.IntVar(&portSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") } // FLags var portHelp bool // -h, --help flag var portGateway string // -g, --gateway flag +var portSSHUser string // -u, --user flag +var portSSHPort int // -p, --port flag func runPort(cmd *Command, rawArgs []string) error { if portHelp { @@ -33,6 +37,8 @@ func runPort(cmd *Command, rawArgs []string) error { args := commands.PortArgs{ Gateway: portGateway, Server: rawArgs[0], + SSHUser: portSSHUser, + SSHPort: portSSHPort, } ctx := cmd.GetContext(rawArgs) return commands.RunPort(ctx, args) diff --git a/pkg/cli/cmd_run.go b/pkg/cli/cmd_run.go index f960f17d2a..e4c208d2f4 100644 --- a/pkg/cli/cmd_run.go +++ b/pkg/cli/cmd_run.go @@ -46,10 +46,12 @@ func init() { cmdRun.Flag.StringVar(&runGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") cmdRun.Flag.StringVar(&runUserdatas, []string{"u", "-userdata"}, "", "Start a server with userdata predefined") cmdRun.Flag.StringVar(&runCommercialType, []string{"-commercial-type"}, "VC1S", "Start a server with specific commercial-type C1, VC1S, C2[SML]") + cmdRun.Flag.StringVar(&runSSHUser, []string{"-u", "-user"}, "root", "Specify SSH User") cmdRun.Flag.BoolVar(&runAutoRemove, []string{"-rm"}, false, "Automatically remove the server when it exits") cmdRun.Flag.BoolVar(&runIPV6, []string{"-ipv6"}, false, "Enable IPV6") cmdRun.Flag.BoolVar(&runTmpSSHKey, []string{"-tmp-ssh-key"}, false, "Access your server without uploading your SSH key to your account") cmdRun.Flag.BoolVar(&runShowBoot, []string{"-show-boot"}, false, "Allows to show the boot") + cmdRun.Flag.IntVar(&runSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") // FIXME: handle start --timeout } @@ -71,6 +73,8 @@ var runShowBoot bool // --show-boot flag var runIPV6 bool // --ipv6 flag var runTimeout int64 // --timeout flag var runSetState string // --set-state flag +var runSSHUser string // -u, --user flag +var runSSHPort int // -p, --port flag func runRun(cmd *Command, rawArgs []string) error { if runHelpFlag { @@ -118,6 +122,8 @@ func runRun(cmd *Command, rawArgs []string) error { CommercialType: runCommercialType, State: runSetState, IPV6: runIPV6, + SSHUser: runSSHUser, + SSHPort: runSSHPort, // FIXME: Timeout } diff --git a/pkg/cli/cmd_top.go b/pkg/cli/cmd_top.go index adbffde3a8..5586da5bdf 100644 --- a/pkg/cli/cmd_top.go +++ b/pkg/cli/cmd_top.go @@ -16,11 +16,15 @@ var cmdTop = &Command{ func init() { cmdTop.Flag.BoolVar(&topHelp, []string{"h", "-help"}, false, "Print usage") cmdTop.Flag.StringVar(&topGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") + cmdTop.Flag.StringVar(&topSSHUser, []string{"u", "-user"}, "root", "Specify SSH user") + cmdTop.Flag.IntVar(&topSSHPort, []string{"-p", "-port"}, 22, "Specify SSH port") } // Flags var topHelp bool // -h, --help flag var topGateway string // -g, --gateway flag +var topSSHUser string // -u, --user flag +var topSSHPort int // -p, --port flag func runTop(cmd *Command, rawArgs []string) error { if topHelp { @@ -33,6 +37,8 @@ func runTop(cmd *Command, rawArgs []string) error { args := commands.TopArgs{ Gateway: topGateway, Server: rawArgs[0], + SSHUser: topSSHUser, + SSHPort: topSSHPort, } ctx := cmd.GetContext(rawArgs) return commands.RunTop(ctx, args) diff --git a/pkg/commands/cp.go b/pkg/commands/cp.go index 14e3a3d9aa..0950a1bf21 100644 --- a/pkg/commands/cp.go +++ b/pkg/commands/cp.go @@ -23,6 +23,8 @@ type CpArgs struct { Gateway string Source string Destination string + SSHUser string + SSHPort int } // RunCp is the handler for 'scw cp' @@ -31,12 +33,12 @@ func RunCp(ctx CommandContext, args CpArgs) error { return fmt.Errorf("bad usage, see 'scw help cp'") } - sourceStream, err := TarFromSource(ctx, args.Source, args.Gateway) + sourceStream, err := TarFromSource(ctx, args.Source, args.Gateway, args.SSHUser, args.SSHPort) if err != nil { return fmt.Errorf("cannot tar from source '%s': %v", args.Source, err) } - err = UntarToDest(ctx, sourceStream, args.Destination, args.Gateway) + err = UntarToDest(ctx, sourceStream, args.Destination, args.Gateway, args.SSHUser, args.SSHPort) if err != nil { return fmt.Errorf("cannot untar to destination '%s': %v", args.Destination, err) } @@ -44,7 +46,7 @@ func RunCp(ctx CommandContext, args CpArgs) error { } // TarFromSource creates a stream buffer with the tarballed content of the user source -func TarFromSource(ctx CommandContext, source string, gateway string) (*io.ReadCloser, error) { +func TarFromSource(ctx CommandContext, source, gateway, user string, port int) (*io.ReadCloser, error) { var tarOutputStream io.ReadCloser // source is a server address + path (scp-like uri) @@ -93,7 +95,7 @@ func TarFromSource(ctx CommandContext, source string, gateway string) (*io.ReadC } // execCmd contains the ssh connection + the remoteCommand - sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, remoteCommand, gateway) + sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, user, port, false, remoteCommand, gateway) logrus.Debugf("Executing: %s", sshCommand) spawnSrc := exec.Command("ssh", sshCommand.Slice()[1:]...) @@ -151,7 +153,7 @@ func TarFromSource(ctx CommandContext, source string, gateway string) (*io.ReadC } // UntarToDest writes to user destination the streamed tarball in input -func UntarToDest(ctx CommandContext, sourceStream *io.ReadCloser, destination string, gateway string) error { +func UntarToDest(ctx CommandContext, sourceStream *io.ReadCloser, destination, gateway, user string, port int) error { // destination is a server address + path (scp-like uri) if strings.Contains(destination, ":") { logrus.Debugf("Streaming using ssh and untaring remotely") @@ -193,7 +195,7 @@ func UntarToDest(ctx CommandContext, sourceStream *io.ReadCloser, destination st } // execCmd contains the ssh connection + the remoteCommand - sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, remoteCommand, gateway) + sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, user, port, false, remoteCommand, gateway) logrus.Debugf("Executing: %s", sshCommand) spawnDst := exec.Command("ssh", sshCommand.Slice()[1:]...) diff --git a/pkg/commands/create.go b/pkg/commands/create.go index 27fc8e67ab..b312b48012 100644 --- a/pkg/commands/create.go +++ b/pkg/commands/create.go @@ -8,6 +8,7 @@ import ( "fmt" "strings" + "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" ) @@ -56,7 +57,9 @@ func RunCreate(ctx CommandContext, args CreateArgs) error { if err != nil { return err } - + logrus.Debugf("Server created: %s", serverID) + logrus.Debugf("PublicDNS %s", serverID+api.URLPublicDNS) + logrus.Debugf("PrivateDNS %s", serverID+api.URLPrivateDNS) fmt.Fprintln(ctx.Stdout, serverID) return nil } diff --git a/pkg/commands/exec.go b/pkg/commands/exec.go index eb289a1952..937c03e8eb 100644 --- a/pkg/commands/exec.go +++ b/pkg/commands/exec.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" "github.com/scaleway/scaleway-cli/pkg/utils" @@ -21,6 +21,8 @@ type ExecArgs struct { Gateway string Server string Command []string + SSHUser string + SSHPort int } // RunExec is the handler for 'scw exec' @@ -45,7 +47,7 @@ func RunExec(ctx CommandContext, args ExecArgs) error { var gateway string if args.Gateway == serverID || args.Gateway == args.Server { - log.Debugf("The server and the gateway are the same host, using direct access to the 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) @@ -53,21 +55,21 @@ func RunExec(ctx CommandContext, args ExecArgs) error { return fmt.Errorf("Cannot resolve Gateway '%s': %v", args.Gateway, err) } if gateway != "" { - log.Debugf("The server will be accessed using the gateway '%s' as a SSH relay", 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 - log.Debugf("Waiting for server to be ready") + 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 - log.Debugf("scw won't wait for the server to be ready, if it is not, the command will fail") + 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) @@ -79,16 +81,16 @@ func RunExec(ctx CommandContext, args ExecArgs) error { } if server.PublicAddress.IP == "" && gateway == "" { - log.Warn(`Your host has no public IP address, you should use '--gateway', see 'scw help exec'`) + logrus.Warn(`Your host has no public IP address, you should use '--gateway', see 'scw help exec'`) } // --timeout if args.Timeout > 0 { - log.Debugf("Setting up a global timeout of %d seconds", args.Timeout) + 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) - log.Fatalf("Operation timed out") + logrus.Fatalf("Operation timed out") }() } @@ -98,10 +100,12 @@ func RunExec(ctx CommandContext, args ExecArgs) error { fmt.Fprintf(ctx.Stdout, "%s\n", fingerprints[i]) } } - if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, !args.Wait, gateway); err != nil { + 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) } - log.Debugf("Command successfully executed") + logrus.Debugf("Command successfully executed") return nil } diff --git a/pkg/commands/info.go b/pkg/commands/info.go index 0e446f660c..55b46881d2 100644 --- a/pkg/commands/info.go +++ b/pkg/commands/info.go @@ -95,5 +95,11 @@ func RunInfo(ctx CommandContext, args InfoArgs) error { for key, value := range quotas.Quotas { fmt.Fprintf(ctx.Stdout, " %-20s: %d\n", key, value) } + fmt.Fprintf(ctx.Stdout, "\n") + fmt.Fprintln(ctx.Stdout, "Urls:") + fmt.Fprintf(ctx.Stdout, " compute: %s\n", api.ComputeAPI) + fmt.Fprintf(ctx.Stdout, " account: %s\n", api.AccountAPI) + fmt.Fprintf(ctx.Stdout, " metadata: %s\n", api.MetadataAPI) + fmt.Fprintf(ctx.Stdout, " marketplace: %s\n", api.MarketplaceAPI) return nil } diff --git a/pkg/commands/kill.go b/pkg/commands/kill.go index 5f4742eabb..6e37b6e5c4 100644 --- a/pkg/commands/kill.go +++ b/pkg/commands/kill.go @@ -17,6 +17,8 @@ import ( type KillArgs struct { Gateway string Server string + SSHUser string + SSHPort int } // RunKill is the handler for 'scw kill' @@ -45,7 +47,7 @@ func RunKill(ctx CommandContext, args KillArgs) error { } } - sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, []string{command}, gateway) + sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, true, []string{command}, gateway) logrus.Debugf("Executing: %s", sshCommand) diff --git a/pkg/commands/logs.go b/pkg/commands/logs.go index e7bc7359dd..37eacbf314 100644 --- a/pkg/commands/logs.go +++ b/pkg/commands/logs.go @@ -15,6 +15,8 @@ import ( type LogsArgs struct { Gateway string Server string + SSHUser string + SSHPort int } // RunLogs is the handler for 'scw logs' @@ -45,7 +47,7 @@ func RunLogs(ctx CommandContext, args LogsArgs) error { } command := []string{"dmesg"} - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway) + 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) } diff --git a/pkg/commands/port.go b/pkg/commands/port.go index 6369c64200..8b54ca7d32 100644 --- a/pkg/commands/port.go +++ b/pkg/commands/port.go @@ -15,6 +15,8 @@ import ( type PortArgs struct { Gateway string Server string + SSHUser string + SSHPort int } // RunPort is the handler for 'scw port' @@ -43,7 +45,7 @@ func RunPort(ctx CommandContext, args PortArgs) error { } command := []string{"netstat -lutn 2>/dev/null | grep LISTEN"} - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway) + 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) } diff --git a/pkg/commands/run.go b/pkg/commands/run.go index f6cb528de3..a22aeed73a 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -31,7 +31,9 @@ type RunArgs struct { Userdata string CommercialType string State string + SSHUser string Timeout int64 + SSHPort int AutoRemove bool TmpSSHKey bool ShowBoot bool @@ -134,7 +136,7 @@ func runShowBoot(ctx CommandContext, args RunArgs, serverID string, closeTimeout } server := sshConnection.server logrus.Info("Connecting to server ...") - if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil { + if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, []string{}, false, gateway); err != nil { return fmt.Errorf("Connection to server failed: %v", err) } } @@ -180,6 +182,8 @@ func Run(ctx CommandContext, args RunArgs) error { return fmt.Errorf("failed to create server: %v", err) } logrus.Infof("Server created: %s", serverID) + logrus.Debugf("PublicDNS %s", serverID+api.URLPublicDNS) + logrus.Debugf("PrivateDNS %s", serverID+api.URLPrivateDNS) if args.AutoRemove { defer ctx.API.DeleteServerSafe(serverID) @@ -272,12 +276,12 @@ func Run(ctx CommandContext, args RunArgs) error { // exec -w SERVER COMMAND ARGS... if len(args.Command) < 1 { logrus.Info("Connecting to server ...") - if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil { + if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, []string{}, false, gateway); err != nil { return fmt.Errorf("Connection to server failed: %v", err) } } else { logrus.Infof("Executing command: %s ...", args.Command) - if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway); err != nil { + if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, args.Command, false, gateway); err != nil { return fmt.Errorf("command execution failed: %v", err) } logrus.Info("Command successfully executed") diff --git a/pkg/commands/top.go b/pkg/commands/top.go index 1a07b99a4b..edf63322d7 100644 --- a/pkg/commands/top.go +++ b/pkg/commands/top.go @@ -17,6 +17,8 @@ import ( type TopArgs struct { Server string Gateway string + SSHUser string + SSHPort int } // RunTop is the handler for 'scw top' @@ -45,7 +47,7 @@ func RunTop(ctx CommandContext, args TopArgs) error { } } - sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, []string{command}, gateway) + sshCommand := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, true, []string{command}, gateway) logrus.Debugf("Executing: %s", sshCommand) out, err := exec.Command("ssh", sshCommand.Slice()[1:]...).CombinedOutput() if err == nil { diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index e37e20e39d..52cda4b198 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -39,11 +39,14 @@ type SpawnRedirection struct { } // SSHExec executes a command over SSH and redirects file-descriptors -func SSHExec(publicIPAddress string, privateIPAddress string, command []string, checkConnection bool, gateway string) error { +func SSHExec(publicIPAddress, privateIPAddress, user string, port int, command []string, checkConnection bool, gateway string) error { gatewayUser := "root" gatewayIPAddress := gateway if strings.Contains(gateway, "@") { parts := strings.Split(gatewayIPAddress, "@") + if len(parts) != 2 { + return fmt.Errorf("gateway: must be like root@IP") + } gatewayUser = parts[0] gatewayIPAddress = parts[1] gateway = gatewayUser + "@" + gatewayIPAddress @@ -66,7 +69,7 @@ func SSHExec(publicIPAddress string, privateIPAddress string, command []string, } } - sshCommand := NewSSHExecCmd(publicIPAddress, privateIPAddress, isatty.IsTerminal(os.Stdin.Fd()), command, gateway) + sshCommand := NewSSHExecCmd(publicIPAddress, privateIPAddress, user, port, isatty.IsTerminal(os.Stdin.Fd()), command, gateway) log.Debugf("Executing: %s", sshCommand) @@ -78,7 +81,7 @@ func SSHExec(publicIPAddress string, privateIPAddress string, command []string, } // NewSSHExecCmd computes execve compatible arguments to run a command via ssh -func NewSSHExecCmd(publicIPAddress string, privateIPAddress string, allocateTTY bool, command []string, gatewayIPAddress string) *sshcommand.Command { +func NewSSHExecCmd(publicIPAddress, privateIPAddress, user string, port int, allocateTTY bool, command []string, gatewayIPAddress string) *sshcommand.Command { quiet := os.Getenv("DEBUG") != "1" secureExec := os.Getenv("SCW_SECURE_EXEC") == "1" sshCommand := &sshcommand.Command{ @@ -87,8 +90,9 @@ func NewSSHExecCmd(publicIPAddress string, privateIPAddress string, allocateTTY Host: publicIPAddress, Quiet: quiet, SkipHostKeyChecking: !secureExec, - User: "root", + User: user, NoEscapeCommand: true, + Port: port, } if gatewayIPAddress != "" { sshCommand.Host = privateIPAddress @@ -97,7 +101,8 @@ func NewSSHExecCmd(publicIPAddress string, privateIPAddress string, allocateTTY SkipHostKeyChecking: !secureExec, AllocateTTY: allocateTTY, Quiet: quiet, - User: "root", + User: user, + Port: port, } }