diff --git a/go.mod b/go.mod index 901f6a31..569b9660 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel/trace v1.29.0 go.uber.org/goleak v1.3.0 - golang.org/x/crypto v0.31.0 golang.org/x/net v0.33.0 gopkg.in/go-playground/assert.v1 v1.2.1 ) diff --git a/go.sum b/go.sum index 35135fbf..fe871fb3 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 h1:t95Grn2 github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230/go.mod h1:t2EzW1qybnPDQ3LR/GgeF0GOzHUXT5IVMLP2gkW1cmc= github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 h1:a0MBqYm44o0NcthLKCljZHe1mxlN6oahCQHHThnSwB4= github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22/go.mod h1:/B7V22rcz4860iDqstGvia/2+IYWXf3/JdQCVd/1D2A= -github.com/bmc-toolbox/common v0.0.0-20241031162543-6b96e5981a0d h1:dMmFDAAEpXizInaNwPSa5LM6tX/xDIPKjL6v9jYfMxo= -github.com/bmc-toolbox/common v0.0.0-20241031162543-6b96e5981a0d/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bmc-toolbox/common v0.0.0-20250112191656-b6de52e8303d h1:5c0jhS9jNLm1t3GVEESsWv+p6recFRLGW90zp8HDIDs= github.com/bmc-toolbox/common v0.0.0-20250112191656-b6de52e8303d/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= @@ -75,8 +73,6 @@ go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt3 go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -87,8 +83,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/sshclient/sshclient.go b/internal/sshclient/sshclient.go deleted file mode 100644 index 0533e88a..00000000 --- a/internal/sshclient/sshclient.go +++ /dev/null @@ -1,127 +0,0 @@ -package sshclient - -import ( - "fmt" - "net" - "sync" - "time" - - "golang.org/x/crypto/ssh" -) - -const ( - clientTimeout = 15 * time.Second - sshPort = "22" -) - -// SSHClient implements out common abstraction for SSH -type SSHClient struct { - addr string - config *ssh.ClientConfig - client *ssh.Client - lock *sync.Mutex -} - -// New creates a new SSH client -func New(addr string, username string, password string) (*SSHClient, error) { - cfg := &ssh.ClientConfig{ - User: username, - Auth: []ssh.AuthMethod{ - ssh.Password(password), - ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) { - if len(questions) == 0 { - return []string{}, nil - } - if len(questions) == 1 { - return []string{password}, nil - } - return []string{}, fmt.Errorf("unsupported keyboard-interactive auth") - }), - }, - HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { - return nil - }, - Timeout: clientTimeout, - } - - addr, err := checkAndBuildAddr(addr) - if err != nil { - return nil, err - } - - return &SSHClient{addr: addr, config: cfg, lock: new(sync.Mutex)}, nil -} - -// Run executes the given command and returns the output as a string -func (s *SSHClient) Run(command string) (string, error) { - if err := s.createClient(); err != nil { - return "", err - } - - return s.run(command) -} - -func (s *SSHClient) run(command string) (string, error) { - session, err := s.client.NewSession() - if err != nil { - return "", err - } - defer session.Close() - - output, err := session.CombinedOutput(command) - return string(output), err -} - -// Close sends "exit" command and closes the SSH connection -func (s *SSHClient) Close() error { - s.lock.Lock() - defer s.lock.Unlock() - - if s.client == nil { - return nil - } - defer func() { - s.client.Close() - s.client = nil - }() - - // some vendors have issues with the bmc if you don't do it - if _, err := s.run("exit"); err != nil { - return err - } - - return nil -} - -func (s *SSHClient) createClient() error { - s.lock.Lock() - defer s.lock.Unlock() - if s.client != nil { - return nil // TODO: check client is alive - } - - c, err := ssh.Dial("tcp", s.addr, s.config) - if err != nil { - return fmt.Errorf("unable to connect to bmc: %w", err) - } - s.client = c - - return nil -} - -func checkAndBuildAddr(addr string) (string, error) { - if addr == "" { - return "", fmt.Errorf("address is empty") - } - - if _, _, err := net.SplitHostPort(addr); err == nil { - return addr, nil - } - - addrWithPort := net.JoinHostPort(addr, sshPort) - if _, _, err := net.SplitHostPort(addrWithPort); err == nil { - return addrWithPort, nil - } - - return "", fmt.Errorf("failed to parse address %q", addr) -} diff --git a/internal/sshclient/sshclient_test.go b/internal/sshclient/sshclient_test.go deleted file mode 100644 index d68af297..00000000 --- a/internal/sshclient/sshclient_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package sshclient - -import "testing" - -func Test_checkAndBuildAddr(t *testing.T) { - type args struct { - addr string - } - tests := []struct { - name string - args args - want string - wantErr bool - }{ - { - name: "OK: only IPv4 address", - args: args{ - "127.0.0.1", - }, - want: "127.0.0.1:22", - wantErr: false, - }, - { - name: "OK: only IPv6 address", - args: args{ - "fe80::1", - }, - want: "[fe80::1]:22", - wantErr: false, - }, - { - name: "OK: only host", - args: args{ - "localhost", - }, - want: "localhost:22", - wantErr: false, - }, - { - name: "OK: IPv4 address with port", - args: args{ - "127.0.0.1:2222", - }, - want: "127.0.0.1:2222", - wantErr: false, - }, - { - name: "OK: IPv6 address with port", - args: args{ - "[fe80::1]:2222", - }, - want: "[fe80::1]:2222", - wantErr: false, - }, - { - name: "OK: host with port", - args: args{ - "localhost:2222", - }, - want: "localhost:2222", - wantErr: false, - }, - { - name: "Not OK: empty addr", - args: args{ - "", - }, - want: "", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := checkAndBuildAddr(tt.args.addr) - t.Log(got) - if (err != nil) != tt.wantErr { - t.Errorf("checkAndBuildAddr() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("checkAndBuildAddr() got = %v, want %v", got, tt.want) - } - }) - } -}