-
Notifications
You must be signed in to change notification settings - Fork 341
/
status.go
140 lines (117 loc) · 4.18 KB
/
status.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
/*
Copyright 2018 Heptio Inc.
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.
*/
package aggregation
import (
"encoding/json"
"fmt"
"time"
"github.com/heptio/sonobuoy/pkg/plugin"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
const (
// RunningStatus means the sonobuoy run is still in progress.
RunningStatus string = "running"
// CompleteStatus means the sonobuoy run is complete.
CompleteStatus string = "complete"
// PostProcessingStatus means the plugins are complete. The state is not
// put in the more finalized, complete, status until any postprocessing is
// done.
PostProcessingStatus string = "post-processing"
// FailedStatus means one or more plugins has failed and the run will not complete successfully.
FailedStatus string = "failed"
)
// PluginStatus represents the current status of an individual plugin.
type PluginStatus struct {
Plugin string `json:"plugin"`
Node string `json:"node"`
Status string `json:"status"`
ResultStatus string `json:"result-status"`
ResultStatusCounts map[string]int `json:"result-counts"`
Progress *plugin.ProgressUpdate `json:"progress,omitempty"`
}
// Status represents the current status of a Sonobuoy run.
// TODO(EKF): Find a better name for this struct/package.
type Status struct {
Plugins []PluginStatus `json:"plugins"`
Status string `json:"status"`
Tarball TarInfo `json:"tar-info,omitempty"`
}
// TarInfo is the type that contains information regarding the tarball
// that a user would get after running `sonobuoy retrieve`.
type TarInfo struct {
Name string `json:"name"`
CreatedAt time.Time `json:"created"`
SHA256 string `json:"sha256"`
Size int64 `json:"size"`
}
// Key returns a unique identifier for the plugin that these status values
// correspond to.
func (p PluginStatus) Key() string {
nodeName := p.Node
if p.Node == "" {
nodeName = plugin.GlobalResult
}
return p.Plugin + "/" + nodeName
}
// updateStatus sets the overall status field based on the values of all of the plugins' status.
func (s *Status) updateStatus() error {
status := PostProcessingStatus
for _, plugin := range s.Plugins {
switch plugin.Status {
case CompleteStatus:
continue
case FailedStatus:
status = FailedStatus
case RunningStatus:
if status != FailedStatus {
status = RunningStatus
}
default:
return fmt.Errorf("unknown status %s", plugin.Status)
}
}
s.Status = status
return nil
}
// GetStatus returns the current status status on the sonobuoy pod. If the pod
// does not exist, is not running, or is missing the status annotation, an error
// is returned.
func GetStatus(client kubernetes.Interface, namespace string) (*Status, error) {
if _, err := client.CoreV1().Namespaces().Get(namespace, metav1.GetOptions{}); err != nil {
return nil, errors.Wrap(err, "sonobuoy namespace does not exist")
}
// Determine sonobuoy pod name
podName, err := GetAggregatorPodName(client, namespace)
if err != nil {
return nil, errors.Wrap(err, "failed to get the name of the aggregator pod to get the status from")
}
pod, err := client.CoreV1().Pods(namespace).Get(podName, metav1.GetOptions{})
if err != nil {
return nil, errors.New("could not retrieve sonobuoy pod")
}
if pod.Status.Phase != corev1.PodRunning {
return nil, fmt.Errorf("pod has status %q", pod.Status.Phase)
}
statusJSON, ok := pod.Annotations[StatusAnnotationName]
if !ok {
return nil, fmt.Errorf("missing status annotation %q", StatusAnnotationName)
}
var status Status
if err := json.Unmarshal([]byte(statusJSON), &status); err != nil {
return nil, errors.Wrap(err, "couldn't unmarshal the JSON status annotation")
}
return &status, nil
}