omaha: split request and response structures

Despite having common names between the request and response XML
structures the actual values which may appear in them are completely
disjoint. Splitting the types up makes the protocol easier to understand
when reading the code. When applicable, required fields like status are
passed to Add* methods.
This commit is contained in:
Michael Marineau 2015-07-25 16:44:18 -07:00
parent ec70842bdd
commit 75a1125f53
2 changed files with 101 additions and 61 deletions

View file

@ -28,18 +28,19 @@ import (
"github.com/coreos/mantle/version" "github.com/coreos/mantle/version"
) )
// Request sent by the Omaha client
type Request struct { type Request struct {
XMLName xml.Name `xml:"request" json:"-"` XMLName xml.Name `xml:"request" json:"-"`
OS *OS `xml:"os"` OS *OS `xml:"os"`
Apps []*App `xml:"app"` Apps []*AppRequest `xml:"app"`
Protocol string `xml:"protocol,attr"` Protocol string `xml:"protocol,attr"`
Version string `xml:"version,attr,omitempty"` Version string `xml:"version,attr,omitempty"`
IsMachine string `xml:"ismachine,attr,omitempty"` IsMachine string `xml:"ismachine,attr,omitempty"`
RequestId string `xml:"requestid,attr,omitempty"`
SessionId string `xml:"sessionid,attr,omitempty"` SessionId string `xml:"sessionid,attr,omitempty"`
UserId string `xml:"userid,attr,omitempty"` UserId string `xml:"userid,attr,omitempty"`
InstallSource string `xml:"installsource,attr,omitempty"` InstallSource string `xml:"installsource,attr,omitempty"`
TestSource string `xml:"testsource,attr,omitempty"` TestSource string `xml:"testsource,attr,omitempty"`
RequestId string `xml:"requestid,attr,omitempty"`
UpdaterVersion string `xml:"updaterversion,attr,omitempty"` UpdaterVersion string `xml:"updaterversion,attr,omitempty"`
} }
@ -55,16 +56,69 @@ func NewRequest() *Request {
} }
} }
func (r *Request) AddApp(id, version string) *App { func (r *Request) AddApp(id, version string) *AppRequest {
a := &App{Id: id, Version: version} a := &AppRequest{Id: id, Version: version}
r.Apps = append(r.Apps, a) r.Apps = append(r.Apps, a)
return a return a
} }
type AppRequest struct {
Ping *PingRequest `xml:"ping"`
UpdateCheck *UpdateRequest `xml:"updatecheck"`
Events []*EventRequest `xml:"event" json:",omitempty"`
Id string `xml:"appid,attr,omitempty"`
Version string `xml:"version,attr,omitempty"`
NextVersion string `xml:"nextversion,attr,omitempty"`
Lang string `xml:"lang,attr,omitempty"`
Client string `xml:"client,attr,omitempty"`
InstallAge string `xml:"installage,attr,omitempty"`
// update engine extensions
Track string `xml:"track,attr,omitempty"`
FromTrack string `xml:"from_track,attr,omitempty"`
// coreos update engine extensions
BootId string `xml:"bootid,attr,omitempty"`
MachineID string `xml:"machineid,attr,omitempty"`
OEM string `xml:"oem,attr,omitempty"`
}
func (a *AppRequest) AddUpdateCheck() *UpdateRequest {
a.UpdateCheck = &UpdateRequest{}
return a.UpdateCheck
}
func (a *AppRequest) AddPing() *PingRequest {
a.Ping = new(PingRequest)
return a.Ping
}
func (a *AppRequest) AddEvent() *EventRequest {
event := &EventRequest{}
a.Events = append(a.Events, event)
return event
}
type UpdateRequest struct {
TargetVersionPrefix string `xml:"targetversionprefix,attr,omitempty"`
}
type PingRequest struct {
LastReportDays string `xml:"r,attr,omitempty"`
}
type EventRequest struct {
Type EventType `xml:"eventtype,attr"`
Result EventResult `xml:"eventresult,attr"`
PreviousVersion string `xml:"previousversion,attr,omitempty"`
ErrorCode string `xml:"errorcode,attr,omitempty"`
}
// Response sent by the Omaha server
type Response struct { type Response struct {
XMLName xml.Name `xml:"response" json:"-"` XMLName xml.Name `xml:"response" json:"-"`
DayStart DayStart `xml:"daystart"` DayStart DayStart `xml:"daystart"`
Apps []*App `xml:"app"` Apps []*AppResponse `xml:"app"`
Protocol string `xml:"protocol,attr"` Protocol string `xml:"protocol,attr"`
Server string `xml:"server,attr"` Server string `xml:"server,attr"`
} }
@ -81,58 +135,43 @@ type DayStart struct {
ElapsedSeconds string `xml:"elapsed_seconds,attr"` ElapsedSeconds string `xml:"elapsed_seconds,attr"`
} }
func (r *Response) AddApp(id string, status AppStatus) *App { func (r *Response) AddApp(id string, status AppStatus) *AppResponse {
a := &App{Id: id, Status: status} a := &AppResponse{Id: id, Status: status}
r.Apps = append(r.Apps, a) r.Apps = append(r.Apps, a)
return a return a
} }
type App struct { type AppResponse struct {
Ping *Ping `xml:"ping"` Ping *PingResponse `xml:"ping"`
UpdateCheck *UpdateCheck `xml:"updatecheck"` UpdateCheck *UpdateResponse `xml:"updatecheck"`
Events []*Event `xml:"event" json:",omitempty"` Events []*EventResponse `xml:"event" json:",omitempty"`
Id string `xml:"appid,attr,omitempty"` Id string `xml:"appid,attr,omitempty"`
Version string `xml:"version,attr,omitempty"`
NextVersion string `xml:"nextversion,attr,omitempty"`
Lang string `xml:"lang,attr,omitempty"`
Client string `xml:"client,attr,omitempty"`
InstallAge string `xml:"installage,attr,omitempty"`
Status AppStatus `xml:"status,attr,omitempty"` Status AppStatus `xml:"status,attr,omitempty"`
// update engine extensions
Track string `xml:"track,attr,omitempty"`
FromTrack string `xml:"from_track,attr,omitempty"`
// coreos update engine extensions
BootId string `xml:"bootid,attr,omitempty"`
MachineID string `xml:"machineid,attr,omitempty"`
OEM string `xml:"oem,attr,omitempty"`
} }
func (a *App) AddUpdateCheck() *UpdateCheck { func (a *AppResponse) AddUpdateCheck(status UpdateStatus) *UpdateResponse {
a.UpdateCheck = new(UpdateCheck) a.UpdateCheck = &UpdateResponse{Status: status}
return a.UpdateCheck return a.UpdateCheck
} }
func (a *App) AddPing() *Ping { func (a *AppResponse) AddPing() *PingResponse {
a.Ping = new(Ping) a.Ping = &PingResponse{"ok"}
return a.Ping return a.Ping
} }
func (a *App) AddEvent() *Event { func (a *AppResponse) AddEvent() *EventResponse {
event := new(Event) event := &EventResponse{"ok"}
a.Events = append(a.Events, event) a.Events = append(a.Events, event)
return event return event
} }
type UpdateCheck struct { type UpdateResponse struct {
URLs *URLs `xml:"urls"` URLs *URLs `xml:"urls"`
Manifest *Manifest `xml:"manifest"` Manifest *Manifest `xml:"manifest"`
TargetVersionPrefix string `xml:"targetversionprefix,attr,omitempty"`
Status UpdateStatus `xml:"status,attr,omitempty"` Status UpdateStatus `xml:"status,attr,omitempty"`
} }
func (u *UpdateCheck) AddURL(codebase string) *URL { func (u *UpdateResponse) AddURL(codebase string) *URL {
// An intermediate struct is used instead of a "urls>url" tag simply // An intermediate struct is used instead of a "urls>url" tag simply
// to keep Go from generating <urls></urls> if the list is empty. // to keep Go from generating <urls></urls> if the list is empty.
if u.URLs == nil { if u.URLs == nil {
@ -143,14 +182,17 @@ func (u *UpdateCheck) AddURL(codebase string) *URL {
return url return url
} }
func (u *UpdateCheck) AddManifest(version string) *Manifest { func (u *UpdateResponse) AddManifest(version string) *Manifest {
u.Manifest = &Manifest{Version: version} u.Manifest = &Manifest{Version: version}
return u.Manifest return u.Manifest
} }
type Ping struct { type PingResponse struct {
LastReportDays string `xml:"r,attr,omitempty"` Status string `xml:"status,attr"` // Always "ok".
Status string `xml:"status,attr,omitempty"` }
type EventResponse struct {
Status string `xml:"status,attr"` // Always "ok".
} }
type OS struct { type OS struct {

View file

@ -83,10 +83,8 @@ func TestOmahaRequestUpdateCheck(t *testing.T) {
func ExampleNewResponse() { func ExampleNewResponse() {
response := NewResponse() response := NewResponse()
app := response.AddApp("{52F1B9BC-D31A-4D86-9276-CBC256AADF9A}", "ok") app := response.AddApp("{52F1B9BC-D31A-4D86-9276-CBC256AADF9A}", "ok")
p := app.AddPing() app.AddPing()
p.Status = "ok" u := app.AddUpdateCheck(UpdateOK)
u := app.AddUpdateCheck()
u.Status = "ok"
u.AddURL("http://localhost/updates") u.AddURL("http://localhost/updates")
m := u.AddManifest("9999.0.0") m := u.AddManifest("9999.0.0")
k := m.AddPackage() k := m.AddPackage()