From 93ba5104d5dfaa9ff964d5fcca4cbcb0f55402eb Mon Sep 17 00:00:00 2001 From: "Santiago M. Mola" Date: Tue, 13 Jun 2017 16:51:02 +0200 Subject: transport/ssh: allow passing SSH options Adds the possibility of passing options to SSH transport. Options have the form of functions modifying ssh.ClientConfig. --- plumbing/transport/ssh/common.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'plumbing/transport/ssh') diff --git a/plumbing/transport/ssh/common.go b/plumbing/transport/ssh/common.go index d53fc12..6ab0835 100644 --- a/plumbing/transport/ssh/common.go +++ b/plumbing/transport/ssh/common.go @@ -11,7 +11,16 @@ import ( ) // DefaultClient is the default SSH client. -var DefaultClient = common.NewClient(&runner{}) +var DefaultClient = NewClient() + +// NewClient creates a new SSH client with the given options. +func NewClient(opts ...ClientOption) transport.Transport { + return common.NewClient(&runner{options: opts}) +} + +// ClientOption is a function that gets a standard ssh.ClientConfig and modifies +// it. +type ClientOption func(config *ssh.ClientConfig) // DefaultAuthBuilder is the function used to create a default AuthMethod, when // the user doesn't provide any. @@ -21,10 +30,12 @@ var DefaultAuthBuilder = func(user string) (AuthMethod, error) { const DefaultPort = 22 -type runner struct{} +type runner struct { + options []ClientOption +} func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod) (common.Command, error) { - c := &command{command: cmd, endpoint: ep} + c := &command{command: cmd, endpoint: ep, options: r.options} if auth != nil { c.setAuth(auth) } @@ -42,6 +53,7 @@ type command struct { endpoint transport.Endpoint client *ssh.Client auth AuthMethod + options []ClientOption } func (c *command) setAuth(auth transport.AuthMethod) error { @@ -95,6 +107,10 @@ func (c *command) connect() error { return err } + for _, opt := range c.options { + opt(config) + } + c.client, err = ssh.Dial("tcp", c.getHostWithPort(), config) if err != nil { return err -- cgit From 7368129bc7e7394e8af7262a0764292c3fb8d3c5 Mon Sep 17 00:00:00 2001 From: "Santiago M. Mola" Date: Fri, 23 Jun 2017 20:39:28 +0200 Subject: transport/ssh: allow global *ssh.ClientConfig override A global *ssh.ClientConfig override can be set. It will be use to override values of each SSH session. --- plumbing/transport/ssh/common.go | 45 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'plumbing/transport/ssh') diff --git a/plumbing/transport/ssh/common.go b/plumbing/transport/ssh/common.go index 6ab0835..6d1c51b 100644 --- a/plumbing/transport/ssh/common.go +++ b/plumbing/transport/ssh/common.go @@ -3,6 +3,7 @@ package ssh import ( "fmt" + "reflect" "gopkg.in/src-d/go-git.v4/plumbing/transport" "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common" @@ -11,17 +12,13 @@ import ( ) // DefaultClient is the default SSH client. -var DefaultClient = NewClient() +var DefaultClient = NewClient(nil) -// NewClient creates a new SSH client with the given options. -func NewClient(opts ...ClientOption) transport.Transport { - return common.NewClient(&runner{options: opts}) +// NewClient creates a new SSH client with an optional *ssh.ClientConfig. +func NewClient(config *ssh.ClientConfig) transport.Transport { + return common.NewClient(&runner{config: config}) } -// ClientOption is a function that gets a standard ssh.ClientConfig and modifies -// it. -type ClientOption func(config *ssh.ClientConfig) - // DefaultAuthBuilder is the function used to create a default AuthMethod, when // the user doesn't provide any. var DefaultAuthBuilder = func(user string) (AuthMethod, error) { @@ -31,11 +28,11 @@ var DefaultAuthBuilder = func(user string) (AuthMethod, error) { const DefaultPort = 22 type runner struct { - options []ClientOption + config *ssh.ClientConfig } func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod) (common.Command, error) { - c := &command{command: cmd, endpoint: ep, options: r.options} + c := &command{command: cmd, endpoint: ep, config: r.config} if auth != nil { c.setAuth(auth) } @@ -53,7 +50,7 @@ type command struct { endpoint transport.Endpoint client *ssh.Client auth AuthMethod - options []ClientOption + config *ssh.ClientConfig } func (c *command) setAuth(auth transport.AuthMethod) error { @@ -107,9 +104,7 @@ func (c *command) connect() error { return err } - for _, opt := range c.options { - opt(config) - } + overrideConfig(c.config, config) c.client, err = ssh.Dial("tcp", c.getHostWithPort(), config) if err != nil { @@ -145,3 +140,25 @@ func (c *command) setAuthFromEndpoint() error { func endpointToCommand(cmd string, ep transport.Endpoint) string { return fmt.Sprintf("%s '%s'", cmd, ep.Path()) } + +func overrideConfig(overrides *ssh.ClientConfig, c *ssh.ClientConfig) { + if overrides == nil { + return + } + + vo := reflect.ValueOf(*overrides) + vc := reflect.ValueOf(*c) + for i := 0; i < vc.Type().NumField(); i++ { + vcf := vc.Field(i) + vof := vo.Field(i) + if isZeroValue(vcf) { + vcf.Set(vof) + } + } + + *c = vc.Interface().(ssh.ClientConfig) +} + +func isZeroValue(v reflect.Value) bool { + return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) +} -- cgit