mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #115046 from pacoxu/default-container-e2e
add e2e test for kubectl default container annotation
This commit is contained in:
commit
62d7937b2e
23
test/conformance/testdata/conformance.yaml
vendored
23
test/conformance/testdata/conformance.yaml
vendored
@ -1192,18 +1192,6 @@
|
|||||||
label as the label is removed.
|
label as the label is removed.
|
||||||
release: v1.9
|
release: v1.9
|
||||||
file: test/e2e/kubectl/kubectl.go
|
file: test/e2e/kubectl/kubectl.go
|
||||||
- testname: Kubectl, logs
|
|
||||||
codename: '[sig-cli] Kubectl client Kubectl logs should be able to retrieve and
|
|
||||||
filter logs [Conformance]'
|
|
||||||
description: When a Pod is running then it MUST generate logs. Starting a Pod should
|
|
||||||
have a expected log line. Also log command options MUST work as expected and described
|
|
||||||
below. 'kubectl logs -tail=1' should generate a output of one line, the last line
|
|
||||||
in the log. 'kubectl --limit-bytes=1' should generate a single byte output. 'kubectl
|
|
||||||
--tail=1 --timestamp should generate one line with timestamp in RFC3339 format
|
|
||||||
'kubectl --since=1s' should output logs that are only 1 second older from now
|
|
||||||
'kubectl --since=24h' should output logs that are only 1 day older from now
|
|
||||||
release: v1.9
|
|
||||||
file: test/e2e/kubectl/kubectl.go
|
|
||||||
- testname: Kubectl, patch to annotate
|
- testname: Kubectl, patch to annotate
|
||||||
codename: '[sig-cli] Kubectl client Kubectl patch should add annotations for pods
|
codename: '[sig-cli] Kubectl client Kubectl patch should add annotations for pods
|
||||||
in rc [Conformance]'
|
in rc [Conformance]'
|
||||||
@ -1278,6 +1266,17 @@
|
|||||||
the replicaset to 2. Number of running instances of the Pod MUST be 2.
|
the replicaset to 2. Number of running instances of the Pod MUST be 2.
|
||||||
release: v1.9
|
release: v1.9
|
||||||
file: test/e2e/kubectl/kubectl.go
|
file: test/e2e/kubectl/kubectl.go
|
||||||
|
- testname: Kubectl, logs
|
||||||
|
codename: '[sig-cli] Kubectl logs logs should be able to retrieve and filter logs [Conformance]'
|
||||||
|
description: When a Pod is running then it MUST generate logs. Starting a Pod should
|
||||||
|
have a expected log line. Also log command options MUST work as expected and described
|
||||||
|
below. 'kubectl logs -tail=1' should generate a output of one line, the last line
|
||||||
|
in the log. 'kubectl --limit-bytes=1' should generate a single byte output. 'kubectl
|
||||||
|
--tail=1 --timestamp should generate one line with timestamp in RFC3339 format
|
||||||
|
'kubectl --since=1s' should output logs that are only 1 second older from now
|
||||||
|
'kubectl --since=24h' should output logs that are only 1 day older from now
|
||||||
|
release: v1.9
|
||||||
|
file: test/e2e/kubectl/logs.go
|
||||||
- testname: New Event resource lifecycle, testing a list of events
|
- testname: New Event resource lifecycle, testing a list of events
|
||||||
codename: '[sig-instrumentation] Events API should delete a collection of events
|
codename: '[sig-instrumentation] Events API should delete a collection of events
|
||||||
[Conformance]'
|
[Conformance]'
|
||||||
|
@ -1568,83 +1568,6 @@ metadata:
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.Describe("Kubectl logs", func() {
|
|
||||||
podName := "logs-generator"
|
|
||||||
containerName := "logs-generator"
|
|
||||||
ginkgo.BeforeEach(func() {
|
|
||||||
ginkgo.By("creating an pod")
|
|
||||||
// Agnhost image generates logs for a total of 100 lines over 20s.
|
|
||||||
e2ekubectl.RunKubectlOrDie(ns, "run", podName, "--image="+agnhostImage, "--restart=Never", podRunningTimeoutArg, "--", "logs-generator", "--log-lines-total", "100", "--run-duration", "20s")
|
|
||||||
})
|
|
||||||
ginkgo.AfterEach(func() {
|
|
||||||
e2ekubectl.RunKubectlOrDie(ns, "delete", "pod", podName)
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
Release: v1.9
|
|
||||||
Testname: Kubectl, logs
|
|
||||||
Description: When a Pod is running then it MUST generate logs.
|
|
||||||
Starting a Pod should have a expected log line. Also log command options MUST work as expected and described below.
|
|
||||||
'kubectl logs -tail=1' should generate a output of one line, the last line in the log.
|
|
||||||
'kubectl --limit-bytes=1' should generate a single byte output.
|
|
||||||
'kubectl --tail=1 --timestamp should generate one line with timestamp in RFC3339 format
|
|
||||||
'kubectl --since=1s' should output logs that are only 1 second older from now
|
|
||||||
'kubectl --since=24h' should output logs that are only 1 day older from now
|
|
||||||
*/
|
|
||||||
framework.ConformanceIt("should be able to retrieve and filter logs ", func(ctx context.Context) {
|
|
||||||
// Split("something\n", "\n") returns ["something", ""], so
|
|
||||||
// strip trailing newline first
|
|
||||||
lines := func(out string) []string {
|
|
||||||
return strings.Split(strings.TrimRight(out, "\n"), "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("Waiting for log generator to start.")
|
|
||||||
if !e2epod.CheckPodsRunningReadyOrSucceeded(ctx, c, ns, []string{podName}, framework.PodStartTimeout) {
|
|
||||||
framework.Failf("Pod %s was not ready", podName)
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("checking for a matching strings")
|
|
||||||
_, err := e2eoutput.LookForStringInLog(ns, podName, containerName, "/api/v1/namespaces/kube-system", framework.PodStartTimeout)
|
|
||||||
framework.ExpectNoError(err)
|
|
||||||
|
|
||||||
ginkgo.By("limiting log lines")
|
|
||||||
out := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--tail=1")
|
|
||||||
framework.Logf("got output %q", out)
|
|
||||||
gomega.Expect(len(out)).NotTo(gomega.BeZero())
|
|
||||||
framework.ExpectEqual(len(lines(out)), 1)
|
|
||||||
|
|
||||||
ginkgo.By("limiting log bytes")
|
|
||||||
out = e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--limit-bytes=1")
|
|
||||||
framework.Logf("got output %q", out)
|
|
||||||
framework.ExpectEqual(len(lines(out)), 1)
|
|
||||||
framework.ExpectEqual(len(out), 1)
|
|
||||||
|
|
||||||
ginkgo.By("exposing timestamps")
|
|
||||||
out = e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--tail=1", "--timestamps")
|
|
||||||
framework.Logf("got output %q", out)
|
|
||||||
l := lines(out)
|
|
||||||
framework.ExpectEqual(len(l), 1)
|
|
||||||
words := strings.Split(l[0], " ")
|
|
||||||
gomega.Expect(len(words)).To(gomega.BeNumerically(">", 1))
|
|
||||||
if _, err := time.Parse(time.RFC3339Nano, words[0]); err != nil {
|
|
||||||
if _, err := time.Parse(time.RFC3339, words[0]); err != nil {
|
|
||||||
framework.Failf("expected %q to be RFC3339 or RFC3339Nano", words[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("restricting to a time range")
|
|
||||||
// Note: we must wait at least two seconds,
|
|
||||||
// because the granularity is only 1 second and
|
|
||||||
// it could end up rounding the wrong way.
|
|
||||||
time.Sleep(2500 * time.Millisecond) // ensure that startup logs on the node are seen as older than 1s
|
|
||||||
recentOut := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--since=1s")
|
|
||||||
recent := len(strings.Split(recentOut, "\n"))
|
|
||||||
olderOut := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--since=24h")
|
|
||||||
older := len(strings.Split(olderOut, "\n"))
|
|
||||||
gomega.Expect(recent).To(gomega.BeNumerically("<", older), "expected recent(%v) to be less than older(%v)\nrecent lines:\n%v\nolder lines:\n%v\n", recent, older, recentOut, olderOut)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ginkgo.Describe("Kubectl patch", func() {
|
ginkgo.Describe("Kubectl patch", func() {
|
||||||
/*
|
/*
|
||||||
Release: v1.9
|
Release: v1.9
|
||||||
|
211
test/e2e/kubectl/logs.go
Normal file
211
test/e2e/kubectl/logs.go
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// OWNER = sig/cli
|
||||||
|
|
||||||
|
package kubectl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/kubectl/pkg/cmd/util/podcmd"
|
||||||
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
|
||||||
|
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
||||||
|
e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
|
||||||
|
admissionapi "k8s.io/pod-security-admission/api"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testingPod(name, value, defaultContainerName string) v1.Pod {
|
||||||
|
return v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"name": "foo",
|
||||||
|
"time": value,
|
||||||
|
},
|
||||||
|
Annotations: map[string]string{
|
||||||
|
podcmd.DefaultContainerAnnotationName: defaultContainerName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "container-1",
|
||||||
|
Image: agnhostImage,
|
||||||
|
Args: []string{"logs-generator", "--log-lines-total", "10", "--run-duration", "5s"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: defaultContainerName,
|
||||||
|
Image: agnhostImage,
|
||||||
|
Args: []string{"logs-generator", "--log-lines-total", "20", "--run-duration", "5s"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RestartPolicy: v1.RestartPolicyNever,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO promote to conformance test
|
||||||
|
var _ = SIGDescribe("Kubectl logs", func() {
|
||||||
|
f := framework.NewDefaultFramework("kubectl-logs")
|
||||||
|
f.NamespacePodSecurityEnforceLevel = admissionapi.LevelBaseline
|
||||||
|
defer ginkgo.GinkgoRecover()
|
||||||
|
|
||||||
|
var c clientset.Interface
|
||||||
|
var ns string
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
c = f.ClientSet
|
||||||
|
ns = f.Namespace.Name
|
||||||
|
})
|
||||||
|
|
||||||
|
// Split("something\n", "\n") returns ["something", ""], so
|
||||||
|
// strip trailing newline first
|
||||||
|
lines := func(out string) []string {
|
||||||
|
return strings.Split(strings.TrimRight(out, "\n"), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
ginkgo.Describe("logs", func() {
|
||||||
|
|
||||||
|
podName := "logs-generator"
|
||||||
|
containerName := "logs-generator"
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
ginkgo.By("creating an pod")
|
||||||
|
// Agnhost image generates logs for a total of 100 lines over 20s.
|
||||||
|
e2ekubectl.RunKubectlOrDie(ns, "run", podName, "--image="+agnhostImage, "--restart=Never", podRunningTimeoutArg, "--", "logs-generator", "--log-lines-total", "100", "--run-duration", "20s")
|
||||||
|
})
|
||||||
|
ginkgo.AfterEach(func() {
|
||||||
|
e2ekubectl.RunKubectlOrDie(ns, "delete", "pod", podName)
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
Release: v1.9
|
||||||
|
Testname: Kubectl, logs
|
||||||
|
Description: When a Pod is running then it MUST generate logs.
|
||||||
|
Starting a Pod should have a expected log line. Also log command options MUST work as expected and described below.
|
||||||
|
'kubectl logs -tail=1' should generate a output of one line, the last line in the log.
|
||||||
|
'kubectl --limit-bytes=1' should generate a single byte output.
|
||||||
|
'kubectl --tail=1 --timestamp should generate one line with timestamp in RFC3339 format
|
||||||
|
'kubectl --since=1s' should output logs that are only 1 second older from now
|
||||||
|
'kubectl --since=24h' should output logs that are only 1 day older from now
|
||||||
|
*/
|
||||||
|
framework.ConformanceIt("should be able to retrieve and filter logs ", func(ctx context.Context) {
|
||||||
|
|
||||||
|
ginkgo.By("Waiting for log generator to start.")
|
||||||
|
if !e2epod.CheckPodsRunningReadyOrSucceeded(ctx, c, ns, []string{podName}, framework.PodStartTimeout) {
|
||||||
|
framework.Failf("Pod %s was not ready", podName)
|
||||||
|
}
|
||||||
|
|
||||||
|
ginkgo.By("checking for a matching strings")
|
||||||
|
_, err := e2eoutput.LookForStringInLog(ns, podName, containerName, "/api/v1/namespaces/kube-system", framework.PodStartTimeout)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
ginkgo.By("limiting log lines")
|
||||||
|
out := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--tail=1")
|
||||||
|
framework.Logf("got output %q", out)
|
||||||
|
gomega.Expect(len(out)).NotTo(gomega.BeZero())
|
||||||
|
framework.ExpectEqual(len(lines(out)), 1)
|
||||||
|
|
||||||
|
ginkgo.By("limiting log bytes")
|
||||||
|
out = e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--limit-bytes=1")
|
||||||
|
framework.Logf("got output %q", out)
|
||||||
|
framework.ExpectEqual(len(lines(out)), 1)
|
||||||
|
framework.ExpectEqual(len(out), 1)
|
||||||
|
|
||||||
|
ginkgo.By("exposing timestamps")
|
||||||
|
out = e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--tail=1", "--timestamps")
|
||||||
|
framework.Logf("got output %q", out)
|
||||||
|
l := lines(out)
|
||||||
|
framework.ExpectEqual(len(l), 1)
|
||||||
|
words := strings.Split(l[0], " ")
|
||||||
|
gomega.Expect(len(words)).To(gomega.BeNumerically(">", 1))
|
||||||
|
if _, err := time.Parse(time.RFC3339Nano, words[0]); err != nil {
|
||||||
|
if _, err := time.Parse(time.RFC3339, words[0]); err != nil {
|
||||||
|
framework.Failf("expected %q to be RFC3339 or RFC3339Nano", words[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ginkgo.By("restricting to a time range")
|
||||||
|
// Note: we must wait at least two seconds,
|
||||||
|
// because the granularity is only 1 second and
|
||||||
|
// it could end up rounding the wrong way.
|
||||||
|
time.Sleep(2500 * time.Millisecond) // ensure that startup logs on the node are seen as older than 1s
|
||||||
|
recentOut := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--since=1s")
|
||||||
|
recent := len(strings.Split(recentOut, "\n"))
|
||||||
|
olderOut := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, containerName, "--since=24h")
|
||||||
|
older := len(strings.Split(olderOut, "\n"))
|
||||||
|
gomega.Expect(recent).To(gomega.BeNumerically("<", older), "expected recent(%v) to be less than older(%v)\nrecent lines:\n%v\nolder lines:\n%v\n", recent, older, recentOut, olderOut)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.Describe("default container logs", func() {
|
||||||
|
ginkgo.Describe("the second container is the default-container by annotation", func() {
|
||||||
|
var pod *v1.Pod
|
||||||
|
podName := "pod" + string(uuid.NewUUID())
|
||||||
|
defaultContainerName := "container-2"
|
||||||
|
ginkgo.BeforeEach(func(ctx context.Context) {
|
||||||
|
podClient := f.ClientSet.CoreV1().Pods(ns)
|
||||||
|
ginkgo.By("constructing the pod")
|
||||||
|
value := strconv.Itoa(time.Now().Nanosecond())
|
||||||
|
podCopy := testingPod(podName, value, defaultContainerName)
|
||||||
|
pod = &podCopy
|
||||||
|
ginkgo.By("creating the pod")
|
||||||
|
_, err := podClient.Create(ctx, pod, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
framework.Failf("Failed to create pod: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ginkgo.AfterEach(func() {
|
||||||
|
e2ekubectl.RunKubectlOrDie(ns, "delete", "pod", podName)
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("should log default container if not specified", func(ctx context.Context) {
|
||||||
|
ginkgo.By("Waiting for log generator to start.")
|
||||||
|
if !e2epod.CheckPodsRunningReadyOrSucceeded(ctx, c, ns, []string{podName}, framework.PodStartTimeout) {
|
||||||
|
framework.Failf("Pod %s was not ready", podName)
|
||||||
|
}
|
||||||
|
|
||||||
|
ginkgo.By("specified container log lines")
|
||||||
|
out := e2ekubectl.RunKubectlOrDie(ns, "logs", podName, "-c", "container-1")
|
||||||
|
framework.Logf("got output %q", out)
|
||||||
|
gomega.Expect(len(out)).NotTo(gomega.BeZero())
|
||||||
|
framework.ExpectEqual(len(lines(out)), 10)
|
||||||
|
|
||||||
|
ginkgo.By("log all containers log lines")
|
||||||
|
out = e2ekubectl.RunKubectlOrDie(ns, "logs", podName, "--all-containers")
|
||||||
|
framework.Logf("got output %q", out)
|
||||||
|
gomega.Expect(len(out)).NotTo(gomega.BeZero())
|
||||||
|
framework.ExpectEqual(len(lines(out)), 30)
|
||||||
|
|
||||||
|
ginkgo.By("default container logs")
|
||||||
|
out = e2ekubectl.RunKubectlOrDie(ns, "logs", podName)
|
||||||
|
framework.Logf("got output %q", out)
|
||||||
|
framework.ExpectEqual(len(lines(out)), 20)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user