Skip to content

Commit

Permalink
Ensure errors.json with structured data is parsed (#995)
Browse files Browse the repository at this point in the history
Currently we were handling only the simple case where the errors.json
file contains a map of strings. However, there are situations where
the json file may contain more structured data which needs handled.

Fixes #994

Signed-off-by: John Schnake <[email protected]>
  • Loading branch information
johnSchnake authored Nov 13, 2019
1 parent c5ad70d commit 6f983e2
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 5 deletions.
5 changes: 3 additions & 2 deletions pkg/client/results/processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package results

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
Expand Down Expand Up @@ -270,14 +271,14 @@ func errProcessor(pluginDir string, currentFile string) (Item, error) {
defer infile.Close()

dec := json.NewDecoder(infile)
result := map[string]string{}
result := map[string]interface{}{}
if err := dec.Decode(&result); err != nil {
return resultObj, errors.Wrapf(err, "decoding file %v", currentFile)
}

// Just copy the data from the saved error file.
for k, v := range result {
resultObj.Details[k] = v
resultObj.Details[k] = fmt.Sprint(v)
}

// Surface the error to be the name of the "test" to make the error mode more visible to end users.
Expand Down
4 changes: 4 additions & 0 deletions pkg/client/results/processing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ func TestPostProcessPlugin(t *testing.T) {
desc: "Timeout errors cause timeout status",
key: "job-timeout",
plugin: getPlugin("job-timeout", "job", "junit", []string{}),
}, {
desc: "Errors can contain complex structured data",
key: "job-complex-err",
plugin: getPlugin("job-complex-err", "job", "junit", []string{}),
},
}
for _, tc := range testCases {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error":"Container e2e is terminated state (exit code 0) due to reason: Completed: ","pod":{"metadata":{"name":"sonobuoy-e2e-job-2a1ccb8f20764fa6","namespace":"sonobuoy","selfLink":"/api/v1/namespaces/sonobuoy/pods/sonobuoy-e2e-job-2a1ccb8f20764fa6","uid":"a61eafb3-a789-4eed-9a6e-b59e7ed40f8e","resourceVersion":"783915","creationTimestamp":"2019-11-13T09:12:57Z","labels":{"component":"sonobuoy","sonobuoy-plugin":"e2e","sonobuoy-run":"2a1ccb8f20764fa6","tier":"analysis"},"annotations":{"sonobuoy-driver":"Job","sonobuoy-plugin":"e2e"},"ownerReferences":[{"apiVersion":"v1","kind":"Pod","name":"sonobuoy","uid":"ec2ac9a2-3bfb-453c-99ee-dfda0d1f75c2"}]},"spec":{"volumes":[{"name":"results","emptyDir":{}},{"name":"sonobuoy-serviceaccount-token-k245m","secret":{"secretName":"sonobuoy-serviceaccount-token-k245m","defaultMode":420}}],"containers":[{"name":"e2e","image":"gcr.io/google-containers/conformance:v1.15.3","command":["/run_e2e.sh"],"env":[{"name":"E2E_FOCUS","value":"Pods should be submitted and removed"},{"name":"E2E_SKIP"},{"name":"E2E_PARALLEL","value":"1"},{"name":"E2E_USE_GO_RUNNER","value":"true"}],"resources":{},"volumeMounts":[{"name":"results","mountPath":"/tmp/results"},{"name":"sonobuoy-serviceaccount-token-k245m","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"},{"name":"sonobuoy-worker","image":"sonobuoy/sonobuoy:v0.16.3","command":["/sonobuoy"],"args":["worker","global","-v","5","--logtostderr"],"env":[{"name":"NODE_NAME","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"spec.nodeName"}}},{"name":"RESULTS_DIR","value":"/tmp/results"},{"name":"RESULT_TYPE","value":"e2e"},{"name":"MASTER_URL","value":"https://[10.88.0.16]:8080"},{"name":"CA_CERT","value":"-----BEGIN CERTIFICATE-----\nMIIB0jCCAXigAwIBAgIBATAKBggqhkjOPQQDAjBgMQwwCgYDVQQGEwNVU0ExFjAU\nBgNVBAcTDVBhbG8gQWx0bywgQ0ExDzANBgNVBAoTBlZNd2FyZTERMA8GA1UECxMI\nU29ub2J1b3kxFDASBgNVBAMTC3Nvbm9idW95LWNhMB4XDTE5MTExMzA5MTI1N1oX\nDTE5MTExNTA5MTI1N1owYDEMMAoGA1UEBhMDVVNBMRYwFAYDVQQHEw1QYWxvIEFs\ndG8sIENBMQ8wDQYDVQQKEwZWTXdhcmUxETAPBgNVBAsTCFNvbm9idW95MRQwEgYD\nVQQDEwtzb25vYnVveS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABN0+QzRo\nYef72BU07GIczIIaHqWYgHUHr8ZqkGVeomIsOoKqiY6M6kSQUcpDHEW/5f6m8OE/\n/GoJx70div2hxnOjIzAhMA4GA1UdDwEB/wQEAwICBDAPBgNVHRMBAf8EBTADAQH/\nMAoGCCqGSM49BAMCA0gAMEUCIQDWlamkfJjZXOWp0EJZjDEdGzV+Xj44yKXKfBOO\neVp9EgIgbmREQ4WUYtg7pqv5HMMu4gd3AtIxQvOpx9Xgtevnx48=\n-----END CERTIFICATE-----\n"},{"name":"CLIENT_CERT","valueFrom":{"secretKeyRef":{"name":"sonobuoy-plugin-e2e-2a1ccb8f20764fa6","key":"tls.crt"}}},{"name":"CLIENT_KEY","valueFrom":{"secretKeyRef":{"name":"sonobuoy-plugin-e2e-2a1ccb8f20764fa6","key":"tls.key"}}},{"name":"SONOBUOY_PROGRESS_PORT","value":"8099"}],"resources":{},"volumeMounts":[{"name":"results","mountPath":"/tmp/results"},{"name":"sonobuoy-serviceaccount-token-k245m","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Never","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"sonobuoy-serviceaccount","serviceAccount":"sonobuoy-serviceaccount","nodeName":"worker-1","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node-role.kubernetes.io/master","operator":"Exists","effect":"NoSchedule"},{"key":"CriticalAddonsOnly","operator":"Exists"},{"key":"kubernetes.io/e2e-evict-taint-key","operator":"Exists"},{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Running","conditions":[{"type":"Initialized","status":"True","lastProbeTime":null,"lastTransitionTime":"2019-11-13T09:12:57Z"},{"type":"Ready","status":"False","lastProbeTime":null,"lastTransitionTime":"2019-11-13T09:13:16Z","reason":"ContainersNotReady","message":"containers with unready status: [e2e]"},{"type":"ContainersReady","status":"False","lastProbeTime":null,"lastTransitionTime":"2019-11-13T09:13:16Z","reason":"ContainersNotReady","message":"containers with unready status: [e2e]"},{"type":"PodScheduled","status":"True","lastProbeTime":null,"lastTransitionTime":"2019-11-13T09:12:57Z"}],"hostIP":"192.168.0.21","podIP":"10.88.0.17","startTime":"2019-11-13T09:12:57Z","containerStatuses":[{"name":"e2e","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2019-11-13T09:12:59Z","finishedAt":"2019-11-13T09:13:16Z","containerID":"cri-o://67cc3e7b86946202181601b3015b6bba7eaa6abbfcbf3163b296e09aa4ffa33d"}},"lastState":{},"ready":false,"restartCount":0,"image":"gcr.io/google-containers/conformance:v1.15.3","imageID":"gcr.io/google-containers/conformance@sha256:fd457d177f69c64cc06bacb824b44d099e73c432ac84b8130af6eab2bf702345","containerID":"cri-o://67cc3e7b86946202181601b3015b6bba7eaa6abbfcbf3163b296e09aa4ffa33d"},{"name":"sonobuoy-worker","state":{"running":{"startedAt":"2019-11-13T09:12:59Z"}},"lastState":{},"ready":true,"restartCount":0,"image":"docker.io/sonobuoy/sonobuoy:v0.16.3","imageID":"docker.io/sonobuoy/sonobuoy@sha256:d1c511532ac706b57af9d000866953ebc43729fa87bd088056e7f77b2a6d0633","containerID":"cri-o://f02638d227a08e11f9d97e0b3f29f5a7a6157a7313bbd9608d3779be2ac92738"}],"qosClass":"BestEffort"}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "job-complex-err",
"status": "failed",
"items": [
{
"name": "Container e2e is terminated state (exit code 0) due to reason: Completed: ",
"status": "failed",
"meta": {
"file": "errors/error.json"
},
"details": {
"error": "Container e2e is terminated state (exit code 0) due to reason: Completed: ",
"pod": "map[metadata:map[annotations:map[sonobuoy-driver:Job sonobuoy-plugin:e2e] creationTimestamp:2019-11-13T09:12:57Z labels:map[component:sonobuoy sonobuoy-plugin:e2e sonobuoy-run:2a1ccb8f20764fa6 tier:analysis] name:sonobuoy-e2e-job-2a1ccb8f20764fa6 namespace:sonobuoy ownerReferences:[map[apiVersion:v1 kind:Pod name:sonobuoy uid:ec2ac9a2-3bfb-453c-99ee-dfda0d1f75c2]] resourceVersion:783915 selfLink:/api/v1/namespaces/sonobuoy/pods/sonobuoy-e2e-job-2a1ccb8f20764fa6 uid:a61eafb3-a789-4eed-9a6e-b59e7ed40f8e] spec:map[containers:[map[command:[/run_e2e.sh] env:[map[name:E2E_FOCUS value:Pods should be submitted and removed] map[name:E2E_SKIP] map[name:E2E_PARALLEL value:1] map[name:E2E_USE_GO_RUNNER value:true]] image:gcr.io/google-containers/conformance:v1.15.3 imagePullPolicy:Always name:e2e resources:map[] terminationMessagePath:/dev/termination-log terminationMessagePolicy:File volumeMounts:[map[mountPath:/tmp/results name:results] map[mountPath:/var/run/secrets/kubernetes.io/serviceaccount name:sonobuoy-serviceaccount-token-k245m readOnly:true]]] map[args:[worker global -v 5 --logtostderr] command:[/sonobuoy] env:[map[name:NODE_NAME valueFrom:map[fieldRef:map[apiVersion:v1 fieldPath:spec.nodeName]]] map[name:RESULTS_DIR value:/tmp/results] map[name:RESULT_TYPE value:e2e] map[name:MASTER_URL value:https://[10.88.0.16]:8080] map[name:CA_CERT value:-----BEGIN CERTIFICATE-----\nMIIB0jCCAXigAwIBAgIBATAKBggqhkjOPQQDAjBgMQwwCgYDVQQGEwNVU0ExFjAU\nBgNVBAcTDVBhbG8gQWx0bywgQ0ExDzANBgNVBAoTBlZNd2FyZTERMA8GA1UECxMI\nU29ub2J1b3kxFDASBgNVBAMTC3Nvbm9idW95LWNhMB4XDTE5MTExMzA5MTI1N1oX\nDTE5MTExNTA5MTI1N1owYDEMMAoGA1UEBhMDVVNBMRYwFAYDVQQHEw1QYWxvIEFs\ndG8sIENBMQ8wDQYDVQQKEwZWTXdhcmUxETAPBgNVBAsTCFNvbm9idW95MRQwEgYD\nVQQDEwtzb25vYnVveS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABN0+QzRo\nYef72BU07GIczIIaHqWYgHUHr8ZqkGVeomIsOoKqiY6M6kSQUcpDHEW/5f6m8OE/\n/GoJx70div2hxnOjIzAhMA4GA1UdDwEB/wQEAwICBDAPBgNVHRMBAf8EBTADAQH/\nMAoGCCqGSM49BAMCA0gAMEUCIQDWlamkfJjZXOWp0EJZjDEdGzV+Xj44yKXKfBOO\neVp9EgIgbmREQ4WUYtg7pqv5HMMu4gd3AtIxQvOpx9Xgtevnx48=\n-----END CERTIFICATE-----\n] map[name:CLIENT_CERT valueFrom:map[secretKeyRef:map[key:tls.crt name:sonobuoy-plugin-e2e-2a1ccb8f20764fa6]]] map[name:CLIENT_KEY valueFrom:map[secretKeyRef:map[key:tls.key name:sonobuoy-plugin-e2e-2a1ccb8f20764fa6]]] map[name:SONOBUOY_PROGRESS_PORT value:8099]] image:sonobuoy/sonobuoy:v0.16.3 imagePullPolicy:IfNotPresent name:sonobuoy-worker resources:map[] terminationMessagePath:/dev/termination-log terminationMessagePolicy:File volumeMounts:[map[mountPath:/tmp/results name:results] map[mountPath:/var/run/secrets/kubernetes.io/serviceaccount name:sonobuoy-serviceaccount-token-k245m readOnly:true]]]] dnsPolicy:ClusterFirst enableServiceLinks:true nodeName:worker-1 priority:0 restartPolicy:Never schedulerName:default-scheduler securityContext:map[] serviceAccount:sonobuoy-serviceaccount serviceAccountName:sonobuoy-serviceaccount terminationGracePeriodSeconds:30 tolerations:[map[effect:NoSchedule key:node-role.kubernetes.io/master operator:Exists] map[key:CriticalAddonsOnly operator:Exists] map[key:kubernetes.io/e2e-evict-taint-key operator:Exists] map[effect:NoExecute key:node.kubernetes.io/not-ready operator:Exists tolerationSeconds:300] map[effect:NoExecute key:node.kubernetes.io/unreachable operator:Exists tolerationSeconds:300]] volumes:[map[emptyDir:map[] name:results] map[name:sonobuoy-serviceaccount-token-k245m secret:map[defaultMode:420 secretName:sonobuoy-serviceaccount-token-k245m]]]] status:map[conditions:[map[lastProbeTime:\u003cnil\u003e lastTransitionTime:2019-11-13T09:12:57Z status:True type:Initialized] map[lastProbeTime:\u003cnil\u003e lastTransitionTime:2019-11-13T09:13:16Z message:containers with unready status: [e2e] reason:ContainersNotReady status:False type:Ready] map[lastProbeTime:\u003cnil\u003e lastTransitionTime:2019-11-13T09:13:16Z message:containers with unready status: [e2e] reason:ContainersNotReady status:False type:ContainersReady] map[lastProbeTime:\u003cnil\u003e lastTransitionTime:2019-11-13T09:12:57Z status:True type:PodScheduled]] containerStatuses:[map[containerID:cri-o://67cc3e7b86946202181601b3015b6bba7eaa6abbfcbf3163b296e09aa4ffa33d image:gcr.io/google-containers/conformance:v1.15.3 imageID:gcr.io/google-containers/conformance@sha256:fd457d177f69c64cc06bacb824b44d099e73c432ac84b8130af6eab2bf702345 lastState:map[] name:e2e ready:false restartCount:0 state:map[terminated:map[containerID:cri-o://67cc3e7b86946202181601b3015b6bba7eaa6abbfcbf3163b296e09aa4ffa33d exitCode:0 finishedAt:2019-11-13T09:13:16Z reason:Completed startedAt:2019-11-13T09:12:59Z]]] map[containerID:cri-o://f02638d227a08e11f9d97e0b3f29f5a7a6157a7313bbd9608d3779be2ac92738 image:docker.io/sonobuoy/sonobuoy:v0.16.3 imageID:docker.io/sonobuoy/sonobuoy@sha256:d1c511532ac706b57af9d000866953ebc43729fa87bd088056e7f77b2a6d0633 lastState:map[] name:sonobuoy-worker ready:true restartCount:0 state:map[running:map[startedAt:2019-11-13T09:12:59Z]]]] hostIP:192.168.0.21 phase:Running podIP:10.88.0.17 qosClass:BestEffort startTime:2019-11-13T09:12:57Z]]"
}
}
]
}
4 changes: 2 additions & 2 deletions pkg/plugin/driver/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import (
"time"

"github.com/vmware-tanzu/sonobuoy/pkg/plugin"
gouuid "github.com/satori/go.uuid"

gouuid "github.com/satori/go.uuid"
v1 "k8s.io/api/core/v1"
)

Expand Down Expand Up @@ -74,7 +74,7 @@ func IsPodFailing(pod *v1.Pod) (bool, string) {
if cstatus.State.Terminated != nil {
// Ensure we give some time to process the results.
if time.Now().Sub(cstatus.State.Terminated.FinishedAt.Time) > terminatedContainerWindow {
errstr := fmt.Sprintf("Container %v is terminated state (exit code %v) due to reason: %v: %v",
errstr := fmt.Sprintf("Container %v is in a terminated state (exit code %v) due to reason: %v: %v",
cstatus.Name,
cstatus.State.Terminated.ExitCode,
cstatus.State.Terminated.Reason,
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugin/driver/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func TestPodFailing(t *testing.T) {
}, {
desc: "Terminated container reported failing if old enough",
expectFailing: true,
expectMsg: "Container container1 is terminated state (exit code 1) due to reason: myReason: myMsg",
expectMsg: "Container container1 is in a terminated state (exit code 1) due to reason: myReason: myMsg",
pod: fromGoodPod(func(p *corev1.Pod) *corev1.Pod {
p.Status.ContainerStatuses = []corev1.ContainerStatus{
{
Expand Down

0 comments on commit 6f983e2

Please sign in to comment.