Skip to content

Commit

Permalink
Merge pull request #31 from alitari/newgocui
Browse files Browse the repository at this point in the history
Newgocui
  • Loading branch information
alitari authored Oct 8, 2018
2 parents df9b7d8 + 3a63002 commit 1ac612d
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 173 deletions.
113 changes: 77 additions & 36 deletions backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,9 @@ func (s *nameSorterType) getElements() []interface{} {
}

func (s *nameSorterType) Less(i, j int) bool {
iName := resItemName(s.elements[i])
jName := resItemName(s.elements[j])
var res bool
if len(iName) > 0 && len(jName) > 0 {
res = strings.Compare(iName, jName) < 0
} else {
res = i < j
}
iName := fmt.Sprintf("%s/%s", resItemName(s.elements[i]), resItemNamespace(s.elements[i]))
jName := fmt.Sprintf("%s/%s", resItemName(s.elements[j]), resItemNamespace(s.elements[j]))
res := strings.Compare(iName, jName) < 0
return (s.ascending && res) || (!s.ascending && !res)
}

Expand Down Expand Up @@ -101,30 +96,45 @@ func (s *timeSorterType) Less(i, j int) bool {
itimeStr := resItemCreationTimestamp(s.elements[i])
jtimeStr := resItemCreationTimestamp(s.elements[j])
var res bool
if len(itimeStr) > 0 && len(jtimeStr) > 0 {
if len(itimeStr) > 0 && len(jtimeStr) > 0 && jtimeStr != itimeStr {
itime := totime(itimeStr)
jtime := totime(jtimeStr)
res = jtime.After(itime)
if itime.Equal(jtime) {
res = true
} else {
res = jtime.After(itime)
}
} else {
res = i < j
iName := fmt.Sprintf("%s/%s", resItemName(s.elements[i]), resItemNamespace(s.elements[i]))
jName := fmt.Sprintf("%s/%s", resItemName(s.elements[j]), resItemNamespace(s.elements[j]))
res = strings.Compare(iName, jName) < 0
}
return (s.ascending && res) || (!s.ascending && !res)
}

type changedObjType struct {
id string
changeTime time.Time
}

type watchType struct {
reader *io.ReadCloser
online bool
}

type backendType struct {
context contextType
resItems map[string][]interface{}
podLogs []byte
watches map[string]*watchType
sorter sorterType
restExecutor func(httpMethod, url, body string, timout int) (*http.Response, error)
clusterLivenessCheck <-chan time.Time
clusterLivenessDone chan bool
context contextType
resItems map[string][]interface{}
podLogs []byte
watches map[string]*watchType
sorter sorterType
restExecutor func(httpMethod, url, body string, timout int) (*http.Response, error)
updateLoop <-chan time.Time
lastLivenessCheck time.Time
clusterLivenessDone chan bool
changedObjList []changedObjType
changedObjSet map[string]bool
blink bool
}

func newBackend(context contextType) *backendType {
Expand Down Expand Up @@ -163,9 +173,12 @@ func newBackend(context contextType) *backendType {
return response, err
},

sorter: &nameSorterType{ascending: true},
clusterLivenessCheck: time.NewTicker(time.Duration(5) * time.Second).C,
clusterLivenessDone: make(chan bool),
sorter: &nameSorterType{ascending: true},
updateLoop: time.NewTicker(time.Duration(250) * time.Millisecond).C,
clusterLivenessDone: make(chan bool),
changedObjList: []changedObjType{},
changedObjSet: map[string]bool{},
blink: true,
}
}

Expand Down Expand Up @@ -206,21 +219,30 @@ func (b *backendType) createWatches(resources []resourceType) error {
if err != nil {
return err
}
time.Sleep(50 * time.Millisecond)
}
}
go func() {
for {
select {
case <-b.clusterLivenessCheck:
err := b.availabiltyCheck()
if err != nil {
for _, w := range b.watches {
w.online = false
case <-b.updateLoop:
now := time.Now()
if (now.Sub(b.lastLivenessCheck)).Seconds() > 10 {
b.lastLivenessCheck = now
err := b.availabiltyCheck()
if err != nil {
for _, w := range b.watches {
w.online = false
}
errorlog.Printf("cluster heart beat not ok: %v", err)
}
errorlog.Printf("cluster heart beat no ok: %v", err)
}

b.updateChangedObjList()
b.blink = !b.blink

if currentState.name == "browseState" {
updateResourceItemList(false)
} else {
tracelog.Printf("cluster heart beat ok")
}

case <-b.clusterLivenessDone:
Expand All @@ -233,6 +255,24 @@ func (b *backendType) createWatches(resources []resourceType) error {
return nil
}

func (b *backendType) updateChangedObjList() {
var k = 0
for i, el := range b.changedObjList {
chgTime := el.changeTime
if time.Now().Sub(chgTime).Seconds() < 5 {
k = i
break
}

}
newList := b.changedObjList[k:]
for _, el := range b.changedObjList[:k] {
b.changedObjSet[el.id] = false
}

b.changedObjList = newList
}

func (b *backendType) closeWatches0(filter func(string) bool) {
tracelog.Printf("close watches %s", b.watches)
if b.watches != nil {
Expand Down Expand Up @@ -309,7 +349,7 @@ func (b *backendType) handleResponse(httpMethod, url, reqBody string, resp *http
}

func (b *backendType) availabiltyCheck() error {
url := fmt.Sprintf("%s/%s/%s", b.context.Cluster.URL, "api/v1", "nodes")
url := fmt.Sprintf("%s/%s/%s", b.context.Cluster.URL, "api/v1", "namespaces")
resp, err := b.restExecutor(http.MethodGet, url, "", restCallTimeout)
_, err = b.handleResponse(http.MethodGet, url, "", resp, err)
return err
Expand Down Expand Up @@ -391,9 +431,6 @@ func (b *backendType) watch0(urlPrefix, urlPostfix, queryParam string) error {
showError(mess, err)
}
b.watches[urlPostfix].online = false
if !strings.HasSuffix(urlPostfix, "log") {
updateResourceItemList(false)
}
break
} else {
b.watches[urlPostfix].online = true
Expand Down Expand Up @@ -438,13 +475,17 @@ func (b *backendType) updateResourceItems(resName string, watchBytes []byte) {
if resName == "namespaces" {
updateNamespaces()
}
chngObj := changedObjType{id: fmt.Sprintf("%s/%s/%s", resItemNamespace(watchObj), resName, resItemName(watchObj)), changeTime: time.Now()}

b.changedObjList = append(b.changedObjList, chngObj)
b.changedObjSet[chngObj.id] = true

if len(resourceMenu.widget.items) > 0 && len(namespaceList.widget.items) > 0 {
selRes := selectedResource()
selNs := selectedNamespace()

if currentState.name == "browseState" && selRes.Name == resName && (selNs == "*ALL*" || selNs == resItemNamespace(watchObj)) {
updateResourceItemList(watch["type"] == "DELETED" || watch["type"] == "ADDED")
if currentState.name == "browseState" && selRes.Name == resName && (selNs == "*ALL*" || selNs == resItemNamespace(watchObj)) && (watch["type"] == "DELETED" || watch["type"] == "ADDED") {
updateResourceItemList(true)
}
}
} else {
Expand Down
37 changes: 32 additions & 5 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package kubexp

import (
"fmt"
"os/exec"

"github.com/jroimartin/gocui"
"github.com/alitari/gocui"
)

type commandType struct {
Expand All @@ -19,6 +18,7 @@ type keyEventType struct {
}

type keyBindingType struct {
show bool
KeyEvent keyEventType
Command commandType
}
Expand Down Expand Up @@ -48,7 +48,7 @@ func newExecCommand(name, cmd string, containerNr int) commandType {
containerNr = 0
}

cmd := exec.Command("kubectl", "-n", ns, "exec", "-c", containerNames[containerNr], "-it", rname, cmd)
cmd := kubectl(backend.context.Name, "-n", ns, "exec", "-c", containerNames[containerNr], "-it", rname, cmd)

exe <- cmd
return gocui.ErrQuit
Expand Down Expand Up @@ -430,10 +430,37 @@ var nextContainerFiletransferCommand = commandType{Name: "Next container", f: fu
return nil
}}

func bindKey(g *gocui.Gui, keyBind keyEventType, command commandType) {
func bindKey(g *gocui.Gui, show bool, keyBind keyEventType, command commandType) {
if err := g.SetKeybinding(keyBind.Viewname, keyBind.Key, keyBind.mod, command.f); err != nil {
errorlog.Panicln(err)
}
kb := keyBindingType{keyBind, command}
kb := keyBindingType{show, keyBind, command}
keyBindings = append(keyBindings, kb)
}

func filterKeyBindings(filter func(kb keyBindingType) bool) []keyBindingType {
result := []keyBindingType{}
for _, k := range keyBindings {
if filter(k) {
result = append(result, k)
}
}
return result
}

func keyBindingsForView(viewName string) string {
kbs := filterKeyBindings(func(kb keyBindingType) bool {
return viewName == kb.KeyEvent.Viewname && kb.show
})
res := ""
for _, kb := range kbs {
res = res + "," + kbToText(kb)
}
return res
}

func kbToText(kb keyBindingType) string {
k := kb.KeyEvent
cmd := kb.Command.Name
return fmt.Sprintf("%s %s", keyString(k), cmd)
}
33 changes: 15 additions & 18 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var configFile *string

var useResourceFile = false

var contextColors = []string{"Magenta", "White", "Cyan", "Blue"}
var contextColors = []string{"Magenta", "Cyan", "Blue"}

type configType struct {
isNew bool
Expand Down Expand Up @@ -56,7 +56,7 @@ type viewType struct {
Template string
}

var clusterResourcesTemplate = `{{ "capacity:" | contextColorEmp }} {{ .Capacity.String | contextColor }} {{ "cpu:" | contextColorEmp }} {{ .Requested.CPU.String | contextColor}}({{ .PercentCPU | contextColor }}) {{ "memory:" | contextColorEmp }} {{ .Requested.Memory.String | contextColor}}({{ .PercentMem | contextColor }})`
var clusterResourcesTemplate = `{{ "capacity:" | contextColorEmp }} {{ .Capacity.String }} {{ "cpu:" | contextColorEmp }} {{ .Requested.CPU.String }}({{ .PercentCPU }}) {{ "memory:" | contextColorEmp }} {{ .Requested.Memory.String }}({{ .PercentMem }})`

var helpTemplate = colorizeText(fmt.Sprintf(`
_ __ _ ___ _
Expand Down Expand Up @@ -151,8 +151,8 @@ var defaultResources = []resourceType{
Views: []viewType{
{
Name: "list",
Template: nameAgeColumns + `
{{- header "Status" . (fcwe .status.conditions "status" "True" "type") | printf "%-8.8s " -}}
Template: `{{- header "Status" . (fcwe .status.conditions "status" "True" "type") | printf "%-8.8s " -}}
` + nameAgeColumns + `
{{- header "Age" . (age .metadata.creationTimestamp) | printf "%-8.8s " -}}
{{- header "Version" . .status.nodeInfo.kubeletVersion | printf "%-10.10s " -}}
{{- header "Internal-IP" . ( fcwe .status.addresses "type" "InternalIP" "address") | printf "%-18.18s " -}}
Expand Down Expand Up @@ -210,11 +210,12 @@ var defaultResources = []resourceType{
Views: []viewType{
{
Name: "list",
Template: nameAgeColumns + `
Template: `{{- header "Status" . ( .status.phase | blinkWhenChanged . "persistentvolumes" ) | printf "%-8.8s " -}}
` + nameAgeColumns + `
{{- header "Capacity" . .spec.capacity.storage | printf "%-12.12s " -}}
{{- header "Accessmodes" . ( printArray .spec.accessModes) | printf "%-20.20s " -}}
{{- header "Reclaimpolicy" . .spec.persistentVolumeReclaimPolicy | printf "%-15.15s " -}}
{{- header "Status" . .status.phase | printf "%-8.8s " -}}
{{- header "Claim" . ( printf "%v/%v" .spec.claimRef.namespace .spec.claimRef.name ) | printf "%-30.30s " -}}`,
},
infoView,
Expand Down Expand Up @@ -261,10 +262,6 @@ var defaultResources = []resourceType{
Name: "list",
Template: nameAgeColumns,
},
viewType{
Name: "info",
Template: labelsAndAnnoTemplate,
},
infoView,
yamlView,
jsonView,
Expand Down Expand Up @@ -340,7 +337,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( podStatus .status ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . ( podStatus .status | blinkWhenChanged . "pods" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "PortForward" . ( portForwardPortsShort . )| printf "%-6.6s " -}}
{{- header " R" . ( count ( fk .status.containerStatuses "ready" true )) | printf "%3.3s/" -}}
Expand Down Expand Up @@ -375,7 +372,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .spec.completions .status.succeeded ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .spec.completions .status.succeeded ) | blinkWhenChanged . "jobs" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Desired" . .spec.completions | printf "%8.8s " -}}
{{- header "Succ" . .status.succeeded | printf "%8.8s " -}}
Expand All @@ -392,7 +389,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .spec.jobTemplate.spec.completions .status.succeeded ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .spec.jobTemplate.spec.completions .status.succeeded ) | blinkWhenChanged . "cronjobs" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Schedule" . .spec.schedule | printf "%-20.20s " -}}
{{- header "Last Scheduled" . .status.lastScheduleTime | printf "%-26.26s " -}}
Expand All @@ -407,7 +404,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .spec.replicas .status.readyReplicas ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .spec.replicas .status.readyReplicas ) | blinkWhenChanged . "replicationcontrollers" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Desired" . .spec.replicas | printf "%8.8s " -}}
{{- header "Current" . .status.replicas | printf "%8.8s " -}}
Expand All @@ -423,7 +420,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .spec.replicas .status.readyReplicas ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .spec.replicas .status.readyReplicas ) | blinkWhenChanged . "replicasets" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Desired" . .spec.replicas | printf "%8.8s " -}}
{{- header "Current" . .status.replicas | printf "%8.8s " -}}
Expand All @@ -450,7 +447,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .status.desiredNumberScheduled .status.numberReady ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .status.desiredNumberScheduled .status.numberReady ) | blinkWhenChanged . "daemonsets" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Desired" . .status.desiredNumberScheduled | printf "%8.8s " -}}
{{- header "Current" . .status.currentNumberScheduled | printf "%8.8s " -}}
Expand All @@ -468,7 +465,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .spec.replicas .status.readyReplicas ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .spec.replicas .status.readyReplicas ) | blinkWhenChanged . "deployments" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Desired" . .spec.replicas | printf "%8.8s " -}}
{{- header "Current" . .status.replicas | printf "%8.8s " -}}
Expand All @@ -483,7 +480,7 @@ No Data
Views: []viewType{
{
Name: "list",
Template: `{{- header "Status" . ( status .spec.replicas .status.readyReplicas ) | printf "%-10.10s " | colorPhase -}}
Template: `{{- header "Status" . (( status .spec.replicas .status.readyReplicas ) | blinkWhenChanged . "statefulsets" ) | printf "%-10.10s " | colorPhase -}}
` + nameAgeColumns + `
{{- header "Desired" . .spec.replicas | printf "%8.8s " -}}
{{- header "Current" . .status.replicas | printf "%8.8s " -}}
Expand Down
Binary file modified pics/brwsr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ func Test_podResources(t *testing.T) {

func Test_printMap(t *testing.T) {
m := map[string]interface{}{"alex": "Hello", "bread": "egg"}
checkContains(t, printMap(m), "bread:egg")
checkContains(t, printMap(m), "alex:Hello")
checkContains(t, printMap(m), "bread")
checkContains(t, printMap(m), "alex")
}

// func Test_helpTemplate(t *testing.T) {
Expand Down
Loading

0 comments on commit 1ac612d

Please sign in to comment.