Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit b3647bb

Browse files
committed
Added remote execution example
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
1 parent 3c28884 commit b3647bb

5 files changed

Lines changed: 278 additions & 0 deletions

File tree

examples/rexec/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# rexec
2+
3+
rexec is a sample application demonstrating libchan nested channels and
4+
bytestreams through remote executation calls. This is a minimal
5+
implementation to demonstrate the usage of libchan.
6+
7+
### Usage
8+
9+
Server
10+
~~~~
11+
$ cd rexec_server
12+
$ go build .
13+
$ ./rexec_server
14+
~~~~
15+
16+
Client
17+
~~~~
18+
$ go build .
19+
$ ./rexec /bin/echo "hello"
20+
hello
21+
$ ./rexec /bin/sh -c "exit 4"
22+
$ echo $?
23+
4
24+
~~~~
25+
26+
### Usage with TLS
27+
Server
28+
~~~~
29+
$ TLS_CERT=./cert.pem TLS_KEY=./key.pem ./rexec_server
30+
~~~~
31+
32+
Client
33+
~~~~
34+
$ USE_TLS=true ./rexec /bin/echo "hello"
35+
hello
36+
~~~~

examples/rexec/client.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package main
2+
3+
import (
4+
"crypto/tls"
5+
"io"
6+
"log"
7+
"net"
8+
"os"
9+
10+
"github.com/docker/libchan"
11+
"github.com/docker/libchan/spdy"
12+
)
13+
14+
type RemoteCommand struct {
15+
Cmd string
16+
Args []string
17+
Stdin io.Writer
18+
Stdout io.Reader
19+
Stderr io.Reader
20+
StatusChan libchan.Sender
21+
}
22+
23+
type CommandResponse struct {
24+
Status int
25+
}
26+
27+
func main() {
28+
if len(os.Args) < 2 {
29+
log.Fatal("usage: <command> [<arg> ]")
30+
}
31+
32+
var client net.Conn
33+
var err error
34+
if os.Getenv("USE_TLS") != "" {
35+
client, err = tls.Dial("tcp", "127.0.0.1:9323", &tls.Config{InsecureSkipVerify: true})
36+
} else {
37+
client, err = net.Dial("tcp", "127.0.0.1:9323")
38+
}
39+
if err != nil {
40+
log.Fatal(err)
41+
}
42+
43+
transport, err := spdy.NewClientTransport(client)
44+
if err != nil {
45+
log.Fatal(err)
46+
}
47+
sender, err := transport.NewSendChannel()
48+
if err != nil {
49+
log.Fatal(err)
50+
}
51+
52+
receiver, remoteSender := libchan.Pipe()
53+
54+
command := &RemoteCommand{
55+
Cmd: os.Args[1],
56+
Args: os.Args[2:],
57+
Stdin: os.Stdin,
58+
Stdout: os.Stdout,
59+
Stderr: os.Stderr,
60+
StatusChan: remoteSender,
61+
}
62+
63+
err = sender.Send(command)
64+
if err != nil {
65+
log.Fatal(err)
66+
}
67+
68+
response := &CommandResponse{}
69+
err = receiver.Receive(response)
70+
if err != nil {
71+
log.Fatal(err)
72+
}
73+
74+
os.Exit(response.Status)
75+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIC1zCCAcGgAwIBAgIBADALBgkqhkiG9w0BAQUwEDEOMAwGA1UEChMFcmV4ZWMw
3+
HhcNMTMxMjMxMjM1OTU5WhcNNDkxMjMxMjM1OTU5WjAQMQ4wDAYDVQQKEwVyZXhl
4+
YzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZs3mSUB352e5yCh0ho
5+
nbr/dvvHaHsS2KERyILQBynqbD2DvLpdL2n1IYb+uHFt6XPnZKnkCznGviVLPGcf
6+
WahzG04updvfY/uXh1m7Wz+J/DDldkqGE5PO39uC1rKkbTGKnh21U5LVeRfzgznN
7+
VpEha0IWBEZIdRm/rpB9OynUH/yzmtTxmQnVW6QvggTEm0HcY4sGRRwpcR/8QWMr
8+
v49OnHujMAndrWCYZ8O+9FNd/dIWlmdCq2WxD/0fQ/Ylkml8hpvPBmVdcBom7FOD
9+
HGoMiiW+M9YvZfMYl+bckRKyF0IQatW7BTWP9GduyBP8CHU1DqBgoMSlKt+yOWt9
10+
pzECAwEAAaNAMD4wDgYDVR0PAQH/BAQDAgCgMBAGA1UdEwEB/wQGMAQCAgD/MBoG
11+
A1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATALBgkqhkiG9w0BAQUDggEBAC/efFHQ
12+
AO19EWm4KFlkw2FMOy+xwkCuUCL0fXnCbOezGCzYpBWMcE5JFA9Znd7LCYLvRMmC
13+
LoFjAJRyjPPiKoAENv+wDKVnbfygVsxdQ+WVSmkK7TuElgDbzUcgDepeZGGx623Q
14+
9waiJaeBJGA9zvvoheabAuYQ8VYSbxO/nLQWSzwg5e1cosupWQSojftys8eSBcv2
15+
3DK8+Um9U5mASFwyclk/0gpZKF2SmjXweEcWqELLZtFJCZlXa2yzz0UxIzmAYbFP
16+
Hd7y0jA+UCPdukS9gf0YEW4ak2U8kYHuA6F0lbvWZH2wCy6XQGam9XZptj9WOo0v
17+
YLTya68Tf6vCre4=
18+
-----END CERTIFICATE-----
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpAIBAAKCAQEAxmzeZJQHfnZ7nIKHSGiduv92+8doexLYoRHIgtAHKepsPYO8
3+
ul0vafUhhv64cW3pc+dkqeQLOca+JUs8Zx9ZqHMbTi6l299j+5eHWbtbP4n8MOV2
4+
SoYTk87f24LWsqRtMYqeHbVTktV5F/ODOc1WkSFrQhYERkh1Gb+ukH07KdQf/LOa
5+
1PGZCdVbpC+CBMSbQdxjiwZFHClxH/xBYyu/j06ce6MwCd2tYJhnw770U1390haW
6+
Z0KrZbEP/R9D9iWSaXyGm88GZV1wGibsU4McagyKJb4z1i9l8xiX5tyRErIXQhBq
7+
1bsFNY/0Z27IE/wIdTUOoGCgxKUq37I5a32nMQIDAQABAoIBAF1dWqNut7v8mhtB
8+
m9ApUZZsoBrGcFYAvyfCy1sp8UT6xeWH+CSktiugKR9w+W597iwYQ9hgshuEdXHs
9+
3cYUDUbiqoV2E5rKmSwH16sUKlJSZfTH84oLXmjdHZ4XCVjTX4HBHLcT2/gqNCld
10+
7nAjO0lctTBKVcaQT3FHLSdVlaIPFlbS4+eB6QgSLWhY56GL5lGF3kqq+N1DT81H
11+
LMnJgLcl5nFy84cCvtPljosTP6tp4yULyqAfgDV9JA6KwKIzqJwH8WP3W09bKLuD
12+
YEF5kiFPCYZ9bykfPs8tCgl619qdlvaA0kmN7tN7z59C0SMm64mSBFfMYB1DjA9V
13+
FLwwMDECgYEA00TA1ixHKCrDYBWgFGI9p0hcgrwOgNFL7MiTW7JTpehsV1Uew/sn
14+
o92Ba3IuUtrS4Q9dXVoWFrYSdBhEhCZsoOgJtlQRUI6udhVg78bCtJ1rzbU+HCpU
15+
TqcjEvfoeRzhUCcKslHdgj6Wi0kPw4tbwfpkf3JoUNtO7dUYu4KyURUCgYEA8G/6
16+
lRYzPYrBnBlyA/VmFnCYKYbsYXVkvjly9VcAJLzR+Ayt1uz+3HQNXDs8LfSO4G7A
17+
kHX/tRATBPaOKhthwIUSXnsn2o86C9Y7qk5S+bx2ijOOzDZf+AVJrifJvEfTEpE/
18+
tcF8sZ3u3dcUp+uGIKLuqXsewhRkcsNHQ0WobK0CgYEAt4DUbjLva3gZU2/1Jz9d
19+
hdtYX0Ww4zrn07c0J0VxWn3S/Ng2bMvN1osjSoxWqCjhWhLaaadB4GAtDyG1AYPO
20+
fsSNCw1iLLKB3pcbJ6lgnTjO1lJCrHwn1lleIa+rAOeQ3OnMZK6u095BLKI9Sv/U
21+
p1wxxnE9Il4a5IFfhh8zezECgYAoC05dtDPWhRyXxfkiRaW6CQieqfUGikm8EM9f
22+
oxzIAZaqzFnLmO8dgkqTWN49/SQqpud1Z+Gtoz63reShiKvwJ3mWuMY7dW1CeWy4
23+
gZD6PPQ1Mj8PLeMv6JmL4t6LeB7kUcKdn9sHrfkRg3fSO7y8BMbg/TtzMXhFUNa2
24+
koxphQKBgQDC2b9vzR2I8UgK63RjcFJQjsyNbBcF3FJ7+eaakRkTflOaBkeuXTs4
25+
ZxO9c0ShMVZ6lcBrll2ZrHx1yLrUFgQYYvzJQvMjG1Y7Up4l2gurMvckfG2lGI/B
26+
NHuXlarw598fJP9PX75TyD3+ayDtm/pazBH9kSMupNJ7RNVuKy5v8w==
27+
-----END RSA PRIVATE KEY-----
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package main
2+
3+
import (
4+
"crypto/tls"
5+
"io"
6+
"log"
7+
"net"
8+
"os"
9+
"os/exec"
10+
"syscall"
11+
12+
"github.com/docker/libchan"
13+
"github.com/docker/libchan/spdy"
14+
)
15+
16+
type RemoteCommand struct {
17+
Cmd string
18+
Args []string
19+
Stdin io.Reader
20+
Stdout io.WriteCloser
21+
Stderr io.WriteCloser
22+
StatusChan libchan.Sender
23+
}
24+
25+
type CommandResponse struct {
26+
Status int
27+
}
28+
29+
func main() {
30+
cert := os.Getenv("TLS_CERT")
31+
key := os.Getenv("TLS_KEY")
32+
33+
var listener net.Listener
34+
if cert != "" && key != "" {
35+
tlsCert, err := tls.LoadX509KeyPair(cert, key)
36+
if err != nil {
37+
log.Fatal(err)
38+
}
39+
40+
tlsConfig := &tls.Config{
41+
InsecureSkipVerify: true,
42+
Certificates: []tls.Certificate{tlsCert},
43+
}
44+
45+
listener, err = tls.Listen("tcp", "localhost:9323", tlsConfig)
46+
if err != nil {
47+
log.Fatal(err)
48+
}
49+
} else {
50+
var err error
51+
listener, err = net.Listen("tcp", "localhost:9323")
52+
if err != nil {
53+
log.Fatal(err)
54+
}
55+
}
56+
57+
tl, err := spdy.NewTransportListener(listener, spdy.NoAuthenticator)
58+
if err != nil {
59+
log.Fatal(err)
60+
}
61+
62+
for {
63+
t, err := tl.AcceptTransport()
64+
if err != nil {
65+
log.Print(err)
66+
break
67+
}
68+
69+
go func() {
70+
for {
71+
receiver, err := t.WaitReceiveChannel()
72+
if err != nil {
73+
log.Print(err)
74+
break
75+
}
76+
77+
go func() {
78+
for {
79+
command := &RemoteCommand{}
80+
err := receiver.Receive(command)
81+
if err != nil {
82+
log.Print(err)
83+
break
84+
}
85+
86+
cmd := exec.Command(command.Cmd, command.Args...)
87+
cmd.Stdout = command.Stdout
88+
cmd.Stderr = command.Stderr
89+
90+
stdin, err := cmd.StdinPipe()
91+
if err != nil {
92+
log.Print(err)
93+
break
94+
}
95+
go func() {
96+
io.Copy(stdin, command.Stdin)
97+
stdin.Close()
98+
}()
99+
100+
res := cmd.Run()
101+
command.Stdout.Close()
102+
command.Stderr.Close()
103+
returnResult := &CommandResponse{}
104+
if res != nil {
105+
if exiterr, ok := res.(*exec.ExitError); ok {
106+
returnResult.Status = exiterr.Sys().(syscall.WaitStatus).ExitStatus()
107+
} else {
108+
log.Print(res)
109+
returnResult.Status = 10
110+
}
111+
}
112+
113+
err = command.StatusChan.Send(returnResult)
114+
if err != nil {
115+
log.Print(err)
116+
}
117+
}
118+
}()
119+
}
120+
}()
121+
}
122+
}

0 commit comments

Comments
 (0)