summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-12-22 16:04:54 +0700
committerShulhan <ms@kilabit.info>2023-12-22 16:05:24 +0700
commitf03c271e19f4b417a21515048fd026ddb5dff47e (patch)
tree37b2a70caecb17c14a89713a25e46aadc66ce128
parent9b3597f1aaf886e5489b230ae428b2692f9d6f56 (diff)
downloadawwan-f03c271e19f4b417a21515048fd026ddb5dff47e.tar.xz
all: support cancellation when running command using SSH client
This changes require us to replace golang.org/x/crypto with our fork, since the [ssh.Session.Run] with context is not available yet in upstream. Implements: https://todo.sr.ht/~shulhan/awwan/9
-rw-r--r--_example/localhost/test.aww3
-rw-r--r--go.mod4
-rw-r--r--go.sum8
-rw-r--r--session.go22
-rw-r--r--ssh_client.go37
5 files changed, 40 insertions, 34 deletions
diff --git a/_example/localhost/test.aww b/_example/localhost/test.aww
index 6773668..ff4019f 100644
--- a/_example/localhost/test.aww
+++ b/_example/localhost/test.aww
@@ -6,3 +6,6 @@ ls -al ~/ | grep .ssh
echo "test" > /tmp/awwan.test
cat /tmp/awwan.test
# test
+
+## Test cancellation.
+sleep 300
diff --git a/go.mod b/go.mod
index d7ed685..b19d88a 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ go 1.20
require (
git.sr.ht/~shulhan/ciigo v0.11.0
github.com/evanw/esbuild v0.19.8
- github.com/shuLhan/share v0.51.1-0.20231222030113-7a63c70fb199
+ github.com/shuLhan/share v0.51.1-0.20231222082140-8932e7ab20fc
)
require (
@@ -24,6 +24,8 @@ require (
replace github.com/evanw/esbuild => github.com/shuLhan/esbuild v0.19.9-0.20231209212032-2dc984ffc5f1
+replace golang.org/x/crypto => git.sr.ht/~shulhan/go-x-crypto v0.17.1-0.20231222080754-445dd75cd339
+
//replace github.com/shuLhan/share => ../share
//replace git.sr.ht/~shulhan/ciigo => ../ciigo
diff --git a/go.sum b/go.sum
index 56fcb8b..dd7350b 100644
--- a/go.sum
+++ b/go.sum
@@ -2,16 +2,16 @@ git.sr.ht/~shulhan/asciidoctor-go v0.5.1 h1:TuuLo+N61+qsXkiFgtiW5W1q7xHzeSID4zH+
git.sr.ht/~shulhan/asciidoctor-go v0.5.1/go.mod h1:5audSCN6jDr2+/cMvx1MdZxkCurjl/k6A5OGYWRtB0o=
git.sr.ht/~shulhan/ciigo v0.11.0 h1:t8/PqVQVOsG025WLjNjJSI4S37jN5CkY+LyC+zd1snI=
git.sr.ht/~shulhan/ciigo v0.11.0/go.mod h1:pyt2kxKvipCAO+jrjHuEXOWJ2h0ss/hnO9j7Xot3JHc=
+git.sr.ht/~shulhan/go-x-crypto v0.17.1-0.20231222080754-445dd75cd339 h1:iq2/NVwTZvvs4QWBJaBt1r+ZNaXf/cAOAO5k8Eplqtg=
+git.sr.ht/~shulhan/go-x-crypto v0.17.1-0.20231222080754-445dd75cd339/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
github.com/shuLhan/esbuild v0.19.9-0.20231209212032-2dc984ffc5f1 h1:U4DRlREmugTNkevukauQjjUsz82o3YRjtbxDILoN/Xs=
github.com/shuLhan/esbuild v0.19.9-0.20231209212032-2dc984ffc5f1/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
-github.com/shuLhan/share v0.51.1-0.20231222030113-7a63c70fb199 h1:1aREJiATkXEyEtK7OYwQ+BFIkWqAzxvoqQoHafuJwOs=
-github.com/shuLhan/share v0.51.1-0.20231222030113-7a63c70fb199/go.mod h1:rmp14f8JWRl/2/ruiWMSN6H/P7CupdCqstTNBs1Dwy4=
+github.com/shuLhan/share v0.51.1-0.20231222082140-8932e7ab20fc h1:S5i3VxbBTnEGeeUIl12EXrSzk5KHyUOGoUcFZqdBp4E=
+github.com/shuLhan/share v0.51.1-0.20231222082140-8932e7ab20fc/go.mod h1:aNDs/SjnVYXaLEEJzjmfrUFeLD6u0YHWy6pI8o8iqYw=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
-golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/session.go b/session.go
index f4c14da..f2b5a20 100644
--- a/session.go
+++ b/session.go
@@ -188,7 +188,7 @@ func (ses *Session) Get(stmt *Statement) (err error) {
}
// Put copy file from local to remote system.
-func (ses *Session) Put(req *ExecRequest, stmt *Statement) (err error) {
+func (ses *Session) Put(ctx context.Context, req *ExecRequest, stmt *Statement) (err error) {
var (
logp = `Put`
src = stmt.args[0]
@@ -213,13 +213,13 @@ func (ses *Session) Put(req *ExecRequest, stmt *Statement) (err error) {
return fmt.Errorf("%s: %w", logp, err)
}
if stmt.mode != 0 {
- err = ses.sshc.chmod(dst, stmt.mode)
+ err = ses.sshc.chmod(ctx, dst, stmt.mode)
if err != nil {
return fmt.Errorf(`%s: %w`, logp, err)
}
}
if len(stmt.owner) != 0 {
- err = ses.sshc.chown(dst, stmt.owner)
+ err = ses.sshc.chown(ctx, dst, stmt.owner)
if err != nil {
return fmt.Errorf(`%s: %w`, logp, err)
}
@@ -307,7 +307,7 @@ func (ses *Session) SudoGet(ctx context.Context, req *ExecRequest, stmt *Stateme
dst = stmt.args[1]
)
- err = ses.sshc.sudoGet(src, dst)
+ err = ses.sshc.sudoGet(ctx, src, dst)
if err != nil {
return fmt.Errorf("%s: %w", logp, err)
}
@@ -329,7 +329,7 @@ func (ses *Session) SudoGet(ctx context.Context, req *ExecRequest, stmt *Stateme
}
// SudoPut copy file from local to remote using sudo.
-func (ses *Session) SudoPut(req *ExecRequest, stmt *Statement) (err error) {
+func (ses *Session) SudoPut(ctx context.Context, req *ExecRequest, stmt *Statement) (err error) {
var (
logp = `SudoPut`
src = stmt.args[0]
@@ -343,7 +343,7 @@ func (ses *Session) SudoPut(req *ExecRequest, stmt *Statement) (err error) {
return fmt.Errorf("%s: %w", logp, err)
}
- err = ses.sshc.sudoPut(src, dst)
+ err = ses.sshc.sudoPut(ctx, src, dst)
if isVault {
var errRemove = os.Remove(src)
if errRemove != nil {
@@ -355,13 +355,13 @@ func (ses *Session) SudoPut(req *ExecRequest, stmt *Statement) (err error) {
}
if stmt.mode != 0 {
- err = ses.sshc.sudoChmod(dst, stmt.mode)
+ err = ses.sshc.sudoChmod(ctx, dst, stmt.mode)
if err != nil {
return fmt.Errorf(`%s: %w`, logp, err)
}
}
if len(stmt.owner) != 0 {
- err = ses.sshc.sudoChown(dst, stmt.owner)
+ err = ses.sshc.sudoChown(ctx, dst, stmt.owner)
if err != nil {
return fmt.Errorf(`%s: %w`, logp, err)
}
@@ -518,17 +518,17 @@ func (ses *Session) executeScriptOnRemote(ctx context.Context, req *ExecRequest,
switch stmt.kind {
case statementKindDefault:
- err = ses.sshc.conn.Execute(string(stmt.raw))
+ err = ses.sshc.conn.Execute(ctx, string(stmt.raw))
case statementKindGet:
err = ses.Get(stmt)
case statementKindLocal:
err = ExecLocal(ctx, req, stmt)
case statementKindPut:
- err = ses.Put(req, stmt)
+ err = ses.Put(ctx, req, stmt)
case statementKindSudoGet:
err = ses.SudoGet(ctx, req, stmt)
case statementKindSudoPut:
- err = ses.SudoPut(req, stmt)
+ err = ses.SudoPut(ctx, req, stmt)
}
if err != nil {
return err
diff --git a/ssh_client.go b/ssh_client.go
index b80e8f0..3007df1 100644
--- a/ssh_client.go
+++ b/ssh_client.go
@@ -5,6 +5,7 @@ package awwan
import (
"bytes"
+ "context"
"errors"
"fmt"
"io/fs"
@@ -73,7 +74,7 @@ func newSSHClient(req *ExecRequest, section *config.Section) (sshc *sshClient, e
sshc.dirHome = string(bytes.TrimSpace(stdout))
sshc.dirTmp = strings.Replace(defTmpDirPlay, `~`, sshc.dirHome, 1)
- err = sshc.mkdir(sshc.dirTmp, 0700)
+ err = sshc.mkdir(context.Background(), sshc.dirTmp, 0700)
if err != nil {
return nil, err
}
@@ -82,10 +83,10 @@ func newSSHClient(req *ExecRequest, section *config.Section) (sshc *sshClient, e
}
// chmod change the remoteFile permission.
-func (sshc *sshClient) chmod(remoteFile string, perm fs.FileMode) (err error) {
+func (sshc *sshClient) chmod(ctx context.Context, remoteFile string, perm fs.FileMode) (err error) {
var chmodStmt = fmt.Sprintf(`chmod %o %q`, perm, remoteFile)
- err = sshc.conn.Execute(chmodStmt)
+ err = sshc.conn.Execute(ctx, chmodStmt)
if err != nil {
return err
}
@@ -95,10 +96,10 @@ func (sshc *sshClient) chmod(remoteFile string, perm fs.FileMode) (err error) {
// chown change the owner of remoteFile.
// The owner parameter can be set to user only "user", group only
// ":group", or user and group "user:group".
-func (sshc *sshClient) chown(remoteFile, owner string) (err error) {
+func (sshc *sshClient) chown(ctx context.Context, remoteFile, owner string) (err error) {
var chownStmt = fmt.Sprintf(`chown %s %q`, owner, remoteFile)
- err = sshc.conn.Execute(chownStmt)
+ err = sshc.conn.Execute(ctx, chownStmt)
if err != nil {
return err
}
@@ -138,11 +139,11 @@ func (sshc *sshClient) get(remote, local string) (err error) {
}
// mkdir create directory on the remote server.
-func (sshc *sshClient) mkdir(dir string, permission uint32) (err error) {
+func (sshc *sshClient) mkdir(ctx context.Context, dir string, permission uint32) (err error) {
if sshc.sftpc == nil {
var mkdirStmt = fmt.Sprintf(`mkdir -p %s`, dir)
- err = sshc.conn.Execute(mkdirStmt)
+ err = sshc.conn.Execute(ctx, mkdirStmt)
} else {
var fa = sftp.FileAttrs{}
@@ -163,10 +164,10 @@ func (sshc *sshClient) put(local, remote string) (err error) {
}
// rmdirAll remove the directory on server recursively.
-func (sshc *sshClient) rmdirAll(dir string) (err error) {
+func (sshc *sshClient) rmdirAll(ctx context.Context, dir string) (err error) {
var rmdirStmt = fmt.Sprintf(`rm -rf %s`, dir)
- err = sshc.conn.Execute(rmdirStmt)
+ err = sshc.conn.Execute(ctx, rmdirStmt)
if err != nil {
return fmt.Errorf(`rmdirAll: %s: %w`, dir, err)
}
@@ -175,10 +176,10 @@ func (sshc *sshClient) rmdirAll(dir string) (err error) {
}
// sudoChmod change the permission of remoteFile using sudo.
-func (sshc *sshClient) sudoChmod(remoteFile string, mode fs.FileMode) (err error) {
+func (sshc *sshClient) sudoChmod(ctx context.Context, remoteFile string, mode fs.FileMode) (err error) {
var cmd = fmt.Sprintf(`sudo chmod %o %q`, mode, remoteFile)
- err = sshc.conn.Execute(cmd)
+ err = sshc.conn.Execute(ctx, cmd)
if err != nil {
return err
}
@@ -187,10 +188,10 @@ func (sshc *sshClient) sudoChmod(remoteFile string, mode fs.FileMode) (err error
}
// sudoChown change the owner of remoteFile using sudo.
-func (sshc *sshClient) sudoChown(remoteFile, owner string) (err error) {
+func (sshc *sshClient) sudoChown(ctx context.Context, remoteFile, owner string) (err error) {
var cmd = fmt.Sprintf(`sudo chown %s %q`, owner, remoteFile)
- err = sshc.conn.Execute(cmd)
+ err = sshc.conn.Execute(ctx, cmd)
if err != nil {
return err
}
@@ -201,21 +202,21 @@ func (sshc *sshClient) sudoChown(remoteFile, owner string) (err error) {
// The remote file is copied to temporary directory first, chmod-ed to
// current SSH user so it can be read.
// The temporary file then copied from remote to local.
-func (sshc *sshClient) sudoGet(remote, local string) (err error) {
+func (sshc *sshClient) sudoGet(ctx context.Context, remote, local string) (err error) {
var (
remoteBase = filepath.Base(remote)
remoteTmp = filepath.Join(sshc.dirTmp, remoteBase)
cpRemoteToTmp = fmt.Sprintf(`sudo cp -f %s %s`, remote, remoteTmp)
)
- err = sshc.conn.Execute(cpRemoteToTmp)
+ err = sshc.conn.Execute(ctx, cpRemoteToTmp)
if err != nil {
return err
}
var chmod = fmt.Sprintf(`sudo chown %s %s`, sshc.section.User(), remoteTmp)
- err = sshc.conn.Execute(chmod)
+ err = sshc.conn.Execute(ctx, chmod)
if err != nil {
return err
}
@@ -227,7 +228,7 @@ func (sshc *sshClient) sudoGet(remote, local string) (err error) {
// sudoPut copy local file to remote using sudo.
// The file from local copied to remote in temporary directory first, and
// then the temporary file moved to original destination using sudo.
-func (sshc *sshClient) sudoPut(local, remote string) (err error) {
+func (sshc *sshClient) sudoPut(ctx context.Context, local, remote string) (err error) {
var (
baseName = filepath.Base(local)
remoteTmp = filepath.Join(sshc.dirTmp, baseName)
@@ -244,6 +245,6 @@ func (sshc *sshClient) sudoPut(local, remote string) (err error) {
var moveStmt = fmt.Sprintf(`sudo mv -f %s %s`, remoteTmp, remote)
- err = sshc.conn.Execute(moveStmt)
+ err = sshc.conn.Execute(ctx, moveStmt)
return err
}