code.cloudfoundry.org/cli@v7.1.0+incompatible/command/v7/ssh_command.go (about)

     1  package v7
     2  
     3  import (
     4  	"code.cloudfoundry.org/cli/actor/sharedaction"
     5  	"code.cloudfoundry.org/cli/command"
     6  	"code.cloudfoundry.org/cli/command/flag"
     7  	"code.cloudfoundry.org/cli/command/translatableerror"
     8  	"code.cloudfoundry.org/cli/util/clissh"
     9  )
    10  
    11  //go:generate counterfeiter . SharedSSHActor
    12  
    13  type SharedSSHActor interface {
    14  	ExecuteSecureShell(sshClient sharedaction.SecureShellClient, sshOptions sharedaction.SSHOptions) error
    15  }
    16  
    17  type SSHCommand struct {
    18  	BaseCommand
    19  
    20  	RequiredArgs          flag.AppName             `positional-args:"yes"`
    21  	ProcessIndex          uint                     `long:"app-instance-index" short:"i" default:"0" description:"App process instance index"`
    22  	Commands              []string                 `long:"command" short:"c" description:"Command to run"`
    23  	DisablePseudoTTY      bool                     `long:"disable-pseudo-tty" short:"T" description:"Disable pseudo-tty allocation"`
    24  	ForcePseudoTTY        bool                     `long:"force-pseudo-tty" description:"Force pseudo-tty allocation"`
    25  	LocalPortForwardSpecs []flag.SSHPortForwarding `short:"L" description:"Local port forward specification"`
    26  	ProcessType           string                   `long:"process" default:"web" description:"App process name"`
    27  	RequestPseudoTTY      bool                     `long:"request-pseudo-tty" short:"t" description:"Request pseudo-tty allocation"`
    28  	SkipHostValidation    bool                     `long:"skip-host-validation" short:"k" description:"Skip host key validation. Not recommended!"`
    29  	SkipRemoteExecution   bool                     `long:"skip-remote-execution" short:"N" description:"Do not execute a remote command"`
    30  
    31  	usage           interface{} `usage:"CF_NAME ssh APP_NAME [--process PROCESS] [-i INDEX] [-c COMMAND]...\n   [-L [BIND_ADDRESS:]LOCAL_PORT:REMOTE_HOST:REMOTE_PORT]... [--skip-remote-execution]\n   [--disable-pseudo-tty | --force-pseudo-tty | --request-pseudo-tty] [--skip-host-validation]"`
    32  	relatedCommands interface{} `related_commands:"allow-space-ssh, enable-ssh, space-ssh-allowed, ssh-code, ssh-enabled"`
    33  	allproxy        interface{} `environmentName:"all_proxy" environmentDescription:"Specify a proxy server to enable proxying for all requests"`
    34  
    35  	SSHActor  SharedSSHActor
    36  	SSHClient *clissh.SecureShell
    37  }
    38  
    39  func (cmd *SSHCommand) Setup(config command.Config, ui command.UI) error {
    40  	err := cmd.BaseCommand.Setup(config, ui)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	sharedActor := sharedaction.NewActor(config)
    46  	cmd.SharedActor = sharedActor
    47  	cmd.SSHActor = sharedActor
    48  	cmd.SSHClient = clissh.NewDefaultSecureShell()
    49  
    50  	return nil
    51  }
    52  
    53  func (cmd SSHCommand) Execute(args []string) error {
    54  
    55  	err := cmd.SharedActor.CheckTarget(true, true)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	ttyOption, err := cmd.EvaluateTTYOption()
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	var forwardSpecs []sharedaction.LocalPortForward
    66  	for _, spec := range cmd.LocalPortForwardSpecs {
    67  		forwardSpecs = append(forwardSpecs, sharedaction.LocalPortForward(spec))
    68  	}
    69  
    70  	sshAuth, warnings, err := cmd.Actor.GetSecureShellConfigurationByApplicationNameSpaceProcessTypeAndIndex(
    71  		cmd.RequiredArgs.AppName,
    72  		cmd.Config.TargetedSpace().GUID,
    73  		cmd.ProcessType,
    74  		cmd.ProcessIndex,
    75  	)
    76  	cmd.UI.DisplayWarnings(warnings)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	err = cmd.SSHActor.ExecuteSecureShell(
    82  		cmd.SSHClient,
    83  		sharedaction.SSHOptions{
    84  			Commands:              cmd.Commands,
    85  			Endpoint:              sshAuth.Endpoint,
    86  			HostKeyFingerprint:    sshAuth.HostKeyFingerprint,
    87  			LocalPortForwardSpecs: forwardSpecs,
    88  			Passcode:              sshAuth.Passcode,
    89  			SkipHostValidation:    cmd.SkipHostValidation,
    90  			SkipRemoteExecution:   cmd.SkipRemoteExecution,
    91  			TTYOption:             ttyOption,
    92  			Username:              sshAuth.Username,
    93  		})
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  // EvaluateTTYOption determines which TTY options are mutually exclusive and
   102  // returns an error accordingly.
   103  func (cmd SSHCommand) EvaluateTTYOption() (sharedaction.TTYOption, error) {
   104  	var count int
   105  
   106  	option := sharedaction.RequestTTYAuto
   107  	if cmd.DisablePseudoTTY {
   108  		option = sharedaction.RequestTTYNo
   109  		count++
   110  	}
   111  	if cmd.ForcePseudoTTY {
   112  		option = sharedaction.RequestTTYForce
   113  		count++
   114  	}
   115  	if cmd.RequestPseudoTTY {
   116  		option = sharedaction.RequestTTYYes
   117  		count++
   118  	}
   119  
   120  	if count > 1 {
   121  		return option, translatableerror.ArgumentCombinationError{Args: []string{
   122  			"--disable-pseudo-tty", "-T", "--force-pseudo-tty", "--request-pseudo-tty", "-t",
   123  		}}
   124  	}
   125  
   126  	return option, nil
   127  }