Merge pull request #26 from marineam/oem
Add support for OEM and sending error events
This commit is contained in:
commit
1833613ed6
7 changed files with 377 additions and 34 deletions
|
@ -14,7 +14,8 @@ These differences include:
|
|||
- No offline activity tracking.
|
||||
The protocol's ping mechanism allows for tracking application usage, reporting the number of days since the last ping and how many of those days saw active usage.
|
||||
CoreUpdate does not use this, instead assuming update clients are always online and checking in once every ~45-50 minutes.
|
||||
Each check in should include a ping and optionally an update check.
|
||||
Clients not actively updating should send only a ping, indicating CoreUpdate's "Instance-Hold" state.
|
||||
Clients requesting an update should send a ping, update check, and an UpdateComplete:SuccessReboot event indicating CoreUpdate's "Complete" state.
|
||||
|
||||
- Various protocol extensions/abuses.
|
||||
update_engine, likely due to earlier limitations of the protocol and Google's server implementation, uses a number of non-standard fields.
|
||||
|
|
|
@ -53,6 +53,7 @@ type AppClient struct {
|
|||
appID string
|
||||
track string
|
||||
version string
|
||||
oem string
|
||||
}
|
||||
|
||||
// New creates an omaha client for updating one or more applications.
|
||||
|
@ -154,6 +155,21 @@ func NewAppClient(serverURL, userID, appID, appVersion string) (*AppClient, erro
|
|||
return ac, nil
|
||||
}
|
||||
|
||||
func (ac *AppClient) SetAppID(appID string) error {
|
||||
if appID == ac.appID {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := ac.apps[appID]; ok {
|
||||
return fmt.Errorf("omaha: duplicate app %q", appID)
|
||||
}
|
||||
|
||||
delete(ac.apps, ac.appID)
|
||||
ac.appID = appID
|
||||
ac.apps[appID] = ac
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetVersion changes the application version.
|
||||
func (ac *AppClient) SetVersion(version string) error {
|
||||
if version == "" {
|
||||
|
@ -178,28 +194,42 @@ func (ac *AppClient) SetTrack(track string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetOEM sets the application OEM name.
|
||||
// This is a update_engine/Core Update protocol extension.
|
||||
func (ac *AppClient) SetOEM(oem string) {
|
||||
ac.oem = oem
|
||||
}
|
||||
|
||||
func (ac *AppClient) UpdateCheck() (*omaha.UpdateResponse, error) {
|
||||
req := ac.newReq()
|
||||
req := ac.NewAppRequest()
|
||||
app := req.Apps[0]
|
||||
app.AddPing()
|
||||
app.AddUpdateCheck()
|
||||
|
||||
// Tell CoreUpdate to consider us in its "Complete" state,
|
||||
// otherwise it interprets ping as "Instance-Hold" which is
|
||||
// nonsense when we are sending an update check!
|
||||
app.Events = append(app.Events, EventComplete)
|
||||
|
||||
ac.sentPing = true
|
||||
|
||||
appResp, err := ac.doReq(ac.apiEndpoint, req)
|
||||
appResp, err := ac.SendAppRequest(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if appResp.Ping == nil {
|
||||
// BUG: CoreUpdate does not send ping status in response.
|
||||
/*if appResp.Ping == nil {
|
||||
ac.Event(NewErrorEvent(ExitCodeOmahaResponseInvalid))
|
||||
return nil, fmt.Errorf("omaha: ping status missing from response")
|
||||
}
|
||||
|
||||
if appResp.Ping.Status != "ok" {
|
||||
return nil, fmt.Errorf("omaha: ping status %s", appResp.Ping.Status)
|
||||
}
|
||||
}*/
|
||||
|
||||
if appResp.UpdateCheck == nil {
|
||||
ac.Event(NewErrorEvent(ExitCodeOmahaResponseInvalid))
|
||||
return nil, fmt.Errorf("omaha: update check missing from response")
|
||||
}
|
||||
|
||||
|
@ -211,50 +241,68 @@ func (ac *AppClient) UpdateCheck() (*omaha.UpdateResponse, error) {
|
|||
}
|
||||
|
||||
func (ac *AppClient) Ping() error {
|
||||
req := ac.newReq()
|
||||
req := ac.NewAppRequest()
|
||||
app := req.Apps[0]
|
||||
app.AddPing()
|
||||
|
||||
ac.sentPing = true
|
||||
|
||||
appResp, err := ac.doReq(ac.apiEndpoint, req)
|
||||
appResp, err := ac.SendAppRequest(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if appResp.Ping == nil {
|
||||
// BUG: CoreUpdate does not send ping status in response.
|
||||
_ = appResp
|
||||
/*if appResp.Ping == nil {
|
||||
ac.Event(NewErrorEvent(ExitCodeOmahaResponseInvalid))
|
||||
return fmt.Errorf("omaha: ping status missing from response")
|
||||
}
|
||||
|
||||
if appResp.Ping.Status != "ok" {
|
||||
return fmt.Errorf("omaha: ping status %s", appResp.Ping.Status)
|
||||
}
|
||||
}*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ac *AppClient) Event(event *omaha.EventRequest) error {
|
||||
req := ac.newReq()
|
||||
// Event asynchronously sends the given omaha event.
|
||||
// Reading the error channel is optional.
|
||||
func (ac *AppClient) Event(event *omaha.EventRequest) <-chan error {
|
||||
errc := make(chan error, 1)
|
||||
url := ac.apiEndpoint
|
||||
req := ac.NewAppRequest()
|
||||
app := req.Apps[0]
|
||||
app.Events = append(app.Events, event)
|
||||
|
||||
appResp, err := ac.doReq(ac.apiEndpoint, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
appResp, err := ac.doReq(url, req)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
|
||||
if len(appResp.Events) == 0 {
|
||||
return fmt.Errorf("omaha: event status missing from response")
|
||||
}
|
||||
// BUG: CoreUpdate does not send event status in response.
|
||||
_ = appResp
|
||||
/*if len(appResp.Events) == 0 {
|
||||
errc <- fmt.Errorf("omaha: event status missing from response")
|
||||
return
|
||||
}
|
||||
|
||||
if appResp.Events[0].Status != "ok" {
|
||||
return fmt.Errorf("omaha: event status %s", appResp.Events[0].Status)
|
||||
}
|
||||
if appResp.Events[0].Status != "ok" {
|
||||
errc <- fmt.Errorf("omaha: event status %s", appResp.Events[0].Status)
|
||||
return
|
||||
}*/
|
||||
|
||||
return nil
|
||||
errc <- nil
|
||||
return
|
||||
}()
|
||||
|
||||
return errc
|
||||
}
|
||||
|
||||
func (ac *AppClient) newReq() *omaha.Request {
|
||||
// NewAppRequest creates a Request object containing one application.
|
||||
func (ac *AppClient) NewAppRequest() *omaha.Request {
|
||||
req := omaha.NewRequest()
|
||||
req.Version = ac.clientVersion
|
||||
req.UserID = ac.userID
|
||||
|
@ -265,6 +313,7 @@ func (ac *AppClient) newReq() *omaha.Request {
|
|||
|
||||
app := req.AddApp(ac.appID, ac.version)
|
||||
app.Track = ac.track
|
||||
app.OEM = ac.oem
|
||||
|
||||
// MachineID and BootID are non-standard fields used by CoreOS'
|
||||
// update_engine and Core Update. Copy their values from the
|
||||
|
@ -276,6 +325,23 @@ func (ac *AppClient) newReq() *omaha.Request {
|
|||
return req
|
||||
}
|
||||
|
||||
// SendAppRequest sends a Request object and validates the response.
|
||||
// On failure an error event is automatically sent to the server.
|
||||
func (ac *AppClient) SendAppRequest(req *omaha.Request) (*omaha.AppResponse, error) {
|
||||
resp, err := ac.doReq(ac.apiEndpoint, req)
|
||||
if _, ok := err.(omaha.AppStatus); ok {
|
||||
// No point to sending an error if we got a well-formed
|
||||
// non-ok application status in the response.
|
||||
} else if err, ok := err.(ErrorEvent); ok {
|
||||
ac.Event(err.ErrorEvent())
|
||||
} else if err != nil {
|
||||
ac.Event(NewErrorEvent(ExitCodeOmahaRequestError))
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// doReq posts an omaha request. It may be called in its own goroutine so
|
||||
// it should not touch any mutable data in AppClient, but apiClient is ok.
|
||||
func (ac *AppClient) doReq(url string, req *omaha.Request) (*omaha.AppResponse, error) {
|
||||
if len(req.Apps) != 1 {
|
||||
panic(fmt.Errorf("unexpected number of apps: %d", len(req.Apps)))
|
||||
|
@ -288,7 +354,10 @@ func (ac *AppClient) doReq(url string, req *omaha.Request) (*omaha.AppResponse,
|
|||
|
||||
appResp := resp.GetApp(appID)
|
||||
if appResp == nil {
|
||||
return nil, fmt.Errorf("omaha: app %s missing from response", appID)
|
||||
return nil, &omahaError{
|
||||
Err: fmt.Errorf("app %s missing from response", appID),
|
||||
Code: ExitCodeOmahaResponseInvalid,
|
||||
}
|
||||
}
|
||||
|
||||
if appResp.Status != omaha.AppOK {
|
||||
|
|
|
@ -100,6 +100,15 @@ func TestClientNoUpdate(t *testing.T) {
|
|||
if len(r.checks) != 1 {
|
||||
t.Fatalf("expected 1 update check, not %d", len(r.checks))
|
||||
}
|
||||
|
||||
if len(r.events) != 1 {
|
||||
t.Fatalf("expected 1 event, not %d", len(r.events))
|
||||
}
|
||||
|
||||
if r.events[0].Type != omaha.EventTypeUpdateComplete ||
|
||||
r.events[0].Result != omaha.EventResultSuccessReboot {
|
||||
t.Fatalf("expected %#v, not %#v", EventComplete, r.events[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientWithUpdate(t *testing.T) {
|
||||
|
@ -132,6 +141,15 @@ func TestClientWithUpdate(t *testing.T) {
|
|||
if len(r.checks) != 1 {
|
||||
t.Fatalf("expected 1 update check, not %d", len(r.checks))
|
||||
}
|
||||
|
||||
if len(r.events) != 1 {
|
||||
t.Fatalf("expected 1 event, not %d", len(r.events))
|
||||
}
|
||||
|
||||
if r.events[0].Type != omaha.EventTypeUpdateComplete ||
|
||||
r.events[0].Result != omaha.EventResultSuccessReboot {
|
||||
t.Fatalf("expected %#v, not %#v", EventComplete, r.events[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientPing(t *testing.T) {
|
||||
|
@ -167,7 +185,7 @@ func TestClientEvent(t *testing.T) {
|
|||
Type: omaha.EventTypeDownloadComplete,
|
||||
Result: omaha.EventResultSuccess,
|
||||
}
|
||||
if err := ac.Event(event); err != nil {
|
||||
if err := <-ac.Event(event); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,19 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-omaha/omaha"
|
||||
)
|
||||
|
||||
var (
|
||||
bodySizeError = errors.New("http response exceeded 1MB")
|
||||
bodyEmptyError = errors.New("http response was empty")
|
||||
bodySizeError = &omahaError{
|
||||
Err: errors.New("http response exceeded 1MB"),
|
||||
Code: ExitCodeOmahaResponseInvalid,
|
||||
}
|
||||
bodyEmptyError = &omahaError{
|
||||
Err: errors.New("http response was empty"),
|
||||
Code: ExitCodeOmahaRequestEmptyResponseError,
|
||||
}
|
||||
|
||||
// default parameters for expNetBackoff
|
||||
backoffStart = time.Second
|
||||
|
@ -60,7 +68,21 @@ func isUnexpectedEOF(err error) bool {
|
|||
return err == io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
// httpError implements error and net.Error for http responses.
|
||||
// omahaError implements error and ErrorEvent for omaha requests/responses.
|
||||
type omahaError struct {
|
||||
Err error
|
||||
Code ExitCode
|
||||
}
|
||||
|
||||
func (oe *omahaError) Error() string {
|
||||
return "omaha: request failed: " + oe.Err.Error()
|
||||
}
|
||||
|
||||
func (oe *omahaError) ErrorEvent() *omaha.EventRequest {
|
||||
return NewErrorEvent(oe.Code)
|
||||
}
|
||||
|
||||
// httpError implements error, net.Error, and ErrorEvent for http responses.
|
||||
type httpError struct {
|
||||
*http.Response
|
||||
}
|
||||
|
@ -69,6 +91,14 @@ func (he *httpError) Error() string {
|
|||
return "http error: " + he.Status
|
||||
}
|
||||
|
||||
func (he *httpError) ErrorEvent() *omaha.EventRequest {
|
||||
code := ExitCodeOmahaRequestError
|
||||
if he.StatusCode > 0 && he.StatusCode < 1000 {
|
||||
code = ExitCodeOmahaRequestHTTPResponseBase + ExitCode(he.StatusCode)
|
||||
}
|
||||
return NewErrorEvent(code)
|
||||
}
|
||||
|
||||
func (he *httpError) Timeout() bool {
|
||||
switch he.StatusCode {
|
||||
case http.StatusRequestTimeout: // 408
|
||||
|
|
|
@ -45,7 +45,7 @@ func newHTTPClient() *httpClient {
|
|||
func (hc *httpClient) doPost(url string, reqBody []byte) (*omaha.Response, error) {
|
||||
resp, err := hc.Post(url, "text/xml; charset=utf-8", bytes.NewReader(reqBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, &omahaError{err, ExitCodeOmahaRequestError}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
@ -59,6 +59,8 @@ func (hc *httpClient) doPost(url string, reqBody []byte) (*omaha.Response, error
|
|||
err = bodySizeError
|
||||
} else if err == io.EOF {
|
||||
err = bodyEmptyError
|
||||
} else if err != nil {
|
||||
err = &omahaError{err, ExitCodeOmahaRequestXMLParseError}
|
||||
}
|
||||
|
||||
// Prefer reporting HTTP errors over XML parsing errors.
|
||||
|
@ -81,9 +83,6 @@ func (hc *httpClient) Omaha(url string, req *omaha.Request) (resp *omaha.Respons
|
|||
resp, err = hc.doPost(url, buf.Bytes())
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("omaha: request failed: %v", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
return resp, err
|
||||
}
|
||||
|
|
226
omaha/client/update_engine_events.go
Normal file
226
omaha/client/update_engine_events.go
Normal file
|
@ -0,0 +1,226 @@
|
|||
// Copyright 2017 CoreOS, Inc.
|
||||
// Copyright 2011 The Chromium OS Authors.
|
||||
//
|
||||
// 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 client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/go-omaha/omaha"
|
||||
)
|
||||
|
||||
var (
|
||||
// These events are what update_engine sends to CoreUpdate to
|
||||
// mark different steps in the update process.
|
||||
EventDownloading = &omaha.EventRequest{
|
||||
Type: omaha.EventTypeUpdateDownloadStarted,
|
||||
Result: omaha.EventResultSuccess,
|
||||
}
|
||||
EventDownloaded = &omaha.EventRequest{
|
||||
Type: omaha.EventTypeUpdateDownloadFinished,
|
||||
Result: omaha.EventResultSuccess,
|
||||
}
|
||||
EventInstalled = &omaha.EventRequest{
|
||||
Type: omaha.EventTypeUpdateComplete,
|
||||
Result: omaha.EventResultSuccess,
|
||||
}
|
||||
EventComplete = &omaha.EventRequest{
|
||||
Type: omaha.EventTypeUpdateComplete,
|
||||
Result: omaha.EventResultSuccessReboot,
|
||||
}
|
||||
)
|
||||
|
||||
// ExitCode is used for omaha event error codes derived from update_engine
|
||||
type ExitCode int
|
||||
|
||||
// These error codes are from CoreOS Container Linux update_engine 0.4.x
|
||||
// https://github.com/coreos/update_engine/blob/master/src/update_engine/action_processor.h
|
||||
// The whole list is included for the sake of completeness but lots of these
|
||||
// are not generally applicable and not even used by update_engine any more.
|
||||
// Also there are clearly duplicate errors for the same condition.
|
||||
const (
|
||||
ExitCodeSuccess ExitCode = 0
|
||||
ExitCodeError ExitCode = 1
|
||||
ExitCodeOmahaRequestError ExitCode = 2
|
||||
ExitCodeOmahaResponseHandlerError ExitCode = 3
|
||||
ExitCodeFilesystemCopierError ExitCode = 4
|
||||
ExitCodePostinstallRunnerError ExitCode = 5
|
||||
ExitCodeSetBootableFlagError ExitCode = 6
|
||||
ExitCodeInstallDeviceOpenError ExitCode = 7
|
||||
ExitCodeKernelDeviceOpenError ExitCode = 8
|
||||
ExitCodeDownloadTransferError ExitCode = 9
|
||||
ExitCodePayloadHashMismatchError ExitCode = 10
|
||||
ExitCodePayloadSizeMismatchError ExitCode = 11
|
||||
ExitCodeDownloadPayloadVerificationError ExitCode = 12
|
||||
ExitCodeDownloadNewPartitionInfoError ExitCode = 13
|
||||
ExitCodeDownloadWriteError ExitCode = 14
|
||||
ExitCodeNewRootfsVerificationError ExitCode = 15
|
||||
ExitCodeNewKernelVerificationError ExitCode = 16
|
||||
ExitCodeSignedDeltaPayloadExpectedError ExitCode = 17
|
||||
ExitCodeDownloadPayloadPubKeyVerificationError ExitCode = 18
|
||||
ExitCodePostinstallBootedFromFirmwareB ExitCode = 19
|
||||
ExitCodeDownloadStateInitializationError ExitCode = 20
|
||||
ExitCodeDownloadInvalidMetadataMagicString ExitCode = 21
|
||||
ExitCodeDownloadSignatureMissingInManifest ExitCode = 22
|
||||
ExitCodeDownloadManifestParseError ExitCode = 23
|
||||
ExitCodeDownloadMetadataSignatureError ExitCode = 24
|
||||
ExitCodeDownloadMetadataSignatureVerificationError ExitCode = 25
|
||||
ExitCodeDownloadMetadataSignatureMismatch ExitCode = 26
|
||||
ExitCodeDownloadOperationHashVerificationError ExitCode = 27
|
||||
ExitCodeDownloadOperationExecutionError ExitCode = 28
|
||||
ExitCodeDownloadOperationHashMismatch ExitCode = 29
|
||||
ExitCodeOmahaRequestEmptyResponseError ExitCode = 30
|
||||
ExitCodeOmahaRequestXMLParseError ExitCode = 31
|
||||
ExitCodeDownloadInvalidMetadataSize ExitCode = 32
|
||||
ExitCodeDownloadInvalidMetadataSignature ExitCode = 33
|
||||
ExitCodeOmahaResponseInvalid ExitCode = 34
|
||||
ExitCodeOmahaUpdateIgnoredPerPolicy ExitCode = 35
|
||||
ExitCodeOmahaUpdateDeferredPerPolicy ExitCode = 36
|
||||
ExitCodeOmahaErrorInHTTPResponse ExitCode = 37
|
||||
ExitCodeDownloadOperationHashMissingError ExitCode = 38
|
||||
ExitCodeDownloadMetadataSignatureMissingError ExitCode = 39
|
||||
ExitCodeOmahaUpdateDeferredForBackoff ExitCode = 40
|
||||
ExitCodePostinstallPowerwashError ExitCode = 41
|
||||
ExitCodeNewPCRPolicyVerificationError ExitCode = 42
|
||||
ExitCodeNewPCRPolicyHTTPError ExitCode = 43
|
||||
|
||||
// Use the 2xxx range to encode HTTP errors from the Omaha server.
|
||||
// Sometimes aggregated into ExitCodeOmahaErrorInHTTPResponse
|
||||
ExitCodeOmahaRequestHTTPResponseBase ExitCode = 2000 // + HTTP response code
|
||||
)
|
||||
|
||||
func (e ExitCode) String() string {
|
||||
switch e {
|
||||
case ExitCodeSuccess:
|
||||
return "success"
|
||||
case ExitCodeError:
|
||||
return "error"
|
||||
case ExitCodeOmahaRequestError:
|
||||
return "omaha request error"
|
||||
case ExitCodeOmahaResponseHandlerError:
|
||||
return "omaha response handler error"
|
||||
case ExitCodeFilesystemCopierError:
|
||||
return "filesystem copier error"
|
||||
case ExitCodePostinstallRunnerError:
|
||||
return "postinstall runner error"
|
||||
case ExitCodeSetBootableFlagError:
|
||||
return "set bootable flag error"
|
||||
case ExitCodeInstallDeviceOpenError:
|
||||
return "install device open error"
|
||||
case ExitCodeKernelDeviceOpenError:
|
||||
return "kernel device open error"
|
||||
case ExitCodeDownloadTransferError:
|
||||
return "download transfer error"
|
||||
case ExitCodePayloadHashMismatchError:
|
||||
return "payload hash mismatch error"
|
||||
case ExitCodePayloadSizeMismatchError:
|
||||
return "payload size mismatch error"
|
||||
case ExitCodeDownloadPayloadVerificationError:
|
||||
return "download payload verification error"
|
||||
case ExitCodeDownloadNewPartitionInfoError:
|
||||
return "download new partition info error"
|
||||
case ExitCodeDownloadWriteError:
|
||||
return "download write error"
|
||||
case ExitCodeNewRootfsVerificationError:
|
||||
return "new rootfs verification error"
|
||||
case ExitCodeNewKernelVerificationError:
|
||||
return "new kernel verification error"
|
||||
case ExitCodeSignedDeltaPayloadExpectedError:
|
||||
return "signed delta payload expected error"
|
||||
case ExitCodeDownloadPayloadPubKeyVerificationError:
|
||||
return "download payload pubkey verification error"
|
||||
case ExitCodePostinstallBootedFromFirmwareB:
|
||||
return "postinstall booted from firmware B"
|
||||
case ExitCodeDownloadStateInitializationError:
|
||||
return "download state initialization error"
|
||||
case ExitCodeDownloadInvalidMetadataMagicString:
|
||||
return "download invalid metadata magic string"
|
||||
case ExitCodeDownloadSignatureMissingInManifest:
|
||||
return "download signature missing in manifest"
|
||||
case ExitCodeDownloadManifestParseError:
|
||||
return "download manifest parse error"
|
||||
case ExitCodeDownloadMetadataSignatureError:
|
||||
return "download metadata signature error"
|
||||
case ExitCodeDownloadMetadataSignatureVerificationError:
|
||||
return "download metadata signature verification error"
|
||||
case ExitCodeDownloadMetadataSignatureMismatch:
|
||||
return "download metadata signature mismatch"
|
||||
case ExitCodeDownloadOperationHashVerificationError:
|
||||
return "download operation hash verification error"
|
||||
case ExitCodeDownloadOperationExecutionError:
|
||||
return "download operation execution error"
|
||||
case ExitCodeDownloadOperationHashMismatch:
|
||||
return "download operation hash mismatch"
|
||||
case ExitCodeOmahaRequestEmptyResponseError:
|
||||
return "omaha request empty response error"
|
||||
case ExitCodeOmahaRequestXMLParseError:
|
||||
return "omaha request XML parse error"
|
||||
case ExitCodeDownloadInvalidMetadataSize:
|
||||
return "download invalid metadata size"
|
||||
case ExitCodeDownloadInvalidMetadataSignature:
|
||||
return "download invalid metadata signature"
|
||||
case ExitCodeOmahaResponseInvalid:
|
||||
return "omaha response invalid"
|
||||
case ExitCodeOmahaUpdateIgnoredPerPolicy:
|
||||
return "omaha update ignored per policy"
|
||||
case ExitCodeOmahaUpdateDeferredPerPolicy:
|
||||
return "omaha update deferred per policy"
|
||||
case ExitCodeOmahaErrorInHTTPResponse:
|
||||
return "omaha error in HTTP response"
|
||||
case ExitCodeDownloadOperationHashMissingError:
|
||||
return "download operation hash missing error"
|
||||
case ExitCodeDownloadMetadataSignatureMissingError:
|
||||
return "download metadata signature missing error"
|
||||
case ExitCodeOmahaUpdateDeferredForBackoff:
|
||||
return "omaha update deferred for backoff"
|
||||
case ExitCodePostinstallPowerwashError:
|
||||
return "postinstall powerwash error"
|
||||
case ExitCodeNewPCRPolicyVerificationError:
|
||||
return "new PCR policy verification error"
|
||||
case ExitCodeNewPCRPolicyHTTPError:
|
||||
return "new PCR policy HTTP error"
|
||||
default:
|
||||
if e > ExitCodeOmahaRequestHTTPResponseBase {
|
||||
return fmt.Sprintf("omaha response HTTP %d error",
|
||||
e-ExitCodeOmahaRequestHTTPResponseBase)
|
||||
}
|
||||
return fmt.Sprintf("error code %d", e)
|
||||
}
|
||||
}
|
||||
|
||||
// NewErrorEvent creates an EventRequest for reporting errors.
|
||||
func NewErrorEvent(e ExitCode) *omaha.EventRequest {
|
||||
return &omaha.EventRequest{
|
||||
Type: omaha.EventTypeUpdateComplete,
|
||||
Result: omaha.EventResultError,
|
||||
ErrorCode: int(e),
|
||||
}
|
||||
}
|
||||
|
||||
// EventString allows for easily logging events in a readable format.
|
||||
func EventString(e *omaha.EventRequest) string {
|
||||
s := fmt.Sprintf("omaha event: %s: %s", e.Type, e.Result)
|
||||
if e.ErrorCode != 0 {
|
||||
s = fmt.Sprintf("%s (%d - %s)", s,
|
||||
e.ErrorCode, ExitCode(e.ErrorCode))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ErrorEvent is an error type that can generate EventRequests for reporting.
|
||||
type ErrorEvent interface {
|
||||
error
|
||||
ErrorEvent() *omaha.EventRequest
|
||||
}
|
|
@ -142,7 +142,7 @@ type PingRequest struct {
|
|||
type EventRequest struct {
|
||||
Type EventType `xml:"eventtype,attr"`
|
||||
Result EventResult `xml:"eventresult,attr"`
|
||||
ErrorCode string `xml:"errorcode,attr,omitempty"`
|
||||
ErrorCode int `xml:"errorcode,attr,omitempty"`
|
||||
NextVersion string `xml:"nextversion,attr,omitempty"`
|
||||
PreviousVersion string `xml:"previousversion,attr,omitempty"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue