...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/emulator/shell.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/emulator

     1  package emulator
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"strings"
     9  
    10  	"github.com/c-bata/go-prompt"
    11  
    12  	"edge-infra.dev/pkg/sds/lib/colors"
    13  )
    14  
    15  func (em *Emulator) startShell(connectionDetails connectionData) error {
    16  	// Setting up a session isn't required as part of local shell mode, however
    17  	// making a connection can notify us of some potential issues that may occur
    18  	// during remotecli exec, such as an invalid terminal ID, so we connect
    19  	// here, and display any errors that might occur. If there are no errors
    20  	// then we can immediately End the session and continue with shell mode.
    21  	err := em.cls.Connect(em.runCtx, connectionDetails.projectID, connectionDetails.bannerID, connectionDetails.storeID, connectionDetails.terminalID)
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	err = em.cls.End()
    27  	if err != nil {
    28  		em.log.Error(err, "ending session")
    29  	}
    30  
    31  	fmt.Println(colors.Text("Shell prompt. 'Ctrl-D', 'end', 'exit' or 'q' to exit.", colors.BgGreen))
    32  	em.connectData = connectionDetails
    33  	em.shellPrompt().Run()
    34  
    35  	return nil
    36  }
    37  
    38  func (em *Emulator) shellPrompt() *prompt.Prompt {
    39  	opts := []prompt.Option{
    40  		prompt.OptionSetExitCheckerOnInput(em.handleBreakLineExit),
    41  
    42  		// History
    43  		prompt.OptionHistory(em.shellHistory.history),
    44  
    45  		// keybinding
    46  		prompt.OptionAddKeyBind(commonKeyBindings...),
    47  
    48  		// colors
    49  		prompt.OptionPreviewSuggestionTextColor(prompt.Blue),
    50  		prompt.OptionSelectedSuggestionBGColor(prompt.LightGray),
    51  		prompt.OptionSuggestionBGColor(prompt.DarkGray),
    52  
    53  		prompt.OptionPrefixTextColor(prompt.Yellow),
    54  		prompt.OptionPrefix("<> "),
    55  	}
    56  
    57  	return prompt.New(em.shellPromptExecutor,
    58  		shellPromptCompleter,
    59  		opts...,
    60  	)
    61  }
    62  
    63  func (em *Emulator) shellPromptExecutor(in string) {
    64  	if em.handleBreakLineExit(in, true) {
    65  		return
    66  	}
    67  	in = strings.TrimRight(in, "\r")
    68  
    69  	err := em.shellHistory.updateHistory(in, historyFileLimit)
    70  	if err != nil {
    71  		em.log.Error(err, "Error updating shell history file")
    72  	}
    73  
    74  	env := append(os.Environ(),
    75  		em.cls.Env()...,
    76  	)
    77  	env = append(env,
    78  		envVar("RCLI_BANNER", em.connectData.bannerID),
    79  		envVar("RCLI_STORE", em.connectData.storeID),
    80  		envVar("RCLI_TERMINAL", em.connectData.terminalID),
    81  	)
    82  
    83  	c := exec.Command("bash", "-c", in)
    84  	if c.Err != nil {
    85  		fmt.Printf("invalid command: %s\n", c.Err.Error())
    86  		return
    87  	}
    88  
    89  	c.Env = env
    90  
    91  	out, rErr := c.CombinedOutput()
    92  
    93  	var exitError *exec.ExitError
    94  	if rErr != nil && !errors.As(rErr, &exitError) {
    95  		// An ExitError indicates the process has started but exited with a non-
    96  		// zero exit code. We want output in this case to be similar to a zero
    97  		// exit code output so only need to handle a non-ExitError error here
    98  		fmt.Println("Error occurred while executing command. See logs for details")
    99  		em.log.Error(rErr, "error executing shell command")
   100  	}
   101  
   102  	fmt.Print(string(out))
   103  
   104  	exitCode := c.ProcessState.ExitCode()
   105  	if exitCode == 0 {
   106  		fmt.Println(colors.BufferedText("Exit code: %d", colors.BgGreen, exitCode))
   107  	} else {
   108  		fmt.Println(colors.BufferedText("Exit code: %d", colors.BgRed, exitCode))
   109  	}
   110  }
   111  
   112  // creates a string which can be used as an env option within golang's os/exec
   113  // package when specifying env vars
   114  func envVar(name, value string) string {
   115  	return name + "=" + value
   116  }
   117  
   118  func shellPromptCompleter(_ prompt.Document) []prompt.Suggest {
   119  	return []prompt.Suggest{}
   120  }
   121  

View as plain text