2022-06-02 12:56:07 +03:00
|
|
|
package e2e
|
|
|
|
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the Apache License 2.0.
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-06-14 04:15:29 +03:00
|
|
|
"errors"
|
2022-10-11 15:50:37 +03:00
|
|
|
"fmt"
|
2022-06-02 12:56:07 +03:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2022-10-11 15:50:37 +03:00
|
|
|
"strings"
|
2022-06-02 12:56:07 +03:00
|
|
|
"time"
|
|
|
|
|
2022-06-15 03:10:42 +03:00
|
|
|
. "github.com/onsi/ginkgo/v2"
|
2022-06-02 12:56:07 +03:00
|
|
|
. "github.com/onsi/gomega"
|
|
|
|
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ = Describe("[Admin API] Kubernetes get pod logs action", func() {
|
|
|
|
BeforeEach(skipIfNotInDevelopmentEnv)
|
|
|
|
|
|
|
|
const containerName = "e2e-test-container-name"
|
|
|
|
const podName = "e2e-test-pod-name"
|
|
|
|
|
|
|
|
When("in a standard openshift namespace", func() {
|
|
|
|
const namespace = "openshift-azure-operator"
|
|
|
|
|
2022-10-31 19:19:20 +03:00
|
|
|
It("must be able to get logs from a container of a pod", func(ctx context.Context) {
|
2022-06-02 12:56:07 +03:00
|
|
|
testGetPodLogsOK(ctx, containerName, podName, namespace)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
When("in a customer namespace", func() {
|
|
|
|
const namespace = "e2e-test-namespace"
|
|
|
|
|
2022-10-31 19:19:20 +03:00
|
|
|
It("must be not be able to get logs from customer workload namespaces", func(ctx context.Context) {
|
2022-06-02 12:56:07 +03:00
|
|
|
testGetPodLogsFromCustomerNamespaceForbidden(ctx, containerName, podName, namespace)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// We will create a pod with known logs of its container and will compare the logs gotten through the kubernetes client and through the Admin API.
|
|
|
|
func testGetPodLogsOK(ctx context.Context, containerName, podName, namespace string) {
|
2022-10-11 15:50:37 +03:00
|
|
|
expectedLog := "mock-pod-logs"
|
|
|
|
|
|
|
|
By("creating a test pod in openshift-azure-operator namespace with some known logs")
|
|
|
|
pod := mockPod(containerName, podName, namespace, expectedLog)
|
2022-06-02 12:56:07 +03:00
|
|
|
pod, err := clients.Kubernetes.CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
2022-10-11 15:50:37 +03:00
|
|
|
|
2022-06-02 12:56:07 +03:00
|
|
|
defer func() {
|
2022-10-11 15:50:37 +03:00
|
|
|
By("deleting the test pod")
|
2022-06-02 12:56:07 +03:00
|
|
|
err = clients.Kubernetes.CoreV1().Pods(namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{})
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
}()
|
2022-10-11 15:50:37 +03:00
|
|
|
|
|
|
|
By("waiting for the pod to successfully terminate")
|
2022-06-14 04:15:29 +03:00
|
|
|
err = wait.PollInfinite(time.Second*5, func() (done bool, err error) {
|
2022-06-02 12:56:07 +03:00
|
|
|
pod, err = clients.Kubernetes.CoreV1().Pods(namespace).Get(ctx, pod.Name, metav1.GetOptions{})
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
2022-06-14 04:15:29 +03:00
|
|
|
|
|
|
|
switch pod.Status.Phase {
|
|
|
|
case corev1.PodSucceeded:
|
2022-06-02 12:56:07 +03:00
|
|
|
return true, nil
|
2022-06-14 04:15:29 +03:00
|
|
|
case corev1.PodPending:
|
|
|
|
if pod.CreationTimestamp.Time.Add(5*time.Minute).Unix() < time.Now().Unix() {
|
|
|
|
return false, errors.New("pod was pending for more than 5min")
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
case corev1.PodFailed:
|
|
|
|
return true, errors.New(pod.Status.Message)
|
2022-06-02 12:56:07 +03:00
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
})
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
2022-10-11 15:50:37 +03:00
|
|
|
By("requesting logs via RP admin API")
|
2022-06-02 12:56:07 +03:00
|
|
|
params := url.Values{
|
|
|
|
"container": []string{containerName},
|
|
|
|
"namespace": []string{namespace},
|
|
|
|
"podname": []string{podName},
|
|
|
|
}
|
|
|
|
var logs string
|
|
|
|
resp, err := adminRequest(ctx, http.MethodGet, "/admin"+resourceIDFromEnv()+"/kubernetespodlogs", params, nil, &logs)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
|
|
|
|
2022-10-11 15:50:37 +03:00
|
|
|
By("verifying that logs received from RP match known logs")
|
|
|
|
Expect(strings.TrimRight(logs, "\n")).To(Equal(expectedLog))
|
2022-06-02 12:56:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func testGetPodLogsFromCustomerNamespaceForbidden(ctx context.Context, containerName, podName, namespace string) {
|
2022-10-11 15:50:37 +03:00
|
|
|
By("requesting logs via RP admin API")
|
2022-06-02 12:56:07 +03:00
|
|
|
params := url.Values{
|
|
|
|
"container": []string{containerName},
|
|
|
|
"namespace": []string{namespace},
|
|
|
|
"podname": []string{podName},
|
|
|
|
}
|
2022-10-11 15:50:37 +03:00
|
|
|
|
|
|
|
var logs string
|
|
|
|
resp, err := adminRequest(ctx, http.MethodGet, "/admin"+resourceIDFromEnv()+"/kubernetespodlogs", params, nil, logs)
|
2022-06-02 12:56:07 +03:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(resp.StatusCode).To(Equal(http.StatusForbidden))
|
2022-10-11 15:50:37 +03:00
|
|
|
|
|
|
|
By("verifying that we not receive any logs from RP")
|
|
|
|
Expect(strings.TrimRight(logs, "\n")).To(BeEmpty())
|
2022-06-02 12:56:07 +03:00
|
|
|
}
|
|
|
|
|
2022-10-11 15:50:37 +03:00
|
|
|
func mockPod(containerName, podName, namespace, fakeLog string) *corev1.Pod {
|
2022-06-02 12:56:07 +03:00
|
|
|
return &corev1.Pod{
|
|
|
|
TypeMeta: metav1.TypeMeta{
|
|
|
|
Kind: "Pod",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: podName,
|
|
|
|
Namespace: namespace,
|
|
|
|
},
|
|
|
|
Spec: corev1.PodSpec{
|
|
|
|
Containers: []corev1.Container{{
|
|
|
|
Name: containerName,
|
|
|
|
Image: "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:103505c93bf45c4a29301f282f1ff046e35b63bceaf4df1cca2e631039289da2",
|
2022-10-11 15:50:37 +03:00
|
|
|
Command: []string{"/bin/bash", "-c", fmt.Sprintf("echo %q", fakeLog)},
|
2022-06-02 12:56:07 +03:00
|
|
|
}},
|
|
|
|
RestartPolicy: "Never",
|
|
|
|
HostNetwork: true,
|
|
|
|
HostPID: true,
|
|
|
|
},
|
|
|
|
Status: corev1.PodStatus{},
|
|
|
|
}
|
|
|
|
}
|