Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into error-kinds-from-…
Browse files Browse the repository at this point in the history
…client

fix conflicts
  • Loading branch information
pedronis committed Aug 5, 2020
2 parents 9fbb318 + a777978 commit 6888672
Show file tree
Hide file tree
Showing 13 changed files with 699 additions and 136 deletions.
64 changes: 32 additions & 32 deletions client/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ type ErrorKind string
// error kind const value doc comments here have a non-default,
// specialized style (to help docs/error-kind.go):
//
// // ErrorKind...: DESCRIPTION [no final dot]
// // ErrorKind...: DESCRIPTION .
//
// Note the mandatory dot at the end.
// `code-like` quoting should be used when meaningful.

// Error kinds. Keep in sync with: https://forum.snapcraft.io/t/using-the-rest-api/18603#heading--errors
// Error kinds. Keep https://forum.snapcraft.io/t/using-the-rest-api/18603#heading--errors in sync using doc/error-kinds.go.
const (
// ErrorKindTwoFactorRequired: the client needs to retry the
// `login` command including an OTP
// `login` command including an OTP.
ErrorKindTwoFactorRequired ErrorKind = "two-factor-required"
// ErrorKindTwoFactorFailed: the OTP provided wasn't recognised
// ErrorKindTwoFactorFailed: the OTP provided wasn't recognised.
ErrorKindTwoFactorFailed ErrorKind = "two-factor-failed"
// ErrorKindLoginRequired: the requested operation cannot be
// performed without an authenticated user. This is the kind
Expand All @@ -46,46 +47,45 @@ const (
// and a list of the failures on each field.
ErrorKindInvalidAuthData ErrorKind = "invalid-auth-data"
// ErrorKindPasswordPolicy: provided password doesn't meet
// system policy
// system policy.
ErrorKindPasswordPolicy ErrorKind = "password-policy"
// ErrorKindAuthCancelled: authentication was cancelled by the user
// ErrorKindAuthCancelled: authentication was cancelled by the user.
ErrorKindAuthCancelled ErrorKind = "auth-cancelled"

// ErrorKindTermsNotAccepted: deprecated, do not document
// ErrorKindTermsNotAccepted: deprecated, do not document.
ErrorKindTermsNotAccepted ErrorKind = "terms-not-accepted"
// ErrorKindNoPaymentMethods: deprecated, do not document
// ErrorKindNoPaymentMethods: deprecated, do not document.
ErrorKindNoPaymentMethods ErrorKind = "no-payment-methods"
// ErrorKindPaymentDeclined: deprecated, do not document
// ErrorKindPaymentDeclined: deprecated, do not document.
ErrorKindPaymentDeclined ErrorKind = "payment-declined"

// ErrorKindSnapAlreadyInstalled: the requested snap is
// already installed
// already installed.
ErrorKindSnapAlreadyInstalled ErrorKind = "snap-already-installed"
// ErrorKindSnapNotInstalled: the requested snap is not installed
// ErrorKindSnapNotInstalled: the requested snap is not installed.
ErrorKindSnapNotInstalled ErrorKind = "snap-not-installed"
// ErrorKindSnapNotFound: the requested snap couldn't be found
// ErrorKindSnapNotFound: the requested snap couldn't be found.
ErrorKindSnapNotFound ErrorKind = "snap-not-found"
// ErrorKindAppNotFound: the requested app couldn't be found
// ErrorKindAppNotFound: the requested app couldn't be found.
ErrorKindAppNotFound ErrorKind = "app-not-found"
// ErrorKindSnapLocal: cannot perform operation on local snap
// ErrorKindSnapLocal: cannot perform operation on local snap.
ErrorKindSnapLocal ErrorKind = "snap-local"
// ErrorKindSnapNeedsDevMode: the requested snap needs devmode
// to be installed
// to be installed.
ErrorKindSnapNeedsDevMode ErrorKind = "snap-needs-devmode"
// ErrorKindSnapNeedsClassic: the requested snap needs classic
// confinement to be installed
// confinement to be installed.
ErrorKindSnapNeedsClassic ErrorKind = "snap-needs-classic"
// ErrorKindSnapNeedsClassicSystem: the requested snap can't
// be installed on the current non-classic system
// be installed on the current non-classic system.
ErrorKindSnapNeedsClassicSystem ErrorKind = "snap-needs-classic-system"
// ErrorKindSnapNotClassic: snap not compatible with classic mode
// ErrorKindSnapNotClassic: snap not compatible with classic mode.
ErrorKindSnapNotClassic ErrorKind = "snap-not-classic"
// ErrorKindSnapNoUpdateAvailable: the requested snap does not
// have an update available
// have an update available.
ErrorKindSnapNoUpdateAvailable ErrorKind = "snap-no-update-available"

// ErrorKindSnapRevisionNotAvailable: no snap revision available
// as specified
// as specified.
ErrorKindSnapRevisionNotAvailable ErrorKind = "snap-revision-not-available"
// ErrorKindSnapChannelNotAvailable: no snap revision on specified
// channel. The `value` of the error is a rich object with
Expand All @@ -105,38 +105,38 @@ const (
ErrorKindSnapChangeConflict ErrorKind = "snap-change-conflict"

// ErrorKindNotSnap: the given snap or directory does not
// look like a snap
// look like a snap.
ErrorKindNotSnap ErrorKind = "snap-not-a-snap"

// ErrorKindInterfacesUnchanged: the requested interfaces'
// operation would have no effect
// operation would have no effect.
ErrorKindInterfacesUnchanged ErrorKind = "interfaces-unchanged"

// ErrorKindBadQuery: a bad query was provided
// ErrorKindBadQuery: a bad query was provided.
ErrorKindBadQuery ErrorKind = "bad-query"
// ErrorKindConfigNoSuchOption: the given configuration option
// does not exist
// does not exist.
ErrorKindConfigNoSuchOption ErrorKind = "option-not-found"

// ErrorKindAssertionNotFound: assertion can not be found
// ErrorKindAssertionNotFound: assertion can not be found.
ErrorKindAssertionNotFound ErrorKind = "assertion-not-found"

// ErrorKindUnsuccessful: snapctl command was unsuccessful
// ErrorKindUnsuccessful: snapctl command was unsuccessful.
ErrorKindUnsuccessful ErrorKind = "unsuccessful"

// ErrorKindNetworkTimeout: a timeout occurred during the request
// ErrorKindNetworkTimeout: a timeout occurred during the request.
ErrorKindNetworkTimeout ErrorKind = "network-timeout"

// ErrorKindDNSFailure: DNS not responding
// ErrorKindDNSFailure: DNS not responding.
ErrorKindDNSFailure ErrorKind = "dns-failure"
)

// Maintenance error kinds.
// These are used only inside the maintenance field of responses.
// Keep in sync with: https://forum.snapcraft.io/t/using-the-rest-api/18603#heading--maint-errors
// Keep https://forum.snapcraft.io/t/using-the-rest-api/18603#heading--maint-errors in sync using doc/error-kinds.go.
const (
// ErrorKindDaemonRestart: daemon is restarting
// ErrorKindDaemonRestart: daemon is restarting.
ErrorKindDaemonRestart ErrorKind = "daemon-restart"
// ErrorKindSystemRestart: system is restarting
// ErrorKindSystemRestart: system is restarting.
ErrorKindSystemRestart ErrorKind = "system-restart"
)
8 changes: 8 additions & 0 deletions cmd/snap-bootstrap/cmd_initramfs_mounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,14 @@ func (s *initramfsMountsSuite) testInitramfsMountsInstallRecoverModeStep2Measure
}

func (s *initramfsMountsSuite) TestInitramfsMountsInstallModeStep2Measure(c *C) {
s.testInitramfsMountsInstallRecoverModeStep2Measure(c, "install")
}

func (s *initramfsMountsSuite) TestInitramfsMountsInstallModeUnsetStep2Measure(c *C) {
// TODO:UC20: eventually we should require snapd_recovery_mode to be set to
// explicitly "install" for install mode, but we originally allowed
// snapd_recovery_mode="" and interpreted it as install mode, so test that
// case too
s.testInitramfsMountsInstallRecoverModeStep2Measure(c, "")
}

Expand Down
22 changes: 20 additions & 2 deletions cmd/snap/cmd_debug_seeding.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

type cmdSeeding struct {
clientMixin
unicodeMixin
}

func init() {
Expand All @@ -45,6 +46,8 @@ func init() {
}

func (x *cmdSeeding) Execute(args []string) error {
esc := x.getEscapes()

if len(args) > 0 {
return ErrExtraArgs
}
Expand All @@ -59,6 +62,8 @@ func (x *cmdSeeding) Execute(args []string) error {
// use json.RawMessage to delay unmarshal'ing to the interfaces pkg
PreseedSystemKey *json.RawMessage `json:"preseed-system-key,omitempty"`
SeedRestartSystemKey *json.RawMessage `json:"seed-restart-system-key,omitempty"`

SeedError string `json:"seed-error,omitempty"`
}
if err := x.client.DebugGet("seeding", &resp, nil); err != nil {
return err
Expand All @@ -68,6 +73,19 @@ func (x *cmdSeeding) Execute(args []string) error {

// show seeded and preseeded keys
fmt.Fprintf(w, "seeded:\t%v\n", resp.Seeded)
if resp.SeedError != "" {
// print seed-error
termWidth, _ := termSize()
termWidth -= 3
if termWidth > 100 {
// any wider than this and it gets hard to read
termWidth = 100
}
fmt.Fprintln(w, "seed-error: |")
// XXX: reuse/abuse
printDescr(w, resp.SeedError, termWidth)
}

fmt.Fprintf(w, "preseeded:\t%v\n", resp.Preseeded)

// calculate the time spent preseeding (if preseeded) and seeding
Expand All @@ -76,13 +94,13 @@ func (x *cmdSeeding) Execute(args []string) error {

// if we are missing time values, we will default to showing "-" for the
// duration
seedDuration := "-"
seedDuration := esc.dash
if resp.Preseeded {
if resp.PreseedTime != nil && resp.PreseedStartTime != nil {
preseedDuration := resp.PreseedTime.Sub(*resp.PreseedStartTime).Round(time.Millisecond)
fmt.Fprintf(w, "image-preseeding:\t%v\n", preseedDuration)
} else {
fmt.Fprintf(w, "image-preseeding:\t-\n")
fmt.Fprintf(w, "image-preseeding:\t%s\n", esc.dash)
}

if resp.SeedTime != nil && resp.SeedRestartTime != nil {
Expand Down
85 changes: 73 additions & 12 deletions cmd/snap/cmd_debug_seeding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,18 @@ var noPreseedingJSON = `
"type": "sync"
}`

var seedingError = `{
"result": {
"preseed-start-time": "2020-07-24T21:41:33.838194712Z",
"preseed-time": "2020-07-24T21:41:43.156401424Z",
"preseeded": true,
"seed-error": "cannot perform the following tasks:\n- xxx"
},
"status": "OK",
"status-code": 200,
"type": "sync"
}`

// a system that was preseeded, but didn't record the new keys
// this is the case for a system that was preseeded and then seeded with an old
// snapd, but then is refreshed to a version of snapd that supports snap debug
Expand Down Expand Up @@ -258,11 +270,12 @@ var stillSeedingNoPreseed = `{

func (s *SnapSuite) TestDebugSeeding(c *C) {
tt := []struct {
jsonResp string
expStdout string
expStderr string
expErr string
comment string
jsonResp string
expStdout string
expStderr string
expErr string
comment string
hasUnicode bool
}{
{
jsonResp: newPreseedNewSnapdSameSysKey,
Expand Down Expand Up @@ -361,9 +374,19 @@ seed-restart-system-key: {
expStdout: `
seeded: true
preseeded: false
seed-completion: -
seed-completion: --
`[1:],
comment: "not preseeded",
comment: "not preseeded no unicode",
},
{
jsonResp: noPreseedingJSON,
expStdout: `
seeded: true
preseeded: false
seed-completion: –
`[1:],
comment: "not preseeded",
hasUnicode: true,
},
{
jsonResp: oldPreseedingJSON,
Expand All @@ -381,18 +404,52 @@ seed-completion: 2m0s
seeded: false
preseeded: true
image-preseeding: 9.318s
seed-completion: -
seed-completion: --
`[1:],
comment: "preseeded, still seeding",
comment: "preseeded, still seeding no unicode",
},
{
jsonResp: stillSeeding,
expStdout: `
seeded: false
preseeded: true
image-preseeding: 9.318s
seed-completion: –
`[1:],
hasUnicode: true,
comment: "preseeded, still seeding",
},
{
jsonResp: stillSeedingNoPreseed,
expStdout: `
seeded: false
preseeded: false
seed-completion: -
seed-completion: --
`[1:],
comment: "not preseeded, still seeding",
comment: "not preseeded, still seeding no unicode",
},
{
jsonResp: stillSeedingNoPreseed,
expStdout: `
seeded: false
preseeded: false
seed-completion: –
`[1:],
hasUnicode: true,
comment: "not preseeded, still seeding",
},
{
jsonResp: seedingError,
expStdout: `
seeded: false
seed-error: |
cannot perform the following tasks:
- xxx
preseeded: true
image-preseeding: 9.318s
seed-completion: --
`[1:],
comment: "preseeded, error during seeding",
},
}

Expand All @@ -414,7 +471,11 @@ seed-completion: -
c.Fatalf("expected to get 1 request, now on %d", n)
}
})
rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"debug", "seeding"})
args := []string{"debug", "seeding"}
if t.hasUnicode {
args = append(args, "--unicode=always")
}
rest, err := snap.Parser(snap.Client()).ParseArgs(args)
if t.expErr != "" {
c.Assert(err, ErrorMatches, t.expErr, comment)
c.Assert(s.Stdout(), Equals, "", comment)
Expand Down
22 changes: 22 additions & 0 deletions daemon/api_debug_seeding.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ type seedingInfo struct {
// SeedRestartSystemKey is the system-key that was created on first boot of the
// preseeded image.
SeedRestartSystemKey interface{} `json:"seed-restart-system-key,omitempty"`

// SeedError is set if no seed change succeeded yet and at
// least one was in error. It is set to the error of the
// oldest known in error one.
SeedError string `json:"seed-error,omitempty"`
}

func getSeedingInfo(st *state.State) Response {
Expand All @@ -76,8 +81,25 @@ func getSeedingInfo(st *state.State) Response {
return InternalError(err.Error())
}

var seedError string
var seedErrorChangeTime time.Time
if !seeded {
for _, chg := range st.Changes() {
if chg.Kind() != "seed" && !chg.IsReady() {
continue
}
if err := chg.Err(); err != nil {
if seedErrorChangeTime.IsZero() || chg.SpawnTime().Before(seedErrorChangeTime) {
seedError = chg.Err().Error()
seedErrorChangeTime = chg.SpawnTime()
}
}
}
}

data := &seedingInfo{
Seeded: seeded,
SeedError: seedError,
Preseeded: preseeded,
PreseedSystemKey: preseedSysKey,
SeedRestartSystemKey: seedRestartSysKey,
Expand Down
Loading

0 comments on commit 6888672

Please sign in to comment.