Skip to content

Commit

Permalink
Feature/sshlib (#105)
Browse files Browse the repository at this point in the history
* Adds ssh agent support

* Better error out

* Shell output
  • Loading branch information
bomoko authored Oct 24, 2023
1 parent 77737ab commit 604ee55
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 41 deletions.
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ require (
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.9.0
github.com/withmandala/go-log v0.1.0
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa
golang.org/x/text v0.3.8 // indirect
golang.org/x/crypto v0.13.0
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.64.0 // indirect
gopkg.in/yaml.v2 v2.4.0
Expand Down
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -361,6 +363,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -400,6 +403,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -428,6 +433,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -488,9 +494,17 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -502,6 +516,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down Expand Up @@ -562,6 +580,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
91 changes: 52 additions & 39 deletions synchers/syncutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,28 @@ func SyncRunSourceCommand(remoteEnvironment Environment, syncer Syncer, dryRun b
}

var execString string

if remoteEnvironment.EnvironmentName == LOCAL_ENVIRONMENT_NAME {
execString = command
} else {
execString = GenerateRemoteCommand(remoteEnvironment, command, sshOptions)
}
execString = command

utils.LogExecutionStep("Running the following for source", execString)

if !dryRun {
err, response, errstring := utils.Shellout(execString)
if err != nil {
log.Printf(errstring)
return err
}
if response != "" && debug == false {
log.Println(response)

if remoteEnvironment.EnvironmentName == LOCAL_ENVIRONMENT_NAME {
err, response, errstring := utils.Shellout(execString)
if err != nil {
log.Printf(errstring)
return err
}
if response != "" && debug == false {
log.Println(response)
}
} else {
err, output := utils.RemoteShellout(execString, remoteEnvironment.GetOpenshiftProjectName(), sshOptions.Host, sshOptions.Port, sshOptions.PrivateKey)
utils.LogDebugInfo(output, nil)
if err != nil {
utils.LogFatalError("Unable to exec remote command: "+err.Error(), nil)
return err
}
}
}
}
Expand Down Expand Up @@ -227,16 +232,22 @@ func SyncRunTransfer(sourceEnvironment Environment, targetEnvironment Environmen
sourceEnvironmentName,
targetEnvironmentName)

if executeRsyncRemotelyOnTarget {
execString = GenerateRemoteCommand(targetEnvironment, execString, sshOptions)
}

utils.LogExecutionStep(fmt.Sprintf("Running the following for target (%s)", targetEnvironment.EnvironmentName), execString)

if !dryRun {
if err, _, errstring := utils.Shellout(execString); err != nil {
utils.LogFatalError(errstring, nil)
return err

if executeRsyncRemotelyOnTarget {
err, output := utils.RemoteShellout(execString, targetEnvironment.GetOpenshiftProjectName(), sshOptions.Host, sshOptions.Port, sshOptions.PrivateKey)
utils.LogDebugInfo(output, nil)
if err != nil {
utils.LogFatalError("Unable to exec remote command: "+err.Error(), nil)
return err
}
} else {
if err, _, errstring := utils.Shellout(execString); err != nil {
utils.LogFatalError(errstring, nil)
return err
}
}
}

Expand All @@ -256,28 +267,27 @@ func SyncRunTargetCommand(targetEnvironment Environment, syncer Syncer, dryRun b
}

var execString string
targetCommands, commandErr := targetCommand.GetCommand()
tcomm, commandErr := targetCommand.GetCommand()
if commandErr != nil {
return commandErr
}

if targetEnvironment.EnvironmentName == LOCAL_ENVIRONMENT_NAME {
execString = targetCommands
} else {
execString = GenerateRemoteCommand(targetEnvironment, targetCommands, sshOptions)
}
execString = tcomm

utils.LogExecutionStep(fmt.Sprintf("Running the following for target (%s)", targetEnvironment.EnvironmentName), execString)
if !dryRun {
err, outstring, errstring := utils.Shellout(execString)
if err != nil {
utils.LogError(outstring, nil)
if errstring != "" {
if targetEnvironment.EnvironmentName == LOCAL_ENVIRONMENT_NAME {
err, _, errstring := utils.Shellout(execString)
if err != nil {
utils.LogFatalError(errstring, nil)
} else {
utils.LogFatalError(fmt.Sprintf("Error: %s", err), nil)
return err
}
} else {
err, output := utils.RemoteShellout(execString, targetEnvironment.GetOpenshiftProjectName(), sshOptions.Host, sshOptions.Port, sshOptions.PrivateKey)
utils.LogDebugInfo(output, nil)
if err != nil {
utils.LogFatalError("Unable to exec remote command: "+err.Error(), nil)
return err
}
return err
}
}
}
Expand All @@ -299,13 +309,16 @@ func SyncCleanUp(environment Environment, syncer Syncer, dryRun bool, sshOptions
transferResourceName := fileToCleanup
execString := fmt.Sprintf("rm -r %s || true", transferResourceName)

if environment.EnvironmentName != LOCAL_ENVIRONMENT_NAME {
execString = GenerateRemoteCommand(environment, execString, sshOptions)
}

utils.LogExecutionStep("Running the following", execString)

if !dryRun {
if environment.EnvironmentName != LOCAL_ENVIRONMENT_NAME {
err, output := utils.RemoteShellout(execString, environment.GetOpenshiftProjectName(), sshOptions.Host, sshOptions.Port, sshOptions.PrivateKey)
utils.LogDebugInfo(output, nil)
if err != nil {
utils.LogFatalError("Unable to exec remote command: "+err.Error(), nil)
return err
}
}
err, _, errstring := utils.Shellout(execString)
if err != nil {
utils.LogFatalError(errstring, nil)
Expand Down
87 changes: 87 additions & 0 deletions utils/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package utils

import (
"bytes"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"net"
"os"
"os/exec"
)

Expand All @@ -16,3 +20,86 @@ func Shellout(command string) (error, string, string) {
err := cmd.Run()
return err, stdout.String(), stderr.String()
}

func RemoteShellout(command string, remoteUser string, remoteHost string, remotePort string, privateKeyfile string) (error, string) {
// Read the private key file

skipAgent := false

var authMethods []ssh.AuthMethod

if skipAgent != true {
// Connect to SSH agent to ask for unencrypted private keys
if sshAgentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
sshAgent := agent.NewClient(sshAgentConn)
keys, _ := sshAgent.List()
if len(keys) > 0 {
agentAuthmethods := ssh.PublicKeysCallback(sshAgent.Signers)
authMethods = append(authMethods, agentAuthmethods)
}
}
}

privateKeyBytes, err := os.ReadFile(privateKeyfile)

// if there are authMethods already, let's keep going
if err != nil && len(authMethods) == 0 {
return err, ""
}

if len(privateKeyBytes) > 0 {
// Parse the private key
signer, err := ssh.ParsePrivateKey(privateKeyBytes)
if err != nil {
return err, ""
}

// SSH client configuration
authKeys := ssh.PublicKeys(signer)
authMethods = append(authMethods, authKeys)
}

config := &ssh.ClientConfig{
User: remoteUser,
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

// Connect to the remote server
client, err := ssh.Dial("tcp", remoteHost+":"+remotePort, config)
if err != nil {
return err, ""
}

defer client.Close()

// Create a session
session, err := client.NewSession()
if err != nil {
return err, ""
}
defer session.Close()

var outputBuffer bytes.Buffer

// Set up pipes for stdin, stdout, and stderr
session.Stdout = &outputBuffer
session.Stderr = &outputBuffer
//stdin, err := session.StdinPipe()
if err != nil {
return err, ""
}

// Start the remote command
err = session.Start(command)
if err != nil {
return err, outputBuffer.String()
}
// Wait for the command to complete
err = session.Wait()
if err != nil {
return err, outputBuffer.String()
}

return nil, outputBuffer.String()
}

0 comments on commit 604ee55

Please sign in to comment.