Skip to content

Commit

Permalink
Merge pull request #10 from alitari/newshell
Browse files Browse the repository at this point in the history
using kubectl for exec, removed websocket
  • Loading branch information
alitari authored May 19, 2018
2 parents 2ac5f03 + 89ede69 commit 33fcedb
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 252 deletions.
52 changes: 7 additions & 45 deletions backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package kubexp

import (
"bufio"
"bytes"
"crypto/tls"
"errors"
"fmt"
Expand Down Expand Up @@ -110,14 +109,12 @@ func (s *timeSorterType) Less(i, j int) bool {
}

type backendType struct {
cfg *configType
context contextType
resItems map[string][]interface{}
watches map[string]*io.ReadCloser
sorter sorterType
restExecutor func(httpMethod, url, body string, timout time.Duration) (*http.Response, error)
webSocketExecutor func(url string) (string, error)
webSocketConnect func(url string, closeCallback func()) (chan []byte, chan []byte, error)
cfg *configType
context contextType
resItems map[string][]interface{}
watches map[string]*io.ReadCloser
sorter sorterType
restExecutor func(httpMethod, url, body string, timout time.Duration) (*http.Response, error)
}

func newBackend(cfg *configType, context contextType) *backendType {
Expand Down Expand Up @@ -154,12 +151,6 @@ func newBackend(cfg *configType, context contextType) *backendType {
return response, err
},

webSocketExecutor: func(url string) (string, error) {
return websocketExecutor(url, context.user.token)
},
webSocketConnect: func(url string, closeCallback func()) (chan []byte, chan []byte, error) {
return websocketConnect(url, context.user.token, closeCallback)
},
sorter: &nameSorterType{ascending: true},
}
}
Expand Down Expand Up @@ -262,38 +253,9 @@ func (b *backendType) scale(ns string, resource resourceType, deploymentName str
return r, nil
}

func (b *backendType) execPodCommand(namespace, podName, containerName, command string) (interface{}, error) {
var queryCommands bytes.Buffer
for _, qc := range strings.Split(command, " ") {
queryCommands.WriteString(fmt.Sprintf("command=%s&", qc))
}
stderr := "true"
stdin := "true"
stdout := "true"
tty := "false"
path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/exec?container=%s&%sstderr=%s&stdin=%s&stdout=%s&tty=%s", namespace, podName, containerName, queryCommands.String(), stderr, stdin, stdout, tty)
url := fmt.Sprintf("%s://%s:%s%s", "wss", b.context.Cluster.URL.Hostname(), b.context.Cluster.URL.Port(), path)
rp, err := b.webSocketExecutor(url)
if err != nil {
return rp, err
}
return rp, nil
}

func (b *backendType) execIntoPod(namespace, podName, cmd, container string, closeCallback func()) (chan []byte, chan []byte, error) {
stderr := "true"
stdin := "true"
stdout := "true"
tty := "true"
// command := "bin/sh"
path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/exec?command=%s&container=%s&stderr=%s&stdin=%s&stdout=%s&tty=%s", namespace, podName, cmd, container, stderr, stdin, stdout, tty)
url := fmt.Sprintf("%s://%s:%s%s", "wss", b.context.Cluster.URL.Hostname(), b.context.Cluster.URL.Port(), path)
return b.webSocketConnect(url, closeCallback)
}

func (b *backendType) handleResponse(httpMethod, url, reqBody string, resp *http.Response, err error) (string, error) {
if err != nil {
mes := fmt.Sprintf("\nError: %v", err)
mes := fmt.Sprintf("\nError calling '%s %s %s', error: %s", httpMethod, url, reqBody, err)
errorlog.Print(mes)
return mes, err
}
Expand Down
44 changes: 24 additions & 20 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kubexp

import (
"fmt"
"os/exec"

"github.com/jroimartin/gocui"
)
Expand Down Expand Up @@ -41,24 +42,28 @@ func newExecCommand(name, cmd string, containerNr int) commandType {
}
ns := selectedResourceItemNamespace()
rname := selectedResourceItemName()

pod := resourceItemsList.widget.items[resourceItemsList.widget.selectedItem]
containers := val(pod, []interface{}{"spec", "containers"}, "")
containerNames := toStringArray(containers, "name")
if containerNr < len(containerNames) {
in, out, err := backend.execIntoPod(ns, rname, cmd, containerNames[containerNr], func() {
g.Cursor = false
setState(browseState)
})
if err != nil {
showError("Can't exec into pod", err)
return nil
}
setState(execPodState)
execWidget.title = fmt.Sprintf("exec container '%s' in pod '%s'", containerNames[containerNr], rname)
execWidget.open(g, in, out)
}
return nil
cmd := exec.Command("kubectl", "-n", ns, "exec", "-it", rname, cmd)

exe <- cmd
return gocui.ErrQuit

// pod := resourceItemsList.widget.items[resourceItemsList.widget.selectedItem]
// containers := val(pod, []interface{}{"spec", "containers"}, "")
// containerNames := toStringArray(containers, "name")
// if containerNr < len(containerNames) {
// setState(execPodState)
// execWidget.title = fmt.Sprintf("exec container '%s' in pod '%s'", containerNames[containerNr], rname)
// cmd := exec.Command("kubectl", "-n", ns, "exec", "-it", rname, "bash")
// err := execWidget.open(g, cmd, func() {
// g.Cursor = false
// setState(browseState)
// execWidget.close()
// })
// if err != nil {
// showError("Can't exec into pod", err)
// return nil
// }
// }
}}
return execCommand
}
Expand Down Expand Up @@ -107,6 +112,7 @@ var portForwardCommand = newPortForwardCommand("toggle port forward", false)

var quitCommand = commandType{Name: "Quit", f: func(g *gocui.Gui, v *gocui.View) error {
removeAllPortforwardProxies()
leaveApp = true
return gocui.ErrQuit
}}

Expand Down Expand Up @@ -354,8 +360,6 @@ var quitWidgetCommand = commandType{Name: "quit", f: func(g *gocui.Gui, v *gocui
return nil
}}

var keyBindings = []keyBindingType{}

func bindKey(g *gocui.Gui, keyBind keyEventType, command commandType) {
if err := g.SetKeybinding(keyBind.Viewname, keyBind.Key, keyBind.mod, command.f); err != nil {
errorlog.Panicln(err)
Expand Down
18 changes: 0 additions & 18 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,24 +373,6 @@ No Data
Name: "logs",
Template: `{{- podLog .metadata.name ( ind .spec.containers 0).name -}}`,
},
{
Name: "exec",
Template: `
Environment:
--------------
{{ podExec .metadata.name ( ind .spec.containers 0).name "env" }}
Disk usage mounted volumes:
--------------
{{- $p := .}}
{{- range $key, $value := ( ind .spec.containers 0).volumeMounts}}
{{ $value.name }}:
{{ $command := ( $value.mountPath | printf "df -h %s" ) -}}
{{- podExec $p.metadata.name ( ind $p.spec.containers 0).name $command }}
{{else}}
No Data
{{end}}
`,
},
}},
{Name: "jobs", APIPrefix: "apis/batch/v1", ShortName: "jobs", Category: "workloads", Namespace: true, Watch: true,
Views: []viewType{
Expand Down
9 changes: 0 additions & 9 deletions templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ var templateFuncMap = template.FuncMap{
"ctx": contextName,
"decode64": decode64,
"podLog": podLog,
"podExec": podExec,
"events": eventsFor,
"podRes": podRes,
"nodeRes": nodeRes,
Expand Down Expand Up @@ -127,14 +126,6 @@ func podLog(podName, containerName string) interface{} {
return logs
}

func podExec(podName, containerName, command string) interface{} {
resp, err := backend.execPodCommand(selectedResourceItemNamespace(), podName, containerName, command)
if err != nil {
return fmt.Sprintf("error=%v", err)
}
return resp
}

func podsForNode(nodeName string) interface{} {
podType := cfg.resourcesOfName("pods")
pods := backend.resourceItems("", podType)
Expand Down
94 changes: 73 additions & 21 deletions ui.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package kubexp

import (
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"time"

"github.com/jroimartin/gocui"
)

/* local variables naming conventions:
Expand All @@ -22,15 +32,6 @@ context:
selected: sel
*/
import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/jroimartin/gocui"
)

type resourceCategoryType struct {
name string
Expand Down Expand Up @@ -239,11 +240,17 @@ var g *gocui.Gui
var logLevel *string
var logFilePath *string

var wg sync.WaitGroup
var leaveApp = false
var exe = make(chan *exec.Cmd)

var keyBindings = []keyBindingType{}

// Run entrypoint of the program
func Run() {
parseFlags()
currentPortforwardPort = portforwardStartPort
var err error

if len(*logFilePath) != 0 {
logFile, err := os.OpenFile(*logFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
defer logFile.Close()
Expand All @@ -263,24 +270,62 @@ func Run() {
backend = newBackend(cfg, cfg.contexts[0])
updateKubectlContext()

go commandRunner()
currentState = initState

for {
wg.Add(1)
initGui()

if leaveApp {
g.Close()
break
}
wg.Wait()
}

}

func commandRunner() {
for {
select {
case cmd := <-exe:
unbindKeys()
g.Close()

cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Run()
wg.Done()
}
}
}

func initGui() {
var err error
g, err = gocui.NewGui(gocui.OutputNormal)
if err != nil {
errorlog.Panicln(err)
}
defer g.Close()
if currentState.name != browseState.name {
createWidgets()
}
g.SetManager(clusterList.widget, clusterResourcesWidget, namespaceList.widget, resourceMenu.widget, resourcesItemDetailsMenu.widget, searchmodeWidget, resourceItemsList.widget, resourceItemDetailsWidget, helpWidget, errorWidget, execWidget, confirmWidget, loadingWidget)

createWidgets()
bindKeys()
currentState = initState
setState(browseState)
if cfg.isNew {
setState(helpState)
if currentState.name != browseState.name {
setState(browseState)
if cfg.isNew {
setState(helpState)
}
} else {
newResourceCategory()
}

if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
errorlog.Panicln(err)
errorlog.Printf("error in mail loop: %v", err)
}

}

func parseFlags() {
Expand Down Expand Up @@ -397,8 +442,6 @@ func createWidgets() {

loadingWidget = newTextWidget("loading", "", false, false, 30, 10, maxX-60, 4)

g.SetManager(clusterList.widget, clusterResourcesWidget, namespaceList.widget, resourceMenu.widget, resourcesItemDetailsMenu.widget, searchmodeWidget, resourceItemsList.widget, resourceItemDetailsWidget, helpWidget, errorWidget, execWidget, confirmWidget, loadingWidget)

}

func resourceItemDetailsViews() []interface{} {
Expand Down Expand Up @@ -426,7 +469,7 @@ func filterResources(res []resourceType) []interface{} {
}

func showError(mess string, err error) {

mess = strings.Join([]string{mess, fmt.Sprintf(".See log file '%s'", *logFilePath)}, "")
g.Update(func(gui *gocui.Gui) error {
co := []interface{}{mess, err}
errorWidget.setContent(co, tpl("error", errorTemplate))
Expand Down Expand Up @@ -689,6 +732,15 @@ func removePortforwardProxy(key string) error {
return nil
}

func unbindKeys() {
for _, kb := range keyBindings {
if err := g.DeleteKeybinding(kb.KeyEvent.Viewname, kb.KeyEvent.Key, kb.KeyEvent.mod); err != nil {
errorlog.Panicln(err)
}
}
keyBindings = []keyBindingType{}
}

func bindKeys() {
bindKey(g, keyEventType{Viewname: resourceItemsList.widget.name, Key: 'h', mod: gocui.ModNone}, showHelpCommand)
bindKey(g, keyEventType{Viewname: helpWidget.name, Key: gocui.KeyEnter, mod: gocui.ModNone}, quitWidgetCommand)
Expand Down
Loading

0 comments on commit 33fcedb

Please sign in to comment.