Exemple #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
}
Exemple #2
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
}
Exemple #3
0
func runShowBoot(ctx CommandContext, args RunArgs, serverID string, closeTimeout chan struct{}, timeoutExit chan struct{}) error {
	// Attach to server serial
	logrus.Info("Attaching to server console ...")
	gottycli, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
	if err != nil {
		close(closeTimeout)
		return fmt.Errorf("cannot attach to server serial: %v", err)
	}
	utils.Quiet(true)
	notif, gateway, err := waitSSHConnection(ctx, args, serverID)
	if err != nil {
		close(closeTimeout)
		gottycli.ExitLoop()
		<-done
		return err
	}
	select {
	case <-timeoutExit:
		gottycli.ExitLoop()
		<-done
		utils.Quiet(false)
		return fmt.Errorf("Operation timed out")
	case sshConnection := <-notif:
		close(closeTimeout)
		gottycli.ExitLoop()
		<-done
		utils.Quiet(false)
		if sshConnection.err != nil {
			return sshConnection.err
		}
		if fingerprints := ctx.API.GetSSHFingerprintFromServer(serverID); len(fingerprints) > 0 {
			for i := range fingerprints {
				fmt.Fprintf(ctx.Stdout, "%s\n", fingerprints[i])
			}
		}
		server := sshConnection.server
		logrus.Info("Connecting to server ...")
		if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil {
			return fmt.Errorf("Connection to server failed: %v", err)
		}
	}
	return nil
}
Exemple #4
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 ...")
	serverID, err := api.CreateServer(ctx.API, &api.ConfigCreateServer{
		ImageName:         args.Image,
		Name:              args.Name,
		Bootscript:        args.Bootscript,
		Env:               env,
		AdditionalVolumes: volume,
		DynamicIPRequired: args.Gateway == "",
		IP:                args.IP,
	})
	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 ...")
	if err = api.StartServer(ctx.API, serverID, false); 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.Userdata != "" {
		addUserData(ctx, strings.Split(args.Userdata, " "), serverID)
	}
	// Sync cache on disk
	ctx.API.Sync()

	if args.Detach {
		fmt.Fprintln(ctx.Stdout, serverID)
		return nil
	}

	closeTimeout := make(chan struct{})
	timeoutExit := make(chan struct{})

	if args.Timeout > 0 {
		go func() {
			select {
			case <-time.After(time.Duration(args.Timeout) * time.Second):
				close(timeoutExit)
			case <-closeTimeout:
				break
			}
		}()
	}
	if args.ShowBoot {
		return runShowBoot(ctx, args, serverID, closeTimeout, timeoutExit)
	} else if args.Attach {
		// Attach to server serial
		logrus.Info("Attaching to server console ...")
		gottycli, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
		close(closeTimeout)
		if err != nil {
			return fmt.Errorf("cannot attach to server serial: %v", err)
		}
		<-done
		gottycli.Close()
	} else {
		notif, gateway, err := waitSSHConnection(ctx, args, serverID)
		if err != nil {
			close(closeTimeout)
			return err
		}
		select {
		case <-timeoutExit:
			return fmt.Errorf("Operation timed out")
		case sshConnection := <-notif:
			close(closeTimeout)
			if sshConnection.err != nil {
				return sshConnection.err
			}
			if fingerprints := ctx.API.GetSSHFingerprintFromServer(serverID); len(fingerprints) > 0 {
				for i := range fingerprints {
					fmt.Fprintf(ctx.Stdout, "%s\n", fingerprints[i])
				}
			}
			server := sshConnection.server
			// 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 {
					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 {
					return fmt.Errorf("command execution failed: %v", err)
				}
				logrus.Info("Command successfuly executed")
			}
		}
	}
	return nil
}
Exemple #5
0
// WaitForServerReady wait for a server state to be running, then wait for the SSH port to be available
func WaitForServerReady(api *ScalewayAPI, serverID, gateway string) (*ScalewayServer, error) {
	promise := make(chan bool)
	var server *ScalewayServer
	var err error
	var currentState string

	go func() {
		defer close(promise)

		for {
			server, err = api.GetServer(serverID)
			if err != nil {
				promise <- false
				return
			}
			if currentState != server.State {
				log.Infof("Server changed state to '%s'", server.State)
				currentState = server.State
			}
			if server.State == "running" {
				break
			}
			if server.State == "stopped" {
				err = fmt.Errorf("The server has been stopped")
				promise <- false
				return
			}
			time.Sleep(1 * time.Second)
		}

		if gateway == "" {
			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 {
			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)

		}
		promise <- true
	}()

	loop := 0
	for {
		select {
		case done := <-promise:
			utils.LogQuiet("\r \r")
			if !done {
				return nil, err
			}
			return server, nil
		case <-time.After(time.Millisecond * 100):
			utils.LogQuiet(fmt.Sprintf("\r%c\r", "-\\|/"[loop%4]))
			loop = loop + 1
			if loop == 5 {
				loop = 0
			}
		}
	}
}
Exemple #6
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
}
Exemple #7
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
}