Skip to content

Commit 739cdc8

Browse files
committed
Omit nil or empty field when calculating hash value
1 parent ff1e112 commit 739cdc8

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed

pkg/kubelet/container/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ go_test(
4646
name = "go_default_test",
4747
srcs = [
4848
"cache_test.go",
49+
"container_hash_test.go",
4950
"helpers_test.go",
5051
"ref_test.go",
5152
"runtime_cache_test.go",
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
Copyright 2019 The Kubernetes 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 container
18+
19+
import (
20+
"encoding/json"
21+
"testing"
22+
23+
"k8s.io/api/core/v1"
24+
)
25+
26+
var (
27+
sampleContainer = `
28+
{
29+
"name": "test_container",
30+
"image": "foo/image:v1",
31+
"command": [
32+
"/bin/testcmd"
33+
],
34+
"args": [
35+
"/bin/sh",
36+
"-c",
37+
"echo abc"
38+
],
39+
"ports": [
40+
{
41+
"containerPort": 8001
42+
}
43+
],
44+
"env": [
45+
{
46+
"name": "ENV_FOO",
47+
"value": "bar"
48+
},
49+
{
50+
"name": "ENV_BAR",
51+
"valueFrom": {
52+
"secretKeyRef": {
53+
"name": "foo",
54+
"key": "bar",
55+
"optional": true
56+
}
57+
}
58+
}
59+
],
60+
"resources": {
61+
"limits": {
62+
"foo": "1G"
63+
},
64+
"requests": {
65+
"foo": "500M"
66+
}
67+
}
68+
}
69+
`
70+
71+
sampleV115HashValue = uint64(0x311670a)
72+
sampleV116HashValue = sampleV115HashValue
73+
)
74+
75+
func TestConsistentHashContainer(t *testing.T) {
76+
container := &v1.Container{}
77+
if err := json.Unmarshal([]byte(sampleContainer), container); err != nil {
78+
t.Error(err)
79+
}
80+
81+
currentHash := HashContainer(container)
82+
if currentHash != sampleV116HashValue {
83+
t.Errorf("mismatched hash value with v1.16")
84+
}
85+
86+
if currentHash != sampleV115HashValue {
87+
t.Errorf("mismatched hash value with v1.15")
88+
}
89+
}

pkg/kubelet/container/helpers.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package container
1818

1919
import (
20+
"encoding/json"
2021
"fmt"
2122
"hash/fnv"
2223
"strings"
@@ -92,9 +93,13 @@ func ShouldContainerBeRestarted(container *v1.Container, pod *v1.Pod, podStatus
9293

9394
// HashContainer returns the hash of the container. It is used to compare
9495
// the running container with its desired spec.
96+
// Note: remember to update hashValues in container_hash_test.go as well.
9597
func HashContainer(container *v1.Container) uint64 {
9698
hash := fnv.New32a()
97-
hashutil.DeepHashObject(hash, *container)
99+
// Omit nil or empty field when calculating hash value
100+
// Please see https://github.com/kubernetes/kubernetes/issues/53644
101+
containerJson, _ := json.Marshal(container)
102+
hashutil.DeepHashObject(hash, containerJson)
98103
return uint64(hash.Sum32())
99104
}
100105

pkg/kubelet/container/helpers_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,37 @@ func TestMakePortMappings(t *testing.T) {
574574
assert.Equal(t, tt.expectedPortMappings, actual, "[%d]", i)
575575
}
576576
}
577+
578+
func TestHashContainer(t *testing.T) {
579+
testCases := []struct {
580+
name string
581+
image string
582+
args []string
583+
containerPort int32
584+
expectedHash uint64
585+
}{
586+
{
587+
name: "test_container",
588+
image: "foo/image:v1",
589+
args: []string{
590+
"/bin/sh",
591+
"-c",
592+
"echo abc",
593+
},
594+
containerPort: int32(8001),
595+
expectedHash: uint64(0x3c42280f),
596+
},
597+
}
598+
599+
for _, tc := range testCases {
600+
container := v1.Container{
601+
Name: tc.name,
602+
Image: tc.image,
603+
Args: tc.args,
604+
Ports: []v1.ContainerPort{{ContainerPort: tc.containerPort}},
605+
}
606+
607+
hashVal := HashContainer(&container)
608+
assert.Equal(t, tc.expectedHash, hashVal, "the hash value here should not be changed.")
609+
}
610+
}

0 commit comments

Comments
 (0)