Skip to content

Commit 994755a

Browse files
committed
..
0 parents  commit 994755a

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

main.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"log"
9+
"os"
10+
11+
"github.com/docker/docker/api/types/container"
12+
"github.com/docker/docker/api/types/image"
13+
"github.com/docker/docker/api/types/network"
14+
"github.com/docker/docker/client"
15+
"github.com/docker/docker/pkg/stdcopy"
16+
"github.com/gliderlabs/ssh"
17+
18+
v1 "github.com/opencontainers/image-spec/specs-go/v1"
19+
)
20+
21+
func main() {
22+
ssh.Handle(func(sess ssh.Session) {
23+
j, je := json.Marshal(sess)
24+
if je == nil {
25+
fmt.Println(string(j))
26+
}
27+
_, _, isTty := sess.Pty()
28+
cfg := &container.Config{
29+
Image: sess.User(),
30+
Cmd: sess.Command(),
31+
Env: sess.Environ(),
32+
Tty: isTty,
33+
OpenStdin: true,
34+
AttachStderr: true,
35+
AttachStdin: true,
36+
AttachStdout: true,
37+
StdinOnce: true,
38+
}
39+
status, cleanup, err := dockerRun(cfg, sess)
40+
defer cleanup()
41+
if err != nil {
42+
fmt.Fprintln(sess, err)
43+
log.Println(err)
44+
}
45+
sess.Exit(int(status))
46+
})
47+
48+
log.Println("starting ssh server on port 2222...")
49+
log.Fatal(ssh.ListenAndServe(":2222", nil))
50+
}
51+
52+
func imageExistsLocally(imageName string) bool {
53+
ctx := context.Background()
54+
55+
// Create a Docker client
56+
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
57+
if err != nil {
58+
log.Fatalf("Error creating Docker client: %v", err)
59+
}
60+
61+
// List images with filters
62+
images, err := cli.ImageList(ctx, image.ListOptions{})
63+
if err != nil {
64+
log.Fatalf("Error listing images: %v", err)
65+
}
66+
67+
// Check if the image exists locally
68+
for _, image := range images {
69+
for _, tag := range image.RepoTags {
70+
if tag == imageName {
71+
return true
72+
}
73+
}
74+
}
75+
return false
76+
}
77+
78+
func dockerRun(cfg *container.Config, sess ssh.Session) (status int64, cleanup func(), err error) {
79+
docker, err := client.NewClientWithOpts(client.FromEnv)
80+
if err != nil {
81+
panic(err)
82+
}
83+
status = 255
84+
cleanup = func() {}
85+
ctx := context.Background()
86+
87+
log.Printf("User: %s", sess.User())
88+
cImage := sess.User()
89+
90+
hostConfig := container.HostConfig{}
91+
networkingConfig := network.NetworkingConfig{}
92+
platformConfig := v1.Platform{
93+
OS: "linux",
94+
Architecture: "amd64",
95+
// Variant: "minimal",
96+
}
97+
if imageExistsLocally(cImage) != true {
98+
sess.Write([]byte("Fetching Image from repository .."))
99+
reader, pullerr := docker.ImagePull(ctx, cImage, image.PullOptions{})
100+
if pullerr != nil {
101+
sess.Write([]byte("Unable to pull requested image" + string(pullerr.Error()) + "\n"))
102+
log.Printf("Error pulling image: %v", pullerr)
103+
cleanup = func() {}
104+
return
105+
}
106+
defer reader.Close()
107+
if _, err := io.Copy(os.Stdout, reader); err != nil {
108+
log.Printf("Error reading pull output: %v", pullerr)
109+
}
110+
111+
}
112+
113+
res, err := docker.ContainerCreate(ctx, cfg, &hostConfig, &networkingConfig, &platformConfig, "")
114+
if err != nil {
115+
return
116+
}
117+
cleanup = func() {
118+
docker.ContainerRemove(ctx, res.ID, container.RemoveOptions{})
119+
}
120+
opts := container.AttachOptions{
121+
Stdin: cfg.AttachStdin,
122+
Stdout: cfg.AttachStdout,
123+
Stderr: cfg.AttachStderr,
124+
Stream: true,
125+
}
126+
stream, err := docker.ContainerAttach(ctx, res.ID, opts)
127+
if err != nil {
128+
return
129+
}
130+
cleanup = func() {
131+
docker.ContainerRemove(ctx, res.ID, container.RemoveOptions{})
132+
stream.Close()
133+
}
134+
135+
outputErr := make(chan error)
136+
137+
go func() {
138+
var err error
139+
if cfg.Tty {
140+
_, err = io.Copy(sess, stream.Reader)
141+
} else {
142+
_, err = stdcopy.StdCopy(sess, sess.Stderr(), stream.Reader)
143+
}
144+
outputErr <- err
145+
}()
146+
147+
go func() {
148+
defer stream.CloseWrite()
149+
io.Copy(stream.Conn, sess)
150+
}()
151+
152+
err = docker.ContainerStart(ctx, res.ID, container.StartOptions{})
153+
if err != nil {
154+
return
155+
}
156+
if cfg.Tty {
157+
_, winCh, _ := sess.Pty()
158+
go func() {
159+
for win := range winCh {
160+
err := docker.ContainerResize(ctx, res.ID, container.ResizeOptions{
161+
Height: uint(win.Height),
162+
Width: uint(win.Width),
163+
})
164+
if err != nil {
165+
log.Println(err)
166+
break
167+
}
168+
}
169+
}()
170+
}
171+
resultC, errC := docker.ContainerWait(ctx, res.ID, container.WaitConditionNotRunning)
172+
select {
173+
case err = <-errC:
174+
return
175+
case result := <-resultC:
176+
status = result.StatusCode
177+
}
178+
err = <-outputErr
179+
return
180+
}

0 commit comments

Comments
 (0)