Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
Issue 326 sanitize logs go (#425)
Browse files Browse the repository at this point in the history
replace bash-call  with kubectl-call with arguments for logs
  • Loading branch information
andrei-panov authored Nov 16, 2020
1 parent f67f887 commit 22930a4
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 28 deletions.
71 changes: 46 additions & 25 deletions pkg/cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,21 +218,19 @@ func logPod(toMatch string, toTarget string, container string) {
}

func showLogsFromKubectl(namespace, toMatch, container string) {
if container != emptyString {
container = " -c " + container
}
pods, err := Client.CoreV1().Pods(namespace).List(metav1.ListOptions{})
checkError(err)
for _, pod := range pods.Items {
if strings.Contains(pod.Name, toMatch) {
err := ExecCmd(nil, buildKubectlCommand(namespace, pod.Name, container), false)
output, err := ExecCmdReturnOutput("kubectl", BuildLogCommandArgs(KUBECONFIG, namespace, pod.Name, container, flags.tail, flags.sinceSeconds)...)
checkError(err)
fmt.Println(output)
}
}
}

func showLogsFromLoki(namespace, toMatch, container string) {
output, err := ExecCmdReturnOutput("bash", "-c", buildLokiCommand(namespace, toMatch, container))
output, err := ExecCmdReturnOutput("kubectl", BuildLokiCommandArgs(KUBECONFIG, namespace, toMatch, container, flags.tail, flags.sinceSeconds)...)
checkError(err)

byteOutput := []byte(output)
Expand All @@ -243,41 +241,64 @@ func showLogsFromLoki(namespace, toMatch, container string) {
fmt.Println(response)
}

func buildKubectlCommand(namespace, podName, container string) string {
var command strings.Builder
command.WriteString(fmt.Sprintf("kubectl logs --kubeconfig=%s %s%s -n %s ", KUBECONFIG, podName, container, namespace))
if flags.tail != -1 {
command.WriteString(fmt.Sprintf("--tail=%d ", flags.tail))
//BuildLogCommandArgs build kubectl command to get logs
func BuildLogCommandArgs(kubeconfig string, namespace, podName, container string, tail int64, sinceSeconds time.Duration) []string {
args := []string{
"logs",
"--kubeconfig=" + kubeconfig,
podName,
}
if flags.sinceSeconds != 0 {
command.WriteString(fmt.Sprintf("--since=%vs ", flags.sinceSeconds.Seconds()))

if container != emptyString {
args = append(args, []string{"-c", container}...)
}

return command.String()
}
args = append(args, []string{"-n", namespace}...)

func buildLokiCommand(namespace, podName, container string) string {
lokiQuery := fmt.Sprintf("{pod_name=~\"%s.*\"}", podName)
if tail != -1 {
args = append(args, fmt.Sprintf("--tail=%d", tail))
}
if sinceSeconds != 0 {
args = append(args, fmt.Sprintf("--since=%vs", sinceSeconds.Seconds()))
}

command := fmt.Sprintf("wget 'http://localhost:3100/loki/api/v1/query_range' -O- --post-data='query=%s", lokiQuery)
return args
}

//BuildLokiCommandArgs build kubect command to get logs from loki
func BuildLokiCommandArgs(kubeconfig string, namespace, podName, container string, tail int64, sinceSeconds time.Duration) []string {
args := []string{
"--kubeconfig=" + kubeconfig,
"exec",
"loki-0",
"-n",
namespace,
"--",
"wget",
"'http://localhost:3100/loki/api/v1/query_range'",
"-O-",
}

lokiQuery := fmt.Sprintf("{pod_name=~\"%s.*\"}", podName)
command := fmt.Sprintf("--post-data='query=%s", lokiQuery)

if container != emptyString {
command += fmt.Sprintf("&&query={container_name=~\"%s.*\"", container)
}
if flags.tail != 0 {
command += fmt.Sprintf("&&limit=%d", flags.tail)
if tail != 0 {
command += fmt.Sprintf("&&limit=%d", tail)
}
if flags.sinceSeconds == 0 {
flags.sinceSeconds = fourteenDaysInSeconds * time.Second
if sinceSeconds == 0 {
sinceSeconds = fourteenDaysInSeconds * time.Second
}
sinceNanoSec := flags.sinceSeconds.Nanoseconds()
sinceNanoSec := sinceSeconds.Nanoseconds()
now := time.Now().UnixNano()

command += fmt.Sprintf("&&start=%d&&end=%d", now-sinceNanoSec, now)
command += "'"

endCommand := fmt.Sprintf("kubectl --kubeconfig=%s exec loki-0 -n %s -- %s", KUBECONFIG, namespace, command)
return endCommand
args = append(args, command)
return args
}

// logPodGarden print logfiles for garden pods
Expand Down Expand Up @@ -328,7 +349,7 @@ func logPodGardenImproved(podName string) {

for _, pod := range pods.Items {
if strings.Contains(pod.Name, podName) {
output, err := ExecCmdReturnOutput("bash", "-c", buildKubectlCommand("garden", pod.Name, emptyString))
output, err := ExecCmdReturnOutput("kubectl", BuildLogCommandArgs(KUBECONFIG, "garden", pod.Name, emptyString, flags.tail, flags.sinceSeconds)...)
if err != nil {
fmt.Println("Cmd was unsuccessful")
os.Exit(2)
Expand Down
43 changes: 40 additions & 3 deletions pkg/cmd/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ package cmd_test

import (
"github.com/gardener/gardenctl/pkg/cmd"
"github.com/spf13/cobra"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/spf13/cobra"
"regexp"
"strings"
)

var _ = Describe("Logs command", func() {
var _ = Describe("Logs and kubecmd command", func() {

var (
command *cobra.Command
Expand All @@ -42,4 +43,40 @@ var _ = Describe("Logs command", func() {
Expect(err.Error()).To(Equal("Command must be in the format: logs (gardener-apiserver|gardener-controller-manager|gardener-dashboard|api|scheduler|controller-manager|etcd-operator|etcd-main[etcd backup-restore]|etcd-events[etcd backup-restore]|addon-manager|vpn-seed|vpn-shoot|machine-controller-manager|kubernetes-dashboard|prometheus|grafana|gardenlet|tf (infra|dns|ingress)|cluster-autoscaler flags(--loki|--tail|--since|--since-time|--timestamps)"))
})
})

Context("kubectl commands", func() {

It("should build kubectl command", func() {

expected := "logs --kubeconfig=/path/to/configfile myPod -c myContainer -n myns --tail=200 --since=3e-07s"
command := cmd.BuildLogCommandArgs("/path/to/configfile", "myns", "myPod", "myContainer", 200, 300)
join := strings.Join(command, " ")
Expect(expected).To(Equal(join))
})

It("should build kubectl command", func() {

//test `normalizeTimestamp` first - replace timestamp with some predefined values
expected := `--kubeconfig=/path/to/configfile exec loki-0 -n myns -- wget 'http://localhost:3100/loki/api/v1/query_range' -O- --post-data='query={pod_name=~"nginx-pod.*"}&&query={container_name=~"mycontainer.*"&&limit=200&&start=1603184413805314000&&end=1604394013805314000'`
expectedNorm := `--kubeconfig=/path/to/configfile exec loki-0 -n myns -- wget 'http://localhost:3100/loki/api/v1/query_range' -O- --post-data='query={pod_name=~"nginx-pod.*"}&&query={container_name=~"mycontainer.*"&&limit=200&&start=101010&&end=202020'`
norm := normalizeTimestamp(expected)
Expect(expectedNorm).To(Equal(norm))

//test real command builder
args := cmd.BuildLokiCommandArgs("/path/to/configfile", "myns", "nginx-pod", "mycontainer", 200, 0)
command := strings.Join(args, " ")
normCommand := normalizeTimestamp(command)
Expect(expectedNorm).To(Equal(normCommand))
})
})
})

func normalizeTimestamp(command string) string {
var re = regexp.MustCompile(`(?m).*start=(\d+)&&end=(\d+)`)

timestamps := re.FindAllStringSubmatch(command, -1)[0]
command = strings.Replace(command, timestamps[1], "101010", 1)
command = strings.Replace(command, timestamps[2], "202020", 1)

return command
}

0 comments on commit 22930a4

Please sign in to comment.