Skip to content

Commit

Permalink
feat: implements get a pod logs, view-pages history back, fix layout …
Browse files Browse the repository at this point in the history
…(navbar, footer)
  • Loading branch information
itnpeople committed Nov 5, 2021
2 parents 8f8a6d2 + 135a3c8 commit 38a04c9
Show file tree
Hide file tree
Showing 51 changed files with 970 additions and 247 deletions.
55 changes: 16 additions & 39 deletions package-lock.json

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

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@
"xterm": "^4.12.0",
"xterm-addon-fit": "^0.5.0",
"xterm-addon-web-links": "^0.4.0",
"splitpanes": "^2.3.8",
"ansi-to-html": "^0.7.2",
"jsonpath": "^1.1.1"
},
"engines": {
"node": ">=10.13.0",
"npm": ">=6.0.0"
},
"dependencies": {}
}
}
13 changes: 9 additions & 4 deletions src/app/backend/model/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"strings"
"time"

"github.com/kore3lab/dashboard/pkg/config"
"github.com/kore3lab/dashboard/pkg/lang"
Expand Down Expand Up @@ -76,14 +77,17 @@ func GetNodeListWithUsage(cluster string) (interface{}, error) {
return nil, err
}

//timeout 5s
timeout := int64(5)

// node-list
nodeList, err := apiClient.CoreV1().Nodes().List(context.TODO(), metaV1.ListOptions{})
nodeList, err := apiClient.CoreV1().Nodes().List(context.TODO(), metaV1.ListOptions{TimeoutSeconds: &timeout})
if err != nil {
return nil, err
}

// self.Workloads.Pods (노드별 파드 수 & running 파드 수)
podList, err := apiClient.CoreV1().Pods("").List(context.TODO(), metaV1.ListOptions{})
podList, err := apiClient.CoreV1().Pods("").List(context.TODO(), metaV1.ListOptions{TimeoutSeconds: &timeout})
if err != nil {
return nil, err
}
Expand All @@ -96,12 +100,13 @@ func GetNodeListWithUsage(cluster string) (interface{}, error) {

nodes := map[string]*NodeWithMetrics{}
summary := NodeMetricsUsage{}
d := time.Duration(timeout) * time.Second
nodeSummary := ProxyNodeSummary{}

for _, m := range nodeList.Items {

// node summary for storage used percentage (/api/v1/nodes/<node name>/proxy/stats/summary)
nodeSummary := ProxyNodeSummary{}
request := apiClient.CoreV1().RESTClient().Get().Resource("nodes").Name(m.Name).SubResource("proxy").Suffix("stats/summary")
request := apiClient.CoreV1().RESTClient().Get().Resource("nodes").Name(m.Name).SubResource("proxy").Suffix("stats/summary").Timeout(d)
responseRawArrayOfBytes, err := request.DoRaw(context.Background())
if err != nil {
log.Warnf("Unable to get %s/proxy/stats/summary (cause=%v)", m, err)
Expand Down
15 changes: 15 additions & 0 deletions src/app/backend/pkg/app/ack.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
log "github.com/sirupsen/logrus"
"net/http"
"net/url"

"github.com/astaxie/beego/validation"
"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -82,3 +83,17 @@ func (g *Gin) ValidateUrl(params []string) error {
return nil

}

// parse querystrings
func (g *Gin) ParseQuery() (url.Values, error) {

u, err := url.Parse(g.C.Request.RequestURI)
if err != nil {
return nil, err
}
query, err := url.ParseQuery(u.RawQuery)
if err != nil {
return nil, err
}
return query, nil
}
120 changes: 117 additions & 3 deletions src/app/backend/router/apis/raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ package apis
*/

import (
"context"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"

"github.com/gin-gonic/gin"
"github.com/kore3lab/dashboard/pkg/app"
"github.com/kore3lab/dashboard/pkg/config"
log "github.com/sirupsen/logrus"
coreV1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
Expand Down Expand Up @@ -113,8 +118,7 @@ func GetRaw(c *gin.Context) {
var err error

ListOptions := v1.ListOptions{}
u, _ := url.Parse(c.Request.RequestURI)
query, _ := url.ParseQuery(u.RawQuery)
query, _ := g.ParseQuery()

err = v1.Convert_url_Values_To_v1_ListOptions(&query, &ListOptions, nil)
if err != nil {
Expand Down Expand Up @@ -202,3 +206,113 @@ func PatchRaw(c *gin.Context) {
g.Send(http.StatusOK, r)

}

// Get Pod logs
func GetPodLogs(c *gin.Context) {
g := app.Gin{C: c}

var err error

// url parameter validation
v := []string{"NAMESPACE", "NAME"}
if err := g.ValidateUrl(v); err != nil {
g.SendMessage(http.StatusBadRequest, err.Error(), err)
return
}

// instancing dynamic client
client, err := config.Cluster.Client(g.C.Param("CLUSTER"))
if err != nil {
g.SendMessage(http.StatusBadRequest, err.Error(), err)
return
}

apiClient, err := client.NewKubernetesClient()
if err != nil {
g.SendMessage(http.StatusBadRequest, err.Error(), err)
return
}

// log options (with querystring)
options := coreV1.PodLogOptions{}
var limitLines = int64(300)
query, err := g.ParseQuery()
if err == nil {
if len(query) > 0 {
if query["tailLines"] != nil {
var num1, err1 = strconv.Atoi(query["tailLines"][0])
if err1 != nil {
g.SendMessage(http.StatusBadRequest, err.Error(), err)
return
}
limitLines = int64(num1)
}
options.TailLines = &limitLines

if query["sinceTime"] != nil {
var timestamp v1.Time
timestamp.UnmarshalQueryParameter(query["sinceTime"][0])
options.SinceTime = &timestamp
}

if query["container"] != nil {
options.Container = query["container"][0]
}
if query["follow"] != nil {
options.Follow, _ = strconv.ParseBool(query["follow"][0])
}
if query["previous"] != nil {
options.Previous, _ = strconv.ParseBool(query["previous"][0])
}
if query["timestamps"] != nil {
options.Timestamps, _ = strconv.ParseBool(query["timestamps"][0])
}
}
}

// get a log stream
req := apiClient.CoreV1().Pods(g.C.Param("NAMESPACE")).GetLogs(g.C.Param("NAME"), &options)
stream, err := req.Stream(context.TODO())
if err != nil {
g.SendMessage(http.StatusBadRequest, err.Error(), err)
return
}
defer stream.Close()

// read a stream go-routine
chanStream := make(chan []byte, 10)
go func() {
defer close(chanStream)

for {
buf := make([]byte, 4096)
numBytes, err := stream.Read(buf)

if err != nil {
if err != io.EOF {
log.Infof("finished log streaming (cause=%s)", err.Error())
return
} else {
if options.Follow == false {
log.Debug("log stream is EOF")
break
} else {
time.Sleep(time.Second * 1)
}
}
} else {
chanStream <- buf[:numBytes]
}
}
}()

// write stream to client
g.C.Stream(func(w io.Writer) bool {
if data, ok := <-chanStream; ok {
w.Write(data)
return true
}
return false
})

}
1 change: 1 addition & 0 deletions src/app/backend/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func CreateUrlMappings() {
rawAPI.GET("/:A/:B/:RESOURCE/:NAME", apis.GetRaw) // "/namespaces/:NAMESPACE/:RESOURCE/:NAME" > namespaced core apiGroup - get
rawAPI.DELETE("/:A/:B/:RESOURCE/:NAME", apis.DeleteRaw) // "/namespaces/:NAMESPACE/:RESOURCE/:NAME" > namespaced core apiGroup - delete
rawAPI.PATCH("/:A/:B/:RESOURCE/:NAME", apis.PatchRaw) // "/namespaces/:NAMESPACE/:RESOURCE/:NAME" > namespaced core apiGroup - patch
rawAPI.GET("/:A/:B/:RESOURCE/:NAME/log", apis.GetPodLogs) // "/namespaces/:NAMESPACE/pods/:NAME/log" > get a pod logs
}

// RAW-API Grouped
Expand Down

0 comments on commit 38a04c9

Please sign in to comment.