@@ -69,6 +69,20 @@ func execVNCPassword(socket string, password string) error {
69
69
return err
70
70
}
71
71
72
+ // There is errors.Join(), but stupid Yetus has old golang
73
+ // and complains with "Join not declared by package errors".
74
+ // Use our own.
75
+ func joinErrors (err1 , err2 error ) error {
76
+ if err1 == nil {
77
+ return err2
78
+ }
79
+ if err2 == nil {
80
+ return err1
81
+ }
82
+
83
+ return fmt .Errorf ("%v\n %n" , err1 , err2 )
84
+ }
85
+
72
86
func getQemuStatus (socket string ) (types.SwState , error ) {
73
87
// lets parse the status according to
74
88
// https://github.com/qemu/qemu/blob/master/qapi/run-state.json#L8
@@ -88,7 +102,21 @@ func getQemuStatus(socket string) (types.SwState, error) {
88
102
"preconfig" : types .PAUSED ,
89
103
}
90
104
91
- if raw , err := execRawCmd (socket , `{ "execute": "query-status" }` ); err == nil {
105
+ // We do several retries, because correct QEMU status is very crucial to EVE
106
+ // and if for some reason (https://github.com/digitalocean/go-qemu/pull/210)
107
+ // the status is unexpected, EVE stops QEMU and game over.
108
+ var errs error
109
+ state := types .UNKNOWN
110
+ for attempt := 1 ; attempt <= 3 ; attempt ++ {
111
+ raw , err := execRawCmd (socket , `{ "execute": "query-status" }` )
112
+ if err != nil {
113
+ err = fmt .Errorf ("[attempt %d] qmp status failed for QMP socket '%s': err: '%v'; (JSON response: '%s')" ,
114
+ attempt , socket , err , raw )
115
+ errs = joinErrors (errs , err )
116
+ time .Sleep (time .Second )
117
+ continue
118
+ }
119
+
92
120
var result struct {
93
121
ID string `json:"id"`
94
122
Return struct {
@@ -100,18 +128,27 @@ func getQemuStatus(socket string) (types.SwState, error) {
100
128
dec := json .NewDecoder (bytes .NewReader (raw ))
101
129
dec .DisallowUnknownFields ()
102
130
err = dec .Decode (& result )
103
- var matched bool
104
- var state types.SwState
105
131
if err != nil {
106
- err = fmt .Errorf ("%v; (JSON received: '%s')" , err , raw )
107
- } else if state , matched = qmpStatusMap [result .Return .Status ]; ! matched {
108
- err = fmt .Errorf ("unknown QMP status '%s' for QMP socket '%s'; (JSON response: '%s')" ,
109
- result .Return .Status , socket , raw )
132
+ err = fmt .Errorf ("[attempt %d] failed to parse QMP status response for QMP socket '%s': err: '%v'; (JSON response: '%s')" ,
133
+ attempt , socket , err , raw )
134
+ errs = joinErrors (errs , err )
135
+ time .Sleep (time .Second )
136
+ continue
137
+ }
138
+ var matched bool
139
+ if state , matched = qmpStatusMap [result .Return .Status ]; ! matched {
140
+ err = fmt .Errorf ("[attempt %d] unknown QMP status '%s' for QMP socket '%s'; (JSON response: '%s')" ,
141
+ attempt , result .Return .Status , socket , raw )
142
+ errs = joinErrors (errs , err )
143
+ time .Sleep (time .Second )
144
+ continue
110
145
}
111
- return state , err
112
- } else {
113
- return types . UNKNOWN , err
146
+
147
+ // Success
148
+ break
114
149
}
150
+
151
+ return state , errs
115
152
}
116
153
117
154
func qmpEventHandler (listenerSocket , executorSocket string ) {
0 commit comments