forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
images.go
174 lines (160 loc) · 6.73 KB
/
images.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package operators
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strings"
. "github.com/onsi/ginkgo/v2"
exutil "github.com/openshift/origin/test/extended/util"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
e2e "k8s.io/kubernetes/test/e2e/framework"
)
var _ = Describe("[sig-arch] Managed cluster", func() {
oc := exutil.NewCLIWithoutNamespace("operators")
It("should ensure pods use downstream images from our release image with proper ImagePullPolicy [apigroup:config.openshift.io]", func() {
imagePullSecret, err := oc.KubeFramework().ClientSet.CoreV1().Secrets("openshift-config").Get(context.Background(), "pull-secret", metav1.GetOptions{})
if err != nil {
e2e.Failf("unable to get pull secret for cluster: %v", err)
}
// cache file to local temp location
imagePullFile, err := ioutil.TempFile("", "image-pull-secret")
if err != nil {
e2e.Failf("unable to create a temporary file: %v", err)
}
defer os.Remove(imagePullFile.Name())
// write the content
imagePullSecretBytes := imagePullSecret.Data[".dockerconfigjson"]
if _, err := imagePullFile.Write(imagePullSecretBytes); err != nil {
e2e.Failf("unable to write pull secret to temp file: %v", err)
}
if err := imagePullFile.Close(); err != nil {
e2e.Failf("unable to close file: %v", err)
}
// find out the current installed release info using the temp file
out, err := oc.Run("adm", "release", "info").Args("--pullspecs", "-o", "json", "--registry-config", imagePullFile.Name()).Output()
if err != nil {
// TODO need to determine why release tests are not having access to read payload
e2e.Logf("unable to read release payload with error: %v", err)
return
}
releaseInfo := &ReleaseInfo{}
if err := json.Unmarshal([]byte(out), &releaseInfo); err != nil {
e2e.Failf("unable to decode release payload with error: %v \n output: %s", err, out)
}
e2e.Logf("Release Info image=%s", releaseInfo.Image)
e2e.Logf("Release Info number of tags %v", len(releaseInfo.References.Spec.Tags))
// valid images include the release image and all its tagged references
validImages := sets.NewString()
validImages.Insert(releaseInfo.Image)
if releaseInfo.References == nil {
e2e.Failf("no references found")
}
for i := range releaseInfo.References.Spec.Tags {
tag := releaseInfo.References.Spec.Tags[i]
if tag.From != nil && tag.From.Kind == "DockerImage" {
validImages.Insert(tag.From.Name)
}
}
// iterate over the references to find valid images
pods, err := oc.KubeFramework().ClientSet.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{})
if err != nil {
e2e.Failf("unable to list pods: %v", err)
}
// skip containers that are known to be already succeeded when this test run and they always result
// into error: cannot exec into a container in a completed pod; current phase is Succeeded.
skipPodContainersNames := sets.NewString(
"installer",
"pruner",
)
// list of pods that use images not in the release payload
invalidPodContainerImages := sets.NewString()
invalidPodContainerImagePullPolicy := sets.NewString()
invalidPodContainerDownstreamImages := sets.NewString()
for i := range pods.Items {
pod := pods.Items[i]
if ignoredNamespace(pod.Namespace) {
continue
}
containersToInspect := []v1.Container{}
for j := range pod.Spec.InitContainers {
if skipPodContainersNames.Has(pod.Spec.InitContainers[j].Name) {
continue
}
containersToInspect = append(containersToInspect, pod.Spec.InitContainers[j])
}
for j := range pod.Spec.Containers {
if skipPodContainersNames.Has(pod.Spec.Containers[j].Name) {
continue
}
containersToInspect = append(containersToInspect, pod.Spec.Containers[j])
}
for j := range containersToInspect {
container := containersToInspect[j]
if !validImages.Has(container.Image) {
invalidPodContainerImages.Insert(fmt.Sprintf("%s/%s/%s image=%s", pod.Namespace, pod.Name, container.Name, container.Image))
}
if container.ImagePullPolicy != v1.PullIfNotPresent {
invalidPodContainerImagePullPolicy.Insert(fmt.Sprintf("%s/%s/%s imagePullPolicy=%s", pod.Namespace, pod.Name, container.Name, container.ImagePullPolicy))
}
}
// check if the container's image from the downstream.
for j := range pod.Spec.Containers {
containerName := pod.Spec.Containers[j].Name
commands := []string{
"exec",
pod.Name,
"-c",
containerName,
"--",
"cat",
"/etc/redhat-release",
}
oc.SetNamespace(pod.Namespace)
result, err := oc.AsAdmin().Run(commands...).Args().Output()
if err != nil {
e2e.Logf("unable to run command:%v with error: %v", commands, err)
continue
}
e2e.Logf("Image release info: %s", result)
if !strings.Contains(result, "Red Hat Enterprise Linux") {
invalidPodContainerDownstreamImages.Insert(fmt.Sprintf("%s/%s invalid downstream image!", pod.Name, containerName))
}
}
}
// log for debugging output before we ultimately fail
e2e.Logf("Pods found with invalid container images not present in release payload: %s", strings.Join(invalidPodContainerImages.List(), "\n"))
e2e.Logf("Pods found with invalid container image pull policy not equal to IfNotPresent: %s", strings.Join(invalidPodContainerImagePullPolicy.List(), "\n"))
e2e.Logf("Pods with invalid dowstream images: %s", strings.Join(invalidPodContainerDownstreamImages.List(), "\n"))
if len(invalidPodContainerImages) > 0 {
e2e.Failf("Pods found with invalid container images not present in release payload: %s", strings.Join(invalidPodContainerImages.List(), "\n"))
}
if len(invalidPodContainerImagePullPolicy) > 0 {
e2e.Failf("Pods found with invalid container image pull policy not equal to IfNotPresent: %s", strings.Join(invalidPodContainerImagePullPolicy.List(), "\n"))
}
if len(invalidPodContainerDownstreamImages) > 0 {
e2e.Failf("Pods with invalid dowstream images: %s", strings.Join(invalidPodContainerDownstreamImages.List(), "\n"))
}
})
})
// ignoredNamespace() returns true if the namespace is to be ignored by the test
func ignoredNamespace(namespace string) bool {
// a pod in a namespace that begins with kube-* or openshift-* must come from our release payload
// TODO components in openshift-operators may not come from our payload, may want to weaken restriction
namespacePrefixes := sets.NewString("kube-", "openshift-")
ignoredNamespacePrefixes := sets.NewString("openshift-marketplace", "openshift-must-gather-")
for _, prefix := range namespacePrefixes.List() {
if !strings.HasPrefix(namespace, prefix) {
return true
}
}
for _, prefix := range ignoredNamespacePrefixes.List() {
if strings.HasPrefix(namespace, prefix) {
return true
}
}
return false
}