diff --git a/omaha/codes.go b/omaha/codes.go
new file mode 100644
index 0000000..8eefeb2
--- /dev/null
+++ b/omaha/codes.go
@@ -0,0 +1,170 @@
+// Copyright 2013-2015 CoreOS, 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 omaha
+
+import (
+ "fmt"
+)
+
+type EventType int
+
+const (
+ EventTypeUnknown EventType = 0
+ EventTypeDownloadComplete EventType = 1
+ EventTypeInstallComplete EventType = 2
+ EventTypeUpdateComplete EventType = 3
+ EventTypeUninstall EventType = 4
+ EventTypeDownloadStarted EventType = 5
+ EventTypeInstallStarted EventType = 6
+ EventTypeNewApplicationInstallStarted EventType = 9
+ EventTypeSetupStarted EventType = 10
+ EventTypeSetupFinished EventType = 11
+ EventTypeUpdateApplicationStarted EventType = 12
+ EventTypeUpdateDownloadStarted EventType = 13
+ EventTypeUpdateDownloadFinished EventType = 14
+ EventTypeUpdateInstallerStarted EventType = 15
+ EventTypeSetupUpdateBegin EventType = 16
+ EventTypeSetupUpdateComplete EventType = 17
+ EventTypeRegisterProductComplete EventType = 20
+ EventTypeOEMInstallFirstCheck EventType = 30
+ EventTypeAppSpecificCommandStarted EventType = 40
+ EventTypeAppSpecificCommandEnded EventType = 41
+ EventTypeSetupFailure EventType = 100
+ EventTypeComServerFailure EventType = 102
+ EventTypeSetupUpdateFailure EventType = 103
+)
+
+func (e EventType) String() string {
+ switch e {
+ case EventTypeUnknown:
+ return "unknown"
+ case EventTypeDownloadComplete:
+ return "download complete"
+ case EventTypeInstallComplete:
+ return "install complete"
+ case EventTypeUpdateComplete:
+ return "update complete"
+ case EventTypeUninstall:
+ return "uninstall"
+ case EventTypeDownloadStarted:
+ return "download started"
+ case EventTypeInstallStarted:
+ return "install started"
+ case EventTypeNewApplicationInstallStarted:
+ return "new application install started"
+ case EventTypeSetupStarted:
+ return "setup started"
+ case EventTypeSetupFinished:
+ return "setup finished"
+ case EventTypeUpdateApplicationStarted:
+ return "update application started"
+ case EventTypeUpdateDownloadStarted:
+ return "update download started"
+ case EventTypeUpdateDownloadFinished:
+ return "update download finished"
+ case EventTypeUpdateInstallerStarted:
+ return "update installer started"
+ case EventTypeSetupUpdateBegin:
+ return "setup update begin"
+ case EventTypeSetupUpdateComplete:
+ return "setup update complete"
+ case EventTypeRegisterProductComplete:
+ return "register product complete"
+ case EventTypeOEMInstallFirstCheck:
+ return "OEM install first check"
+ case EventTypeAppSpecificCommandStarted:
+ return "app-specific command started"
+ case EventTypeAppSpecificCommandEnded:
+ return "app-specific command ended"
+ case EventTypeSetupFailure:
+ return "setup failure"
+ case EventTypeComServerFailure:
+ return "COM server failure"
+ case EventTypeSetupUpdateFailure:
+ return "setup update failure "
+ default:
+ return fmt.Sprintf("event %d", e)
+ }
+}
+
+type EventResult int
+
+const (
+ EventResultError EventResult = 0
+ EventResultSuccess EventResult = 1
+ EventResultSuccessReboot EventResult = 2
+ EventResultSuccessRestartBrowser EventResult = 3
+ EventResultCancelled EventResult = 4
+ EventResultErrorInstallerMSI EventResult = 5
+ EventResultErrorInstallerOther EventResult = 6
+ EventResultNoUpdate EventResult = 7
+ EventResultInstallerSystem EventResult = 8
+ EventResultUpdateDeferred EventResult = 9
+ EventResultHandoffError EventResult = 10
+)
+
+func (e EventResult) String() string {
+ switch e {
+ case EventResultError:
+ return "error"
+ case EventResultSuccess:
+ return "success"
+ case EventResultSuccessReboot:
+ return "success reboot"
+ case EventResultSuccessRestartBrowser:
+ return "success restart browser"
+ case EventResultCancelled:
+ return "cancelled"
+ case EventResultErrorInstallerMSI:
+ return "error installer MSI"
+ case EventResultErrorInstallerOther:
+ return "error installer other"
+ case EventResultNoUpdate:
+ return "noupdate"
+ case EventResultInstallerSystem:
+ return "error installer system"
+ case EventResultUpdateDeferred:
+ return "update deferred"
+ case EventResultHandoffError:
+ return "handoff error"
+ default:
+ return fmt.Sprintf("result %d", e)
+ }
+}
+
+type AppStatus string
+
+const (
+ // Standard values
+ AppOK AppStatus = "ok"
+ AppRestricted AppStatus = "restricted"
+ AppUnknownId AppStatus = "error-unknownApplication"
+ AppInvalidId AppStatus = "error-invalidAppId"
+
+ // Extra error values
+ AppInvalidVersion AppStatus = "error-invalidVersion"
+)
+
+type UpdateStatus string
+
+const (
+ NoUpdate UpdateStatus = "noupdate"
+ UpdateOK UpdateStatus = "ok"
+ UpdateOSNotSupported UpdateStatus = "error-osnotsupported"
+ UpdateUnsupportedProtocol UpdateStatus = "error-unsupportedProtocol"
+ UpdatePluginRestrictedHost UpdateStatus = "error-pluginRestrictedHost"
+ UpdateHashError UpdateStatus = "error-hash"
+ UpdateInternalError UpdateStatus = "error-internal"
+)
diff --git a/omaha/protocol.go b/omaha/protocol.go
index 347254c..c4af2eb 100644
--- a/omaha/protocol.go
+++ b/omaha/protocol.go
@@ -24,11 +24,13 @@ package omaha
import (
"encoding/xml"
+
+ "github.com/coreos/mantle/version"
)
type Request struct {
XMLName xml.Name `xml:"request" json:"-"`
- Os Os `xml:"os"`
+ OS *OS `xml:"os"`
Apps []*App `xml:"app"`
Protocol string `xml:"protocol,attr"`
Version string `xml:"version,attr,omitempty"`
@@ -41,16 +43,20 @@ type Request struct {
UpdaterVersion string `xml:"updaterversion,attr,omitempty"`
}
-func NewRequest(version string, platform string, sp string, arch string) *Request {
- r := new(Request)
- r.Protocol = "3.0"
- r.Os = Os{Version: version, Platform: platform, Sp: sp, Arch: arch}
- return r
+func NewRequest() *Request {
+ return &Request{
+ Protocol: "3.0",
+ Version: version.Version,
+ OS: &OS{
+ Platform: LocalPlatform(),
+ Arch: LocalArch(),
+ // TODO(marineam): Version and ServicePack
+ },
+ }
}
-func (r *Request) AddApp(id string, version string) *App {
- a := NewApp(id)
- a.Version = version
+func (r *Request) AddApp(id, version string) *App {
+ a := &App{Id: id, Version: version}
r.Apps = append(r.Apps, a)
return a
}
@@ -63,18 +69,20 @@ type Response struct {
Server string `xml:"server,attr"`
}
-func NewResponse(server string) *Response {
- r := &Response{Server: server, Protocol: "3.0"}
- r.DayStart.ElapsedSeconds = "0"
- return r
+func NewResponse() *Response {
+ return &Response{
+ Protocol: "3.0",
+ Server: "mantle",
+ DayStart: DayStart{ElapsedSeconds: "0"},
+ }
}
type DayStart struct {
ElapsedSeconds string `xml:"elapsed_seconds,attr"`
}
-func (r *Response) AddApp(id string) *App {
- a := NewApp(id)
+func (r *Response) AddApp(id string, status AppStatus) *App {
+ a := &App{Id: id, Status: status}
r.Apps = append(r.Apps, a)
return a
}
@@ -89,7 +97,7 @@ type App struct {
Lang string `xml:"lang,attr,omitempty"`
Client string `xml:"client,attr,omitempty"`
InstallAge string `xml:"installage,attr,omitempty"`
- Status string `xml:"status,attr,omitempty"`
+ Status AppStatus `xml:"status,attr,omitempty"`
// update engine extensions
Track string `xml:"track,attr,omitempty"`
@@ -101,11 +109,6 @@ type App struct {
OEM string `xml:"oem,attr,omitempty"`
}
-func NewApp(id string) *App {
- a := &App{Id: id}
- return a
-}
-
func (a *App) AddUpdateCheck() *UpdateCheck {
a.UpdateCheck = new(UpdateCheck)
return a.UpdateCheck
@@ -123,19 +126,20 @@ func (a *App) AddEvent() *Event {
}
type UpdateCheck struct {
- Urls *Urls `xml:"urls"`
- Manifest *Manifest `xml:"manifest"`
- TargetVersionPrefix string `xml:"targetversionprefix,attr,omitempty"`
- Status string `xml:"status,attr,omitempty"`
+ URLs *URLs `xml:"urls"`
+ Manifest *Manifest `xml:"manifest"`
+ TargetVersionPrefix string `xml:"targetversionprefix,attr,omitempty"`
+ Status UpdateStatus `xml:"status,attr,omitempty"`
}
-func (u *UpdateCheck) AddUrl(codebase string) *Url {
- if u.Urls == nil {
- u.Urls = new(Urls)
+func (u *UpdateCheck) AddURL(codebase string) *URL {
+ // An intermediate struct is used instead of a "urls>url" tag simply
+ // to keep Go from generating if the list is empty.
+ if u.URLs == nil {
+ u.URLs = new(URLs)
}
- url := new(Url)
- url.CodeBase = codebase
- u.Urls.Urls = append(u.Urls.Urls, *url)
+ url := &URL{CodeBase: codebase}
+ u.URLs.URLs = append(u.URLs.URLs, url)
return url
}
@@ -149,58 +153,52 @@ type Ping struct {
Status string `xml:"status,attr,omitempty"`
}
-type Os struct {
- Platform string `xml:"platform,attr,omitempty"`
- Version string `xml:"version,attr,omitempty"`
- Sp string `xml:"sp,attr,omitempty"`
- Arch string `xml:"arch,attr,omitempty"`
-}
-
-func NewOs(platform string, version string, sp string, arch string) *Os {
- o := &Os{Version: version, Platform: platform, Sp: sp, Arch: arch}
- return o
+type OS struct {
+ Platform string `xml:"platform,attr,omitempty"`
+ Version string `xml:"version,attr,omitempty"`
+ ServicePack string `xml:"sp,attr,omitempty"`
+ Arch string `xml:"arch,attr,omitempty"`
}
type Event struct {
- Type string `xml:"eventtype,attr,omitempty"`
- Result string `xml:"eventresult,attr,omitempty"`
- PreviousVersion string `xml:"previousversion,attr,omitempty"`
- ErrorCode string `xml:"errorcode,attr,omitempty"`
+ Type EventType `xml:"eventtype,attr"`
+ Result EventResult `xml:"eventresult,attr"`
+ PreviousVersion string `xml:"previousversion,attr,omitempty"`
+ ErrorCode string `xml:"errorcode,attr,omitempty"`
+ Status string `xml:"status,attr,omitempty"`
}
-type Urls struct {
- Urls []Url `xml:"url" json:",omitempty"`
+type URLs struct {
+ URLs []*URL `xml:"url" json:",omitempty"`
}
-type Url struct {
+type URL struct {
CodeBase string `xml:"codebase,attr"`
}
type Manifest struct {
- Packages Packages `xml:"packages"`
- Actions Actions `xml:"actions"`
- Version string `xml:"version,attr"`
-}
-
-type Packages struct {
- Packages []Package `xml:"package" json:",omitempty"`
+ Packages []*Package `xml:"packages>package"`
+ Actions []*Action `xml:"actions>action"`
+ Version string `xml:"version,attr"`
}
type Package struct {
Hash string `xml:"hash,attr"`
Name string `xml:"name,attr"`
- Size string `xml:"size,attr"`
+ Size uint64 `xml:"size,attr"`
Required bool `xml:"required,attr"`
}
-func (m *Manifest) AddPackage(hash string, name string, size string, required bool) *Package {
- p := &Package{Hash: hash, Name: name, Size: size, Required: required}
- m.Packages.Packages = append(m.Packages.Packages, *p)
+func (m *Manifest) AddPackage() *Package {
+ p := &Package{}
+ m.Packages = append(m.Packages, p)
return p
}
-type Actions struct {
- Actions []*Action `xml:"action" json:",omitempty"`
+func (m *Manifest) AddAction(event string) *Action {
+ a := &Action{Event: event}
+ m.Actions = append(m.Actions, a)
+ return a
}
type Action struct {
@@ -216,50 +214,3 @@ type Action struct {
MetadataSize string `xml:"MetadataSize,attr,omitempty"`
Deadline string `xml:"deadline,attr,omitempty"`
}
-
-func (m *Manifest) AddAction(event string) *Action {
- a := &Action{Event: event}
- m.Actions.Actions = append(m.Actions.Actions, a)
- return a
-}
-
-var EventTypes = map[int]string{
- 0: "unknown",
- 1: "download complete",
- 2: "install complete",
- 3: "update complete",
- 4: "uninstall",
- 5: "download started",
- 6: "install started",
- 9: "new application install started",
- 10: "setup started",
- 11: "setup finished",
- 12: "update application started",
- 13: "update download started",
- 14: "update download finished",
- 15: "update installer started",
- 16: "setup update begin",
- 17: "setup update complete",
- 20: "register product complete",
- 30: "OEM install first check",
- 40: "app-specific command started",
- 41: "app-specific command ended",
- 100: "setup failure",
- 102: "COM server failure",
- 103: "setup update failure",
- 800: "ping",
-}
-
-var EventResults = map[int]string{
- 0: "error",
- 1: "success",
- 2: "success reboot",
- 3: "success restart browser",
- 4: "cancelled",
- 5: "error installer MSI",
- 6: "error installer other",
- 7: "noupdate",
- 8: "error installer system",
- 9: "update deferred",
- 10: "handoff error",
-}
diff --git a/omaha/protocol_test.go b/omaha/protocol_test.go
index cc0ff25..428aca2 100644
--- a/omaha/protocol_test.go
+++ b/omaha/protocol_test.go
@@ -35,8 +35,8 @@ func TestOmahaRequestUpdateCheck(t *testing.T) {
v := Request{}
xml.Unmarshal([]byte(SampleRequest), &v)
- if v.Os.Version != "Indy" {
- t.Error("Unexpected version", v.Os.Version)
+ if v.OS.Version != "Indy" {
+ t.Error("Unexpected version", v.OS.Version)
}
if v.Apps[0].Id != "{87efface-864d-49a5-9bb3-4b050a7c227a}" {
@@ -71,22 +71,29 @@ func TestOmahaRequestUpdateCheck(t *testing.T) {
t.Error("dev-channel")
}
- if v.Apps[0].Events[0].Type != "3" {
- t.Error("developer-build")
+ if v.Apps[0].Events[0].Type != EventTypeUpdateComplete {
+ t.Error("Expected EventTypeUpdateComplete")
+ }
+
+ if v.Apps[0].Events[0].Result != EventResultSuccessReboot {
+ t.Error("Expected EventResultSuccessReboot")
}
}
func ExampleNewResponse() {
- response := NewResponse("unit-test")
- app := response.AddApp("{52F1B9BC-D31A-4D86-9276-CBC256AADF9A}")
- app.Status = "ok"
+ response := NewResponse()
+ app := response.AddApp("{52F1B9BC-D31A-4D86-9276-CBC256AADF9A}", "ok")
p := app.AddPing()
p.Status = "ok"
u := app.AddUpdateCheck()
u.Status = "ok"
- u.AddUrl("http://localhost/updates")
+ u.AddURL("http://localhost/updates")
m := u.AddManifest("9999.0.0")
- m.AddPackage("+LXvjiaPkeYDLHoNKlf9qbJwvnk=", "update.gz", "67546213", true)
+ k := m.AddPackage()
+ k.Hash = "+LXvjiaPkeYDLHoNKlf9qbJwvnk="
+ k.Name = "update.gz"
+ k.Size = 67546213
+ k.Required = true
a := m.AddAction("postinstall")
a.ChromeOSVersion = "9999.0.0"
a.Sha256 = "0VAlQW3RE99SGtSB5R4m08antAHO8XDoBMKDyxQT/Mg="
@@ -103,7 +110,7 @@ func ExampleNewResponse() {
// Output:
//
- //
+ //
//
//
//
@@ -125,13 +132,19 @@ func ExampleNewResponse() {
}
func ExampleNewRequest() {
- request := NewRequest("Indy", "Chrome OS", "ForcedUpdate_x86_64", "")
+ request := NewRequest()
+ request.Version = ""
+ request.OS = &OS{
+ Platform: "Chrome OS",
+ Version: "Indy",
+ ServicePack: "ForcedUpdate_x86_64",
+ }
app := request.AddApp("{27BD862E-8AE8-4886-A055-F7F1A6460627}", "1.0.0.0")
app.AddUpdateCheck()
event := app.AddEvent()
- event.Type = "1"
- event.Result = "0"
+ event.Type = EventTypeDownloadComplete
+ event.Result = EventResultError
if raw, err := xml.MarshalIndent(request, "", " "); err != nil {
fmt.Println(err)
diff --git a/omaha/system.go b/omaha/system.go
new file mode 100644
index 0000000..1311a1c
--- /dev/null
+++ b/omaha/system.go
@@ -0,0 +1,53 @@
+// Copyright 2015 CoreOS, 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 omaha
+
+import (
+ "runtime"
+)
+
+// Translate GOARCH to Omaha's choice of names, because no two independent
+// software projects *ever* use the same set of architecture names. ;-)
+func LocalArch() string {
+ switch runtime.GOARCH {
+ case "386":
+ return "x86"
+ case "amd64":
+ return "x64"
+ case "amd64p32":
+ // Not actually specified by Omaha but it follows the above.
+ return "x32"
+ case "arm":
+ fallthrough
+ default:
+ // Nothing else is defined by Omaha so anything goes.
+ return runtime.GOARCH
+ }
+}
+
+// Translate GOOS to Omaha's platform names as best as we can.
+func LocalPlatform() string {
+ switch runtime.GOOS {
+ case "darwin":
+ return "mac" // or "ios"
+ case "linux":
+ return "linux" // or "android"
+ case "windows":
+ return "win"
+ default:
+ // Nothing else is defined by Omaha so anything goes.
+ return runtime.GOOS
+ }
+}