Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit 1895a01

Browse files
authored
Merge pull request #839 from Random-Liu/cherrypick-#761
Backport #761 to release/1.0
2 parents 40007b3 + 8347d40 commit 1895a01

File tree

13 files changed

+569
-108
lines changed

13 files changed

+569
-108
lines changed

docs/config.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ The explanation and default value of each configuration item are as follows:
2727
# enable_tls_streaming enables the TLS streaming support.
2828
enable_tls_streaming = false
2929

30+
# max_container_log_line_size is the maximum log line size in bytes for a container.
31+
# Log line longer than the limit will be split into multiple lines. -1 means no
32+
# limit.
33+
max_container_log_line_size = 16384
34+
3035
# "plugins.cri.containerd" contains config related to containerd
3136
[plugins.cri.containerd]
3237

hack/verify-lint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ set -o pipefail
2020
for d in $(find . -type d -a \( -iwholename './pkg*' -o -iwholename './cmd*' \) -not -iwholename './pkg/api*'); do
2121
echo for directory ${d} ...
2222
gometalinter \
23-
--exclude='error return value not checked.*(Close|Log|Print).*\(errcheck\)$' \
23+
--exclude='error return value not checked.*(Close|Log|Print|Fprint).*\(errcheck\)$' \
2424
--exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$' \
2525
--exclude='duplicate of.*_test.go.*\(dupl\)$' \
2626
--exclude='.*/mock_.*\.go:.*\(golint\)$' \

integration/container_log_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
Copyright 2018 The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package integration
18+
19+
import (
20+
"fmt"
21+
"io/ioutil"
22+
"os"
23+
"path/filepath"
24+
"strings"
25+
"testing"
26+
"time"
27+
28+
"github.com/stretchr/testify/assert"
29+
"github.com/stretchr/testify/require"
30+
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
31+
)
32+
33+
func TestLongContainerLog(t *testing.T) {
34+
testPodLogDir, err := ioutil.TempDir("/tmp", "long-container-log")
35+
require.NoError(t, err)
36+
defer os.RemoveAll(testPodLogDir)
37+
38+
t.Log("Create a sandbox with log directory")
39+
sbConfig := PodSandboxConfig("sandbox", "long-container-log",
40+
WithPodLogDirectory(testPodLogDir),
41+
)
42+
sb, err := runtimeService.RunPodSandbox(sbConfig)
43+
require.NoError(t, err)
44+
defer func() {
45+
assert.NoError(t, runtimeService.StopPodSandbox(sb))
46+
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
47+
}()
48+
49+
const (
50+
testImage = "busybox"
51+
containerName = "test-container"
52+
)
53+
t.Logf("Pull test image %q", testImage)
54+
img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil)
55+
require.NoError(t, err)
56+
defer func() {
57+
assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img}))
58+
}()
59+
60+
t.Log("Create a container with log path")
61+
config, err := CRIConfig()
62+
require.NoError(t, err)
63+
maxSize := config.MaxContainerLogLineSize
64+
shortLineCmd := fmt.Sprintf("i=0; while [ $i -lt %d ]; do printf %s; i=$((i+1)); done", maxSize-1, "a")
65+
maxLenLineCmd := fmt.Sprintf("i=0; while [ $i -lt %d ]; do printf %s; i=$((i+1)); done", maxSize, "b")
66+
longLineCmd := fmt.Sprintf("i=0; while [ $i -lt %d ]; do printf %s; i=$((i+1)); done", maxSize+1, "c")
67+
cnConfig := ContainerConfig(
68+
containerName,
69+
"busybox",
70+
WithCommand("sh", "-c",
71+
fmt.Sprintf("%s; echo; %s; echo; %s", shortLineCmd, maxLenLineCmd, longLineCmd)),
72+
WithLogPath(containerName),
73+
)
74+
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
75+
require.NoError(t, err)
76+
77+
t.Log("Start the container")
78+
require.NoError(t, runtimeService.StartContainer(cn))
79+
80+
t.Log("Wait for container to finish running")
81+
require.NoError(t, Eventually(func() (bool, error) {
82+
s, err := runtimeService.ContainerStatus(cn)
83+
if err != nil {
84+
return false, err
85+
}
86+
if s.GetState() == runtime.ContainerState_CONTAINER_EXITED {
87+
return true, nil
88+
}
89+
return false, nil
90+
}, time.Second, 30*time.Second))
91+
92+
t.Log("Check container log")
93+
content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName))
94+
assert.NoError(t, err)
95+
checkContainerLog(t, string(content), []string{
96+
fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagFull, strings.Repeat("a", maxSize-1)),
97+
fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagFull, strings.Repeat("b", maxSize)),
98+
fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagPartial, strings.Repeat("c", maxSize)),
99+
fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagFull, "c"),
100+
})
101+
}
102+
103+
func checkContainerLog(t *testing.T, log string, messages []string) {
104+
lines := strings.Split(strings.TrimSpace(log), "\n")
105+
require.Len(t, lines, len(messages), "log line number should match")
106+
for i, line := range lines {
107+
parts := strings.SplitN(line, " ", 2)
108+
require.Len(t, parts, 2)
109+
_, err := time.Parse(time.RFC3339Nano, parts[0])
110+
assert.NoError(t, err, "timestamp should be in RFC3339Nano format")
111+
assert.Equal(t, messages[i], parts[1], "log content should match")
112+
}
113+
}

integration/container_update_resources_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func checkMemoryLimit(t *testing.T, spec *runtimespec.Spec, memLimit int64) {
3737
}
3838

3939
func TestUpdateContainerResources(t *testing.T) {
40-
t.Logf("Create a sandbox")
40+
t.Log("Create a sandbox")
4141
sbConfig := PodSandboxConfig("sandbox", "update-container-resources")
4242
sb, err := runtimeService.RunPodSandbox(sbConfig)
4343
require.NoError(t, err)
@@ -46,7 +46,7 @@ func TestUpdateContainerResources(t *testing.T) {
4646
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
4747
}()
4848

49-
t.Logf("Create a container with memory limit")
49+
t.Log("Create a container with memory limit")
5050
cnConfig := ContainerConfig(
5151
"container",
5252
pauseImage,
@@ -57,48 +57,48 @@ func TestUpdateContainerResources(t *testing.T) {
5757
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
5858
require.NoError(t, err)
5959

60-
t.Logf("Check memory limit in container OCI spec")
60+
t.Log("Check memory limit in container OCI spec")
6161
container, err := containerdClient.LoadContainer(context.Background(), cn)
6262
require.NoError(t, err)
6363
spec, err := container.Spec(context.Background())
6464
require.NoError(t, err)
6565
checkMemoryLimit(t, spec, 2*1024*1024)
6666

67-
t.Logf("Update container memory limit after created")
67+
t.Log("Update container memory limit after created")
6868
err = runtimeService.UpdateContainerResources(cn, &runtime.LinuxContainerResources{
6969
MemoryLimitInBytes: 4 * 1024 * 1024,
7070
})
7171
require.NoError(t, err)
7272

73-
t.Logf("Check memory limit in container OCI spec")
73+
t.Log("Check memory limit in container OCI spec")
7474
spec, err = container.Spec(context.Background())
7575
require.NoError(t, err)
7676
checkMemoryLimit(t, spec, 4*1024*1024)
7777

78-
t.Logf("Start the container")
78+
t.Log("Start the container")
7979
require.NoError(t, runtimeService.StartContainer(cn))
8080
task, err := container.Task(context.Background(), nil)
8181
require.NoError(t, err)
8282

83-
t.Logf("Check memory limit in cgroup")
83+
t.Log("Check memory limit in cgroup")
8484
cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid())))
8585
require.NoError(t, err)
8686
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
8787
require.NoError(t, err)
8888
assert.Equal(t, uint64(4*1024*1024), stat.Memory.Usage.Limit)
8989

90-
t.Logf("Update container memory limit after started")
90+
t.Log("Update container memory limit after started")
9191
err = runtimeService.UpdateContainerResources(cn, &runtime.LinuxContainerResources{
9292
MemoryLimitInBytes: 8 * 1024 * 1024,
9393
})
9494
require.NoError(t, err)
9595

96-
t.Logf("Check memory limit in container OCI spec")
96+
t.Log("Check memory limit in container OCI spec")
9797
spec, err = container.Spec(context.Background())
9898
require.NoError(t, err)
9999
checkMemoryLimit(t, spec, 8*1024*1024)
100100

101-
t.Logf("Check memory limit in cgroup")
101+
t.Log("Check memory limit in cgroup")
102102
stat, err = cgroup.Stat(cgroups.IgnoreNotExist)
103103
require.NoError(t, err)
104104
assert.Equal(t, uint64(8*1024*1024), stat.Memory.Usage.Limit)

integration/test_utils.go

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package integration
1818

1919
import (
20+
"context"
21+
"encoding/json"
2022
"flag"
2123
"fmt"
2224
"os/exec"
@@ -27,12 +29,15 @@ import (
2729
"github.com/containerd/containerd"
2830
"github.com/pkg/errors"
2931
"github.com/sirupsen/logrus"
32+
"google.golang.org/grpc"
3033
"k8s.io/kubernetes/pkg/kubelet/apis/cri"
3134
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
3235
"k8s.io/kubernetes/pkg/kubelet/remote"
36+
kubeletutil "k8s.io/kubernetes/pkg/kubelet/util"
3337

3438
api "github.com/containerd/cri/pkg/api/v1"
3539
"github.com/containerd/cri/pkg/client"
40+
criconfig "github.com/containerd/cri/pkg/config"
3641
"github.com/containerd/cri/pkg/constants"
3742
"github.com/containerd/cri/pkg/util"
3843
)
@@ -97,6 +102,7 @@ func ConnectDaemons() error {
97102
// Opts sets specific information in pod sandbox config.
98103
type PodSandboxOpts func(*runtime.PodSandboxConfig)
99104

105+
// Set host network.
100106
func WithHostNetwork(p *runtime.PodSandboxConfig) {
101107
if p.Linux == nil {
102108
p.Linux = &runtime.LinuxPodSandboxConfig{}
@@ -111,6 +117,13 @@ func WithHostNetwork(p *runtime.PodSandboxConfig) {
111117
}
112118
}
113119

120+
// Add pod log directory.
121+
func WithPodLogDirectory(dir string) PodSandboxOpts {
122+
return func(p *runtime.PodSandboxConfig) {
123+
p.LogDirectory = dir
124+
}
125+
}
126+
114127
// PodSandboxConfig generates a pod sandbox config for test.
115128
func PodSandboxConfig(name, ns string, opts ...PodSandboxOpts) *runtime.PodSandboxConfig {
116129
config := &runtime.PodSandboxConfig{
@@ -134,52 +147,59 @@ func PodSandboxConfig(name, ns string, opts ...PodSandboxOpts) *runtime.PodSandb
134147
type ContainerOpts func(*runtime.ContainerConfig)
135148

136149
func WithTestLabels() ContainerOpts {
137-
return func(cf *runtime.ContainerConfig) {
138-
cf.Labels = map[string]string{"key": "value"}
150+
return func(c *runtime.ContainerConfig) {
151+
c.Labels = map[string]string{"key": "value"}
139152
}
140153
}
141154

142155
func WithTestAnnotations() ContainerOpts {
143-
return func(cf *runtime.ContainerConfig) {
144-
cf.Annotations = map[string]string{"a.b.c": "test"}
156+
return func(c *runtime.ContainerConfig) {
157+
c.Annotations = map[string]string{"a.b.c": "test"}
145158
}
146159
}
147160

148161
// Add container resource limits.
149162
func WithResources(r *runtime.LinuxContainerResources) ContainerOpts {
150-
return func(cf *runtime.ContainerConfig) {
151-
if cf.Linux == nil {
152-
cf.Linux = &runtime.LinuxContainerConfig{}
163+
return func(c *runtime.ContainerConfig) {
164+
if c.Linux == nil {
165+
c.Linux = &runtime.LinuxContainerConfig{}
153166
}
154-
cf.Linux.Resources = r
167+
c.Linux.Resources = r
155168
}
156169
}
157170

158171
// Add container command.
159-
func WithCommand(c string, args ...string) ContainerOpts {
160-
return func(cf *runtime.ContainerConfig) {
161-
cf.Command = []string{c}
162-
cf.Args = args
172+
func WithCommand(cmd string, args ...string) ContainerOpts {
173+
return func(c *runtime.ContainerConfig) {
174+
c.Command = []string{cmd}
175+
c.Args = args
163176
}
164177
}
165178

166179
// Add pid namespace mode.
167180
func WithPidNamespace(mode runtime.NamespaceMode) ContainerOpts {
168-
return func(cf *runtime.ContainerConfig) {
169-
if cf.Linux == nil {
170-
cf.Linux = &runtime.LinuxContainerConfig{}
181+
return func(c *runtime.ContainerConfig) {
182+
if c.Linux == nil {
183+
c.Linux = &runtime.LinuxContainerConfig{}
171184
}
172-
if cf.Linux.SecurityContext == nil {
173-
cf.Linux.SecurityContext = &runtime.LinuxContainerSecurityContext{}
185+
if c.Linux.SecurityContext == nil {
186+
c.Linux.SecurityContext = &runtime.LinuxContainerSecurityContext{}
174187
}
175-
if cf.Linux.SecurityContext.NamespaceOptions == nil {
176-
cf.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{}
188+
if c.Linux.SecurityContext.NamespaceOptions == nil {
189+
c.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{}
177190
}
178-
cf.Linux.SecurityContext.NamespaceOptions.Pid = mode
191+
c.Linux.SecurityContext.NamespaceOptions.Pid = mode
179192
}
180193

181194
}
182195

196+
// Add container log path.
197+
func WithLogPath(path string) ContainerOpts {
198+
return func(c *runtime.ContainerConfig) {
199+
c.LogPath = path
200+
}
201+
}
202+
183203
// ContainerConfig creates a container config given a name and image name
184204
// and additional container config options
185205
func ContainerConfig(name, image string, opts ...ContainerOpts) *runtime.ContainerConfig {
@@ -244,3 +264,27 @@ func PidOf(name string) (int, error) {
244264
}
245265
return strconv.Atoi(output)
246266
}
267+
268+
// CRIConfig gets current cri config from containerd.
269+
func CRIConfig() (*criconfig.Config, error) {
270+
addr, dialer, err := kubeletutil.GetAddressAndDialer(*criEndpoint)
271+
if err != nil {
272+
return nil, errors.Wrap(err, "failed to get dialer")
273+
}
274+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
275+
defer cancel()
276+
conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithDialer(dialer))
277+
if err != nil {
278+
return nil, errors.Wrap(err, "failed to connect cri endpoint")
279+
}
280+
client := runtime.NewRuntimeServiceClient(conn)
281+
resp, err := client.Status(ctx, &runtime.StatusRequest{Verbose: true})
282+
if err != nil {
283+
return nil, errors.Wrap(err, "failed to get status")
284+
}
285+
config := &criconfig.Config{}
286+
if err := json.Unmarshal([]byte(resp.Info["config"]), config); err != nil {
287+
return nil, errors.Wrap(err, "failed to unmarshal config")
288+
}
289+
return config, nil
290+
}

pkg/config/config.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ type PluginConfig struct {
9696
SystemdCgroup bool `toml:"systemd_cgroup" json:"systemdCgroup"`
9797
// EnableTLSStreaming indicates to enable the TLS streaming support.
9898
EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"`
99+
// MaxContainerLogLineSize is the maximum log line size in bytes for a container.
100+
// Log line longer than the limit will be split into multiple lines. Non-positive
101+
// value means no limit.
102+
MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"`
99103
}
100104

101105
// Config contains all configurations for cri server.
@@ -129,13 +133,14 @@ func DefaultConfig() PluginConfig {
129133
Root: "",
130134
},
131135
},
132-
StreamServerAddress: "",
133-
StreamServerPort: "10010",
134-
EnableSelinux: false,
135-
EnableTLSStreaming: false,
136-
SandboxImage: "k8s.gcr.io/pause:3.1",
137-
StatsCollectPeriod: 10,
138-
SystemdCgroup: false,
136+
StreamServerAddress: "",
137+
StreamServerPort: "10010",
138+
EnableSelinux: false,
139+
EnableTLSStreaming: false,
140+
SandboxImage: "k8s.gcr.io/pause:3.1",
141+
StatsCollectPeriod: 10,
142+
SystemdCgroup: false,
143+
MaxContainerLogLineSize: 16 * 1024,
139144
Registry: Registry{
140145
Mirrors: map[string]Mirror{
141146
"docker.io": {

0 commit comments

Comments
 (0)