Skip to content

Commit

Permalink
Merge pull request #42 from dyweb/example/udash/docker-log-exec
Browse files Browse the repository at this point in the history
[Partial][example][ui] Udash docker log and exec

- implemented docker log in client and dk cli #40 , it has a package for deduplex stream (stdout, stderr)
- implemented docker exec in client and dk cli #41 , need to create a new connection manually and read the response (I actually don't need to get http client's transport, I can keep the original addr and dial it directly, need a dedicated tcp connection anyway)
- implemented web terminal using xterm and gorillawebsocket #46 , it's tricky if you don't understand all the pty stuff, most examples didn't say that (maybe it's too obvious?), when use pty, you have echo for what you type, so you won't see anything when type in xterm and when it attach to socket it will send each character as a single message, and you don't need to do any buffering on server side (pty will do that), same applies to stdout, you just copy what you read and write to websocket connection (I xterm might did some buffer on that). The gorilla example was for some one off command and submit the entire command in a web form so it adds `\n` when write to pty stdin and buffer output using bufio
  • Loading branch information
at15 authored Jan 6, 2019
2 parents 7af323b + ca6a3d3 commit d52ac67
Show file tree
Hide file tree
Showing 55 changed files with 10,269 additions and 32 deletions.
82 changes: 70 additions & 12 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ ignored = [
# NOTE: we lock gommon version because dep will use lastest release but gommon is adding new features when go.ice need it ...
[[constraint]]
name = "github.com/dyweb/gommon"
branch = "master"
branch = "errors/types"

[[constraint]]
name = "github.com/go-sql-driver/mysql"
Expand Down
3 changes: 3 additions & 0 deletions cli/pkg.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
// Package cli provides wrapper around spf13/cobra so test is easier
package cli

type Command interface {
}
104 changes: 94 additions & 10 deletions cmd/dk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,32 @@ package main

import (
"context"
"log"
"io"
"os"
"strconv"

"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stdcopy"
dlog "github.com/dyweb/gommon/log"
"github.com/olekukonko/tablewriter"

"github.com/dyweb/go.ice/lib/dockerclient"
)

// TODO: start using cobra for handling sub commands
// TODO: support output like kubectl
var log, logReg = dlog.NewApplicationLoggerAndRegistry("dk")

func main() {
//version()
images()
//images()
//containers()
//containerLog(os.Args[1])
containerExec(os.Args[1])
}

func ping() {
c, err := dockerclient.New("/var/run/docker.sock")
if err != nil {
log.Fatal(err)
}
c := cli()
p, err := c.Ping()
if err != nil {
log.Fatal(err)
Expand All @@ -30,10 +37,7 @@ func ping() {
}

func version() {
c, err := dockerclient.New("/var/run/docker.sock")
if err != nil {
log.Fatal(err)
}
c := cli()
p, err := c.Version()
if err != nil {
log.Fatal(err)
Expand All @@ -53,6 +57,86 @@ func images() {
log.Printf("%d images", len(images))
}

func containers() {
c := cli()
containers, err := c.ContainerList(context.Background(), types.ContainerListOptions{
All: true,
})
if err != nil {
log.Fatal(err)
return
}
log.Infof("total %d containers", len(containers))
// TODO: print as table
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"#", "id", "status", "image"})
for i, c := range containers {
table.Append([]string{
strconv.Itoa(i),
c.ID,
c.Status,
c.Image,
})
}
table.Render()
}

// https://docs.docker.com/engine/reference/commandline/logs/#options
func containerLog(container string) {
c := cli()
res, err := c.ContainerLog(context.Background(), container, types.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Timestamps: true,
Follow: true,
Tail: "100",
Details: true,
})
if err != nil {
log.Fatal(err)
}
// https://github.com/docker/cli/blob/master/cli/command/container/logs.go
// NOTE: using StdCopy will remove the 8 bytes multiplex header ...
// TODO: the time in container is in different timezone by default, also docker timestamp seems to be using UTC?
// actually it's not supported https://github.com/moby/moby/issues/33778
stdcopy.StdCopy(os.Stdout, os.Stderr, res)
//io.Copy(os.Stdout, res)
}

func containerExec(container string) {
cfg := types.ExecConfig{
Tty: true,
Cmd: []string{"/bin/sh"},
Detach: false,
AttachStdout: true,
AttachStderr: true,
AttachStdin: true,
}
c := cli()
res, err := c.ContainerExecCreate(context.Background(), container, cfg)
if err != nil {
log.Fatal(err)
return
}
log.Infof("exec id is %s", res.ID)
conn, err := c.ContainerExecAttach(context.Background(), res.ID, types.ExecStartCheck{
Detach: false,
Tty: true,
})
if err != nil {
log.Fatal(err)
return
}
go func() {
if _, err := io.Copy(os.Stdout, conn); err != nil {
log.Warnf("err copy conn to stdout: %s", err)
}
}()
if _, err := io.Copy(conn, os.Stdin); err != nil {
log.Fatalf("err copy stdin to conn: %s", err)
}
}

func cli() *dockerclient.Client {
c, err := dockerclient.New("/var/run/docker.sock")
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions doc/design/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Cli
Loading

0 comments on commit d52ac67

Please sign in to comment.