|
@@ -2,9 +2,12 @@ package costmodel
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
"context"
|
|
"context"
|
|
|
|
|
+ "encoding/base64"
|
|
|
"flag"
|
|
"flag"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
|
|
+ "io/ioutil"
|
|
|
"net/http"
|
|
"net/http"
|
|
|
|
|
+ "os"
|
|
|
"reflect"
|
|
"reflect"
|
|
|
"strconv"
|
|
"strconv"
|
|
|
"strings"
|
|
"strings"
|
|
@@ -15,9 +18,13 @@ import (
|
|
|
"github.com/kubecost/cost-model/pkg/util/httputil"
|
|
"github.com/kubecost/cost-model/pkg/util/httputil"
|
|
|
"github.com/kubecost/cost-model/pkg/util/timeutil"
|
|
"github.com/kubecost/cost-model/pkg/util/timeutil"
|
|
|
"github.com/kubecost/cost-model/pkg/util/watcher"
|
|
"github.com/kubecost/cost-model/pkg/util/watcher"
|
|
|
|
|
+ "github.com/microcosm-cc/bluemonday"
|
|
|
|
|
|
|
|
|
|
+ v1 "k8s.io/api/core/v1"
|
|
|
"k8s.io/klog"
|
|
"k8s.io/klog"
|
|
|
|
|
|
|
|
|
|
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
|
+
|
|
|
"github.com/julienschmidt/httprouter"
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
|
|
|
|
sentry "github.com/getsentry/sentry-go"
|
|
sentry "github.com/getsentry/sentry-go"
|
|
@@ -43,6 +50,8 @@ import (
|
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+var sanitizePolicy = bluemonday.UGCPolicy()
|
|
|
|
|
+
|
|
|
const (
|
|
const (
|
|
|
RFC3339Milli = "2006-01-02T15:04:05.000Z"
|
|
RFC3339Milli = "2006-01-02T15:04:05.000Z"
|
|
|
maxCacheMinutes1d = 11
|
|
maxCacheMinutes1d = 11
|
|
@@ -51,6 +60,8 @@ const (
|
|
|
maxCacheMinutes30d = 137
|
|
maxCacheMinutes30d = 137
|
|
|
CustomPricingSetting = "CustomPricing"
|
|
CustomPricingSetting = "CustomPricing"
|
|
|
DiscountSetting = "Discount"
|
|
DiscountSetting = "Discount"
|
|
|
|
|
+ epRules = apiPrefix + "/rules"
|
|
|
|
|
+ LogSeparator = "+-------------------------------------------------------------------------------------"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
var (
|
|
@@ -910,6 +921,412 @@ func (a *Accesses) GetPrometheusMetrics(w http.ResponseWriter, _ *http.Request,
|
|
|
w.Write(WrapData(result, nil))
|
|
w.Write(WrapData(result, nil))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (a *Accesses) GetAllPersistentVolumes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ pvList, err := a.KubeClientSet.CoreV1().PersistentVolumes().List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting persistent volume %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body, err := json.Marshal(pvList)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding persistent volumes: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllDeployments(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+ namespace := r.URL.Query().Get("namespace")
|
|
|
|
|
+ deploymentsList, err := a.KubeClientSet.AppsV1().Deployments(namespace).List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting deployments %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ body, err := json.Marshal(deploymentsList)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding deployment: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllStorageClasses(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ scList, err := a.KubeClientSet.StorageV1().StorageClasses().List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting storageclasses: "+err.Error())
|
|
|
|
|
+ }
|
|
|
|
|
+ body, err := json.Marshal(scList)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding storageclasses: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllStatefulSets(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+ namespace := r.URL.Query().Get("namespace")
|
|
|
|
|
+ deploymentsList, err := a.KubeClientSet.AppsV1().StatefulSets(namespace).List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting deployments %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ body, err := json.Marshal(deploymentsList)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding deployment: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllNodes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ nodeList, err := a.KubeClientSet.CoreV1().Nodes().List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting node %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body, err := json.Marshal(nodeList)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding nodes: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllPods(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ podlist, err := a.KubeClientSet.CoreV1().Pods("").List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting pod %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body, err := json.Marshal(podlist)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding pods: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllNamespaces(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ namespaces, err := a.KubeClientSet.CoreV1().Namespaces().List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting namespaces %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ body, err := json.Marshal(namespaces)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding deployment: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetAllDaemonSets(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+ daemonSets, err := a.KubeClientSet.AppsV1().DaemonSets("").List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting daemon sets %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ body, err := json.Marshal(daemonSets)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding daemon set: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetPod(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ podName := ps.ByName("name")
|
|
|
|
|
+ podNamespace := ps.ByName("namespace")
|
|
|
|
|
+
|
|
|
|
|
+ // Examples for error handling:
|
|
|
|
|
+ // - Use helper functions like e.g. errors.IsNotFound()
|
|
|
|
|
+ // - And/or cast to StatusError and use its properties like e.g. ErrStatus.Message
|
|
|
|
|
+ pod, err := a.KubeClientSet.CoreV1().Pods(podNamespace).Get(r.Context(), podName, metav1.GetOptions{})
|
|
|
|
|
+ if k8serrors.IsNotFound(err) {
|
|
|
|
|
+ fmt.Fprintf(w, "Pod not found\n")
|
|
|
|
|
+ } else if statusError, isStatus := err.(*k8serrors.StatusError); isStatus {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting pod %v\n", statusError.ErrStatus.Message)
|
|
|
|
|
+ } else if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting pod: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ body, err := json.Marshal(pod)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding pod: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) PrometheusRecordingRules(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ u := a.PrometheusClient.URL(epRules, nil)
|
|
|
|
|
+
|
|
|
|
|
+ req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error creating Prometheus rule request: "+err.Error())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _, body, _, err := a.PrometheusClient.Do(r.Context(), req)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error making Prometheus rule request: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) PrometheusConfig(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ pConfig := make(map[string]string)
|
|
|
|
|
+
|
|
|
|
|
+ pConfig["address"] = os.Getenv("PROMETHEUS_SERVER_ENDPOINT")
|
|
|
|
|
+
|
|
|
|
|
+ body, err := json.Marshal(pConfig)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error marshalling prometheus config")
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) PrometheusTargets(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ u := a.PrometheusClient.URL(epTargets, nil)
|
|
|
|
|
+
|
|
|
|
|
+ req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error creating Prometheus rule request: "+err.Error())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _, body, _, err := a.PrometheusClient.Do(r.Context(), req)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error making Prometheus rule request: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetOrphanedPods(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ podlist, err := a.KubeClientSet.CoreV1().Pods("").List(r.Context(), metav1.ListOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error getting pod %v\n", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var lonePods []v1.Pod
|
|
|
|
|
+ for _, pod := range podlist.Items {
|
|
|
|
|
+ if len(pod.OwnerReferences) == 0 {
|
|
|
|
|
+ lonePods = append(lonePods, pod)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body, err := json.Marshal(lonePods)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error decoding pod: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ w.Write(body)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetInstallNamespace(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ ns := os.Getenv("KUBECOST_NAMESPACE")
|
|
|
|
|
+ w.Write([]byte(ns))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func logsFor(c kubernetes.Interface, namespace string, pod string, container string, dur time.Duration, ctx context.Context) (string, error) {
|
|
|
|
|
+ since := time.Now().UTC().Add(-dur)
|
|
|
|
|
+
|
|
|
|
|
+ logOpts := v1.PodLogOptions{
|
|
|
|
|
+ SinceTime: &metav1.Time{Time: since},
|
|
|
|
|
+ }
|
|
|
|
|
+ if container != "" {
|
|
|
|
|
+ logOpts.Container = container
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ req := c.CoreV1().Pods(namespace).GetLogs(pod, &logOpts)
|
|
|
|
|
+ reader, err := req.Stream(ctx)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return "", err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ podLogs, err := ioutil.ReadAll(reader)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return "", err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return string(podLogs), nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetPodLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ q := r.URL.Query()
|
|
|
|
|
+ ns := q.Get("namespace")
|
|
|
|
|
+ if ns == "" {
|
|
|
|
|
+ ns = os.Getenv("KUBECOST_NAMESPACE")
|
|
|
|
|
+ }
|
|
|
|
|
+ pod := q.Get("pod")
|
|
|
|
|
+ selector := q.Get("selector")
|
|
|
|
|
+ container := q.Get("container")
|
|
|
|
|
+ since := q.Get("since")
|
|
|
|
|
+ if since == "" {
|
|
|
|
|
+ since = "24h"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sinceDuration, err := time.ParseDuration(since)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Invalid Duration String: "+err.Error())
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var logResult string
|
|
|
|
|
+ appendLog := func(ns string, pod string, container string, l string) {
|
|
|
|
|
+ if l == "" {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ logResult += fmt.Sprintf("%s\n| %s:%s:%s\n%s\n%s\n\n", LogSeparator, ns, pod, container, LogSeparator, l)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if pod != "" {
|
|
|
|
|
+ pd, err := a.KubeClientSet.CoreV1().Pods(ns).Get(r.Context(), pod, metav1.GetOptions{})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error Finding Pod: "+err.Error())
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if container != "" {
|
|
|
|
|
+ var foundContainer bool
|
|
|
|
|
+ for _, cont := range pd.Spec.Containers {
|
|
|
|
|
+ if strings.EqualFold(cont.Name, container) {
|
|
|
|
|
+ foundContainer = true
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if !foundContainer {
|
|
|
|
|
+ fmt.Fprintf(w, "Could not find container: "+container)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ logs, err := logsFor(a.KubeClientSet, ns, pod, container, sinceDuration, r.Context())
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error Getting Logs: "+err.Error())
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ appendLog(ns, pod, container, logs)
|
|
|
|
|
+
|
|
|
|
|
+ w.Write([]byte(logResult))
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if selector != "" {
|
|
|
|
|
+ pods, err := a.KubeClientSet.CoreV1().Pods(ns).List(r.Context(), metav1.ListOptions{LabelSelector: selector})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error Finding Pod: "+err.Error())
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, pd := range pods.Items {
|
|
|
|
|
+ for _, cont := range pd.Spec.Containers {
|
|
|
|
|
+ logs, err := logsFor(a.KubeClientSet, ns, pd.Name, cont.Name, sinceDuration, r.Context())
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ appendLog(ns, pd.Name, cont.Name, logs)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ w.Write([]byte(logResult))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) AddServiceKey(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ r.ParseForm()
|
|
|
|
|
+
|
|
|
|
|
+ //p.CloudProvider.AddServiceKey(r.PostForm)
|
|
|
|
|
+
|
|
|
|
|
+ key := r.PostForm.Get("key")
|
|
|
|
|
+ k := []byte(key)
|
|
|
|
|
+ err := ioutil.WriteFile("/var/configs/key.json", k, 0644)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Error writing service key: "+err.Error())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) GetHelmValues(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ encodedValues := os.Getenv("HELM_VALUES")
|
|
|
|
|
+ if encodedValues == "" {
|
|
|
|
|
+ fmt.Fprintf(w, "Values reporting disabled")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ result, err := base64.StdEncoding.DecodeString(encodedValues)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fmt.Fprintf(w, "Failed to decode encoded values: %s", err)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ w.Write(result)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (a *Accesses) Status(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+
|
|
|
|
|
+ api := prometheusAPI.NewAPI(a.PrometheusClient)
|
|
|
|
|
+ result, err := api.Config(r.Context())
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Fprintf(w, "Using Prometheus at "+os.Getenv("PROMETHEUS_SERVER_ENDPOINT")+". Error: "+err.Error())
|
|
|
|
|
+ } else {
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Fprintf(w, "Using Prometheus at "+os.Getenv("PROMETHEUS_SERVER_ENDPOINT")+". PrometheusConfig: "+result.YAML)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// captures the panic event in sentry
|
|
// captures the panic event in sentry
|
|
|
func capturePanicEvent(err string, stack string) {
|
|
func capturePanicEvent(err string, stack string) {
|
|
|
msg := fmt.Sprintf("Panic: %s\nStackTrace: %s\n", err, stack)
|
|
msg := fmt.Sprintf("Panic: %s\nStackTrace: %s\n", err, stack)
|
|
@@ -1184,6 +1601,26 @@ func Initialize(additionalConfigWatchers ...*watcher.ConfigMapWatcher) *Accesses
|
|
|
a.Router.GET("/pricingSourceStatus", a.GetPricingSourceStatus)
|
|
a.Router.GET("/pricingSourceStatus", a.GetPricingSourceStatus)
|
|
|
a.Router.GET("/pricingSourceCounts", a.GetPricingSourceCounts)
|
|
a.Router.GET("/pricingSourceCounts", a.GetPricingSourceCounts)
|
|
|
|
|
|
|
|
|
|
+ // endpoints migrated from server
|
|
|
|
|
+ a.Router.GET("/allPersistentVolumes", a.GetAllPersistentVolumes)
|
|
|
|
|
+ a.Router.GET("/allDeployments", a.GetAllDeployments)
|
|
|
|
|
+ a.Router.GET("/allStorageClasses", a.GetAllStorageClasses)
|
|
|
|
|
+ a.Router.GET("/allStatefulSets", a.GetAllStatefulSets)
|
|
|
|
|
+ a.Router.GET("/allNodes", a.GetAllNodes)
|
|
|
|
|
+ a.Router.GET("/allPods", a.GetAllPods)
|
|
|
|
|
+ a.Router.GET("/allNamespaces", a.GetAllNamespaces)
|
|
|
|
|
+ a.Router.GET("/allDaemonSets", a.GetAllDaemonSets)
|
|
|
|
|
+ a.Router.GET("/pod/:namespace/:name", a.GetPod)
|
|
|
|
|
+ a.Router.GET("/prometheusRecordingRules", a.PrometheusRecordingRules)
|
|
|
|
|
+ a.Router.GET("/prometheusConfig", a.PrometheusConfig)
|
|
|
|
|
+ a.Router.GET("/prometheusTargets", a.PrometheusTargets)
|
|
|
|
|
+ a.Router.GET("/orphanedPods", a.GetOrphanedPods)
|
|
|
|
|
+ a.Router.GET("/installNamespace", a.GetInstallNamespace)
|
|
|
|
|
+ a.Router.GET("/podLogs", a.GetPodLogs)
|
|
|
|
|
+ a.Router.POST("/serviceKey", a.AddServiceKey)
|
|
|
|
|
+ a.Router.GET("/helmValues", a.GetHelmValues)
|
|
|
|
|
+ a.Router.GET("/status", a.Status)
|
|
|
|
|
+
|
|
|
// prom query proxies
|
|
// prom query proxies
|
|
|
a.Router.GET("/prometheusQuery", a.PrometheusQuery)
|
|
a.Router.GET("/prometheusQuery", a.PrometheusQuery)
|
|
|
a.Router.GET("/prometheusQueryRange", a.PrometheusQueryRange)
|
|
a.Router.GET("/prometheusQueryRange", a.PrometheusQueryRange)
|