-
Notifications
You must be signed in to change notification settings - Fork 88
/
preflight.go
161 lines (141 loc) · 4.87 KB
/
preflight.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
package reporting
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"github.com/pkg/errors"
kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1"
appstatetypes "github.com/replicatedhq/kots/pkg/appstate/types"
"github.com/replicatedhq/kots/pkg/buildversion"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/store"
storetypes "github.com/replicatedhq/kots/pkg/store/types"
"github.com/replicatedhq/kots/pkg/util"
troubleshootpreflight "github.com/replicatedhq/troubleshoot/pkg/preflight"
)
func SendPreflightsReportToReplicatedApp(license *kotsv1beta1.License, appID string, clusterID string, sequence int64, skipPreflights bool, installStatus storetypes.DownstreamVersionStatus, isCLI bool, preflightStatus string, appStatus string) error {
endpoint := license.Spec.Endpoint
if !canReport(endpoint) {
return nil
}
urlValues := url.Values{}
urlValues.Set("sequence", fmt.Sprintf("%d", sequence))
urlValues.Set("skipPreflights", fmt.Sprintf("%t", skipPreflights))
urlValues.Set("installStatus", string(installStatus))
urlValues.Set("isCLI", fmt.Sprintf("%t", isCLI))
urlValues.Set("preflightStatus", preflightStatus)
urlValues.Set("appStatus", appStatus)
urlValues.Set("kotsVersion", buildversion.Version())
url := fmt.Sprintf("%s/kots_metrics/preflights/%s/%s?%s", endpoint, appID, clusterID, urlValues.Encode())
var buf bytes.Buffer
postReq, err := util.NewRequest("POST", url, &buf)
if err != nil {
return errors.Wrap(err, "failed to call newrequest")
}
postReq.Header.Add("Authorization", license.Spec.LicenseID)
postReq.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(postReq)
if err != nil {
return errors.Wrap(err, "failed to send preflights reports")
}
defer resp.Body.Close()
if resp.StatusCode != 201 {
return errors.Errorf("Unexpected status code %d", resp.StatusCode)
}
return nil
}
func ReportAppInfo(appID string, sequence int64, isSkipPreflights bool, isCLI bool) error {
app, err := store.GetStore().GetApp(appID)
if err != nil {
return errors.Wrap(err, "failed to get app")
}
if app.IsAirgap {
logger.Debug("no reporting for airgapped app")
return nil
}
license, err := store.GetStore().GetLatestLicenseForApp(appID)
if err != nil {
return errors.Wrap(err, "failed to find license for app")
}
downstreams, err := store.GetStore().ListDownstreamsForApp(appID)
if err != nil {
return errors.Wrap(err, "failed to list downstreams for app")
} else if len(downstreams) == 0 {
err = errors.New("no downstreams for app")
return err
}
clusterID := downstreams[0].ClusterID
go func() {
appStatus := appstatetypes.StateMissing
for start := time.Now(); time.Since(start) < 20*time.Minute; {
s, err := store.GetStore().GetAppStatus(appID)
if err != nil {
logger.Debugf("failed to get app status: %v", err.Error())
return
}
currentDeployedSequence, err := store.GetStore().GetCurrentParentSequence(appID, clusterID)
if err != nil {
logger.Debugf("failed to get downstream parent sequence: %v", err.Error())
return
}
// if user deploy another version and previous version is still running
if currentDeployedSequence != sequence {
logger.Debug("deployed sequence has changed")
return
}
if s.Sequence == sequence && s.State == appstatetypes.StateReady {
appStatus = s.State
break
}
time.Sleep(time.Second * 10)
}
preflightState := ""
var preflightResults *troubleshootpreflight.UploadPreflightResults
for start := time.Now(); time.Since(start) < 5*time.Minute; {
p, err := store.GetStore().GetPreflightResults(appID, sequence)
if err != nil {
logger.Debugf("failed to get preflight results: %v", err.Error())
return
}
if p.Result != "" {
if err := json.Unmarshal([]byte(p.Result), &preflightResults); err != nil {
logger.Debugf("failed to unmarshal preflight results: %v", err.Error())
return
}
preflightState = getPreflightState(preflightResults)
break
}
time.Sleep(time.Second * 10)
}
currentVersionStatus, err := store.GetStore().GetStatusForVersion(appID, clusterID, sequence)
if err != nil {
logger.Debugf("failed to get status for version: %v", err)
return
}
if err := SendPreflightsReportToReplicatedApp(license, appID, clusterID, sequence, isSkipPreflights, currentVersionStatus, isCLI, preflightState, string(appStatus)); err != nil {
logger.Debugf("failed to send preflights data to replicated app: %v", err)
return
}
}()
return nil
}
func getPreflightState(preflightResults *troubleshootpreflight.UploadPreflightResults) string {
if len(preflightResults.Errors) > 0 {
return "fail"
}
if len(preflightResults.Results) == 0 {
return "pass"
}
state := "pass"
for _, result := range preflightResults.Results {
if result.IsFail {
return "fail"
} else if result.IsWarn {
state = "warn"
}
}
return state
}