Skip to content

Commit

Permalink
very early remote support
Browse files Browse the repository at this point in the history
ssh test code - just for reference for now
  • Loading branch information
pgalbavy committed Mar 1, 2022
1 parent e283b8b commit 05bcf72
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cmd/geneos/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ func flagsList(command string, args []string) []string {
}

func commandLS(ct ComponentType, args []string, params []string) (err error) {
if ct == Remote {
// geneos ls remote [NAME]
if len(args) == 0 {
// list remotes

}
}

switch {
case listJSON:
jsonEncoder = json.NewEncoder(log.Writer())
Expand Down
108 changes: 108 additions & 0 deletions cmd/geneos/remote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package main

import "net/url"

// remote support

// "remote" is another component type,

// e.g.
// geneos new remote X URL
//
// below is out of date

// examples:
//
// geneos add remote name URL
// URL here may be ssh://user@host etc.
// URL can include path to ITRS_HOME / ITRSHome, e.g.
// ssh://user@server/home/geneos
// else it default to same as local
//
// non ssh schemes to follow
// ssh support for agents and private key files - no passwords
// known_hosts will be checked, no changes made, missing keys will
// result in error. user must add hosts before use (ssh-keyscan)
//
// geneos ls remote NAME
// XXX - geneos init remote NAME
//
// remote 'localhost' is always implied
//
// geneos ls remote
// ... list remote locations
//
// geneos start gateway [name]@remote
//
// XXX support gateway pairs for standby - how ?
//
// XXX remote netprobes, auto configure with gateway for SANs etc.?
//
// support existing geneos-utils installs on remote

type Remotes struct {
Common
Home string `default:"{{join .Root \"remotes\" .Name}}"`
Hostname string
Port int `default:"22"`
Username string
ITRSHome string `default:"{{.Root}}"`
}

func init() {
components[Remote] = ComponentFuncs{
Instance: remoteInstance,
Command: nil,
Add: remoteAdd,
Clean: nil,
Reload: nil,
}
}

func remoteInstance(name string) interface{} {
// Bootstrap
c := &Remotes{}
c.Root = RunningConfig.ITRSHome
c.Type = Remote.String()
c.Name = name
setDefaults(&c)
return c
}

//
// 'geneos add remote NAME SSH-URL'
//
func remoteAdd(name string, username string, params []string) (c Instance, err error) {
if len(params) == 0 {
log.Fatalln("remote destination must be provided in the form of a URL")
}

c = remoteInstance(name)

u, err := url.Parse(params[0])
if err != nil {
logDebug.Println(err)
return
}

switch {
case u.Scheme == "ssh":
if u.Host == "" {
log.Fatalln("hostname must be provided")
}
setField(c, "Hostname", u.Host)
if u.Port() != "" {
setField(c, "Port", u.Port())
}
if u.User.Username() != "" {
setField(c, "Username", u.User.Username())
}
if u.Path != "" {
setField(c, "ITRSHome", u.Path)
}
return c, writeInstanceConfig(c)
default:
log.Fatalln("unsupport scheme (only ssh at the moment):", u.Scheme)
}
return
}
109 changes: 109 additions & 0 deletions cmd/geneos/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"bytes"
"fmt"
"net"
"os"
"path/filepath"

"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"golang.org/x/crypto/ssh/knownhosts"
)

var userSSHdir = ".ssh"

var privateKeyFiles = []string{
"id_rsa",
"id_ecdsa",
"id_ecdsa_sk",
"id_ed25519",
"id_ed25519_sk",
"id_dsa",
}

// ssh utilities for remote connections

func readSSHkeys(homedir string) (signers []ssh.Signer) {
for _, keyfile := range privateKeyFiles {
path := filepath.Join(homedir, ".ssh", keyfile)
key, err := os.ReadFile(path)
if err != nil {
logDebug.Println(err)
continue
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
logDebug.Println(err)
continue
}
logDebug.Println("loaded private key from", path)
signers = append(signers, signer)
}
return
}

func sshTest(username string, host string) {
socket := os.Getenv("SSH_AUTH_SOCK")
sshAgent, err := net.Dial("unix", socket)
if err != nil {
log.Fatalf("Failed to open SSH_AUTH_SOCK: %v", err)
}

agentClient := agent.NewClient(sshAgent)

homedir, err := os.UserHomeDir()
if err != nil {
log.Fatalln(err)
}
knownHostsFile := filepath.Join(homedir, ".ssh", "known_hosts")
logDebug.Println(knownHostsFile)
khcallback, err := knownhosts.New(knownHostsFile)
if err != nil {
log.Fatalln(err)
}
signers := readSSHkeys(homedir)
config := &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.PublicKeysCallback(agentClient.Signers),
ssh.PublicKeys(signers...),
},
HostKeyCallback: khcallback,
}
conn, err := ssh.Dial("tcp", host, config)
if err != nil {
log.Fatal("unable to connect: ", err)
}
defer conn.Close()

session, err := conn.NewSession()
if err != nil {
log.Fatalln(err)
}
defer session.Close()

var b bytes.Buffer
session.Stdout = &b
if err := session.Run("ls -l"); err != nil {
log.Fatal("Failed to run: " + err.Error())
}
fmt.Println(b.String())

client, err := sftp.NewClient(conn)
if err != nil {
log.Fatal(err)
}
defer client.Close()

// walk a directory
w := client.Walk("/home/pi")
for w.Step() {
if w.Err() != nil {
continue
}
log.Println(w.Path())
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ retract (
require (
github.com/fsnotify/fsnotify v1.5.1
github.com/go-mail/mail/v2 v2.3.0
github.com/pkg/sftp v1.13.4
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
)

require (
github.com/kr/fs v0.1.0 // indirect
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
Expand Down

0 comments on commit 05bcf72

Please sign in to comment.