github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/cf/ssh/options/ssh_options.go (about)

     1  package options
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"code.cloudfoundry.org/cli/cf/flags"
     8  )
     9  
    10  type TTYRequest int
    11  
    12  const (
    13  	RequestTTYAuto TTYRequest = iota
    14  	RequestTTYNo
    15  	RequestTTYYes
    16  	RequestTTYForce
    17  )
    18  
    19  type ForwardSpec struct {
    20  	ListenAddress  string
    21  	ConnectAddress string
    22  }
    23  
    24  type SSHOptions struct {
    25  	AppName             string
    26  	Command             []string
    27  	Index               uint
    28  	SkipHostValidation  bool
    29  	SkipRemoteExecution bool
    30  	TerminalRequest     TTYRequest
    31  	ForwardSpecs        []ForwardSpec
    32  }
    33  
    34  func NewSSHOptions(fc flags.FlagContext) (*SSHOptions, error) {
    35  	sshOptions := &SSHOptions{}
    36  
    37  	sshOptions.AppName = fc.Args()[0]
    38  	sshOptions.Index = uint(fc.Int("i"))
    39  	sshOptions.SkipHostValidation = fc.Bool("k")
    40  	sshOptions.SkipRemoteExecution = fc.Bool("N")
    41  	sshOptions.Command = fc.StringSlice("c")
    42  
    43  	if fc.IsSet("L") {
    44  		for _, arg := range fc.StringSlice("L") {
    45  			forwardSpec, err := sshOptions.parseLocalForwardingSpec(arg)
    46  			if err != nil {
    47  				return sshOptions, err
    48  			}
    49  			sshOptions.ForwardSpecs = append(sshOptions.ForwardSpecs, *forwardSpec)
    50  		}
    51  	}
    52  
    53  	if fc.IsSet("t") && fc.Bool("t") {
    54  		sshOptions.TerminalRequest = RequestTTYYes
    55  	}
    56  
    57  	if fc.IsSet("tt") && fc.Bool("tt") {
    58  		sshOptions.TerminalRequest = RequestTTYForce
    59  	}
    60  
    61  	if fc.Bool("T") {
    62  		sshOptions.TerminalRequest = RequestTTYNo
    63  	}
    64  
    65  	return sshOptions, nil
    66  }
    67  
    68  func (o *SSHOptions) parseLocalForwardingSpec(arg string) (*ForwardSpec, error) {
    69  	arg = strings.TrimSpace(arg)
    70  
    71  	parts := []string{}
    72  	for remainder := arg; remainder != ""; {
    73  		part, r, err := tokenizeForward(remainder)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  
    78  		parts = append(parts, part)
    79  		remainder = r
    80  	}
    81  
    82  	forwardSpec := &ForwardSpec{}
    83  	switch len(parts) {
    84  	case 4:
    85  		if parts[0] == "*" {
    86  			parts[0] = ""
    87  		}
    88  		forwardSpec.ListenAddress = fmt.Sprintf("%s:%s", parts[0], parts[1])
    89  		forwardSpec.ConnectAddress = fmt.Sprintf("%s:%s", parts[2], parts[3])
    90  	case 3:
    91  		forwardSpec.ListenAddress = fmt.Sprintf("localhost:%s", parts[0])
    92  		forwardSpec.ConnectAddress = fmt.Sprintf("%s:%s", parts[1], parts[2])
    93  	default:
    94  		return nil, fmt.Errorf("Unable to parse local forwarding argument: %q", arg)
    95  	}
    96  
    97  	return forwardSpec, nil
    98  }
    99  
   100  func tokenizeForward(arg string) (string, string, error) {
   101  	switch arg[0] {
   102  	case ':':
   103  		return "", arg[1:], nil
   104  
   105  	case '[':
   106  		parts := strings.SplitAfterN(arg, "]", 2)
   107  		if len(parts) != 2 {
   108  			return "", "", fmt.Errorf("Argument missing closing bracket: %q", arg)
   109  		}
   110  
   111  		if parts[1][0] == ':' {
   112  			return parts[0], parts[1][1:], nil
   113  		}
   114  
   115  		return "", "", fmt.Errorf("Unexpected token: %q", parts[1])
   116  
   117  	default:
   118  		parts := strings.SplitN(arg, ":", 2)
   119  		if len(parts) < 2 {
   120  			return parts[0], "", nil
   121  		}
   122  		return parts[0], parts[1], nil
   123  	}
   124  }