Skip to content

Commit

Permalink
Add an /api endpoint to the dashboard (#586)
Browse files Browse the repository at this point in the history
* Fix #585 add /api endpoint back

* Couple fixes

* add namespace selection to API
  • Loading branch information
sudermanjr authored Feb 28, 2023
1 parent c45f3f7 commit 440aa30
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 39 deletions.
114 changes: 76 additions & 38 deletions pkg/dashboard/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package dashboard

import (
"encoding/json"
"math"
"net/http"
"strconv"
Expand Down Expand Up @@ -47,48 +48,13 @@ func Dashboard(opts Options) http.Handler {
namespace = val
}

filterLabels := make(map[string]string)
if !opts.showAllVPAs {
filterLabels = opts.vpaLabels
}

// TODO [hkatz] add caching or refresh button support
summarizer := summary.NewSummarizer(
summary.ForNamespace(namespace),
summary.ForVPAsWithLabels(filterLabels),
summary.ExcludeContainers(opts.excludedContainers),
)

vpaData, err := summarizer.GetSummary()
vpaData, err := getVPAData(opts, namespace, costPerCPU, costPerGB)
if err != nil {
klog.Errorf("Error getting vpaData: %v", err)
http.Error(w, "Error running summary.", http.StatusInternalServerError)
klog.Errorf("Error getting vpa data %v", err)
http.Error(w, "Error getting vpa data", http.StatusInternalServerError)
return
}

if costPerCPU != "" && costPerGB != "" {
costPerCPUFloat, _ := strconv.ParseFloat(costPerCPU, 64)
costPerGBFloat, _ := strconv.ParseFloat(costPerGB, 64)

var containerCost, guaranteedCost, burstableCost float64

for _, n := range vpaData.Namespaces {
for _, w := range n.Workloads {
for k, c := range w.Containers {
containerCost = calculateContainerCost(costPerCPUFloat, costPerGBFloat, c)
guaranteedCost, burstableCost = calculateRecommendedCosts(costPerCPUFloat, costPerGBFloat, containerCost, c)
c.ContainerCost = containerCost
c.ContainerCostInt = getCostInt(containerCost)
c.GuaranteedCostInt = getCostInt(guaranteedCost)
c.BurstableCostInt = getCostInt(burstableCost)
c.GuaranteedCost = math.Abs(guaranteedCost)
c.BurstableCost = math.Abs(burstableCost)
w.Containers[k] = c
}
}
}
}

tmpl, err := getTemplate("dashboard",
"container",
"dashboard",
Expand Down Expand Up @@ -116,6 +82,78 @@ func Dashboard(opts Options) http.Handler {
})
}

// API replies with the JSON data of the VPA summary
func API(opts Options) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)

costPerCPU := r.URL.Query().Get("costPerCPU")
costPerGB := r.URL.Query().Get("costPerGB")

var namespace string
if val, ok := vars["namespace"]; ok {
namespace = val
}

vpaData, err := getVPAData(opts, namespace, costPerCPU, costPerGB)
if err != nil {
klog.Errorf("Error getting vpa data %v", err)
http.Error(w, "Error getting vpa data", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(vpaData); err != nil {
klog.Errorf("Error writing vpa data %v", err)
http.Error(w, "Error writing vpa data", http.StatusInternalServerError)
return
}
})
}

func getVPAData(opts Options, namespace, costPerCPU, costPerGB string) (summary.Summary, error) {

filterLabels := make(map[string]string)
if !opts.showAllVPAs {
filterLabels = opts.vpaLabels
}

summarizer := summary.NewSummarizer(
summary.ForNamespace(namespace),
summary.ForVPAsWithLabels(filterLabels),
summary.ExcludeContainers(opts.excludedContainers),
)

vpaData, err := summarizer.GetSummary()
if err != nil {
return summary.Summary{}, err
}

if costPerCPU != "" && costPerGB != "" {
costPerCPUFloat, _ := strconv.ParseFloat(costPerCPU, 64)
costPerGBFloat, _ := strconv.ParseFloat(costPerGB, 64)

var containerCost, guaranteedCost, burstableCost float64

for _, n := range vpaData.Namespaces {
for _, w := range n.Workloads {
for k, c := range w.Containers {
containerCost = calculateContainerCost(costPerCPUFloat, costPerGBFloat, c)
guaranteedCost, burstableCost = calculateRecommendedCosts(costPerCPUFloat, costPerGBFloat, containerCost, c)
c.ContainerCost = containerCost
c.ContainerCostInt = getCostInt(containerCost)
c.GuaranteedCostInt = getCostInt(guaranteedCost)
c.BurstableCostInt = getCostInt(burstableCost)
c.GuaranteedCost = math.Abs(guaranteedCost)
c.BurstableCost = math.Abs(burstableCost)
w.Containers[k] = c
}
}
}
}
return vpaData, nil
}

func calculateContainerCost(costPerCPUFloat float64, costPerGBFloat float64, c summary.ContainerSummary) float64 {
var cpuRequests, memRequests, cpuLimits, memLimits float64

Expand Down
5 changes: 4 additions & 1 deletion pkg/dashboard/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
package dashboard

import (
"k8s.io/klog/v2"
"net/http"
"path"

"k8s.io/klog/v2"

packr "github.com/gobuffalo/packr/v2"
"github.com/gorilla/mux"
)
Expand Down Expand Up @@ -81,5 +82,7 @@ func GetRouter(setters ...Option) *mux.Router {
http.Redirect(w, r, path.Join(opts.basePath, "/namespaces"), http.StatusMovedPermanently)
})

// api
router.Handle("/api/{namespace:[a-zA-Z0-9-]+}", API(*opts))
return router
}

0 comments on commit 440aa30

Please sign in to comment.