Fix CLI unable to get pod logs from controller (#1451)
This commit is contained in:
@@ -18,12 +18,15 @@ package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
restfulspec "github.com/emicklei/go-restful-openapi"
|
||||
@@ -33,10 +36,12 @@ import (
|
||||
"go.uber.org/zap"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
ferror "github.com/fission/fission/pkg/error"
|
||||
"github.com/fission/fission/pkg/types"
|
||||
)
|
||||
|
||||
func RegisterFunctionRoute(ws *restful.WebService) {
|
||||
@@ -280,27 +285,35 @@ func (a *API) FunctionLogsApiPost(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) FunctionPodLogs(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
fnName := vars["function"]
|
||||
ns := vars["namespace"]
|
||||
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
podNs := "fission-function"
|
||||
|
||||
if len(ns) == 0 {
|
||||
ns = "fission-function"
|
||||
ns = metav1.NamespaceDefault
|
||||
} else if ns != metav1.NamespaceDefault {
|
||||
// If the function namespace is "default", executor
|
||||
// will create function pods under "fission-function".
|
||||
// Otherwise, the function pod will be created under
|
||||
// the same namespace of function.
|
||||
podNs = ns
|
||||
}
|
||||
|
||||
f, err := a.fissionClient.Functions(ns).Get(fnName)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
envName := f.Spec.Environment.Name
|
||||
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get function Pods first
|
||||
selector := "functionName=" + fnName
|
||||
podList, err := a.kubernetesClient.CoreV1().Pods(ns).List(metav1.ListOptions{LabelSelector: selector})
|
||||
selector := map[string]string{
|
||||
types.FUNCTION_UID: string(f.Metadata.UID),
|
||||
types.ENVIRONMENT_NAME: f.Spec.Environment.Name,
|
||||
types.ENVIRONMENT_NAMESPACE: f.Spec.Environment.Namespace,
|
||||
}
|
||||
podList, err := a.kubernetesClient.CoreV1().Pods(podNs).List(metav1.ListOptions{
|
||||
LabelSelector: labels.Set(selector).AsSelector().String(),
|
||||
})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -309,30 +322,47 @@ func (a *API) FunctionPodLogs(w http.ResponseWriter, r *http.Request) {
|
||||
// Get the logs for last Pod executed
|
||||
pods := podList.Items
|
||||
sort.Slice(pods, func(i, j int) bool {
|
||||
itime := pods[i].ObjectMeta.CreationTimestamp.Time
|
||||
jtime := pods[j].ObjectMeta.CreationTimestamp.Time
|
||||
return itime.After(jtime)
|
||||
rv1, _ := strconv.ParseInt(pods[i].ObjectMeta.ResourceVersion, 10, 32)
|
||||
rv2, _ := strconv.ParseInt(pods[j].ObjectMeta.ResourceVersion, 10, 32)
|
||||
return rv1 > rv2
|
||||
})
|
||||
|
||||
podLogOpts := apiv1.PodLogOptions{Container: envName} // Only the env container, not fetcher
|
||||
var podLogsReq *restclient.Request
|
||||
if len(pods) > 0 {
|
||||
podLogsReq = a.kubernetesClient.CoreV1().Pods(ns).GetLogs(pods[0].ObjectMeta.Name, &podLogOpts)
|
||||
} else {
|
||||
if len(pods) <= 0 {
|
||||
a.respondWithError(w, errors.New("no active pods found"))
|
||||
return
|
||||
}
|
||||
|
||||
podLogs, err := podLogsReq.Stream()
|
||||
// get the pod with highest resource version
|
||||
err = getContainerLog(a.kubernetesClient, w, f, &pods[0])
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
defer podLogs.Close()
|
||||
|
||||
_, err = io.Copy(w, podLogs)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
a.respondWithError(w, errors.Wrapf(err, "error getting container logs"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getContainerLog(kubernetesClient *kubernetes.Clientset, w http.ResponseWriter, fn *fv1.Function, pod *apiv1.Pod) error {
|
||||
seq := strings.Repeat("=", 35)
|
||||
|
||||
for _, container := range pod.Spec.Containers {
|
||||
podLogOpts := apiv1.PodLogOptions{Container: container.Name} // Only the env container, not fetcher
|
||||
podLogsReq := kubernetesClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.ObjectMeta.Name, &podLogOpts)
|
||||
|
||||
podLogs, err := podLogsReq.Stream()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error streaming pod log")
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("\n%v\nFunction: %v\nEnvironment: %v\nNamespace: %v\nPod: %v\nContainer: %v\nNode: %v\n%v\n", seq,
|
||||
fn.Metadata.Name, fn.Spec.Environment.Name, pod.Namespace, pod.Name, container.Name, pod.Spec.NodeName, seq)
|
||||
w.Write([]byte(msg))
|
||||
|
||||
_, err = io.Copy(w, podLogs)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error copying pod log")
|
||||
}
|
||||
|
||||
podLogs.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user