diff --git a/CHANGELOG.md b/CHANGELOG.md index 84292c30..79b09177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## [v1.3.2]() TBD +* Handle DEP INVALID_CURSOR response (#497) * Fix URL params decoding. ## [v1.3.1](https://github.com/micromdm/micromdm/compare/v1.3.0...master) (Unreleased) diff --git a/dep/depsync/depsync.go b/dep/depsync/depsync.go index 0ac93dc5..bd9f4904 100644 --- a/dep/depsync/depsync.go +++ b/dep/depsync/depsync.go @@ -117,9 +117,10 @@ func New(pub pubsub.PublishSubscriber, db *bolt.DB, logger log.Logger, opts ...O level.Info(logger).Log("msg", "waiting for DEP token to be added before starting sync") <-sync.startSync } - if err := sync.Run(); err != nil { - level.Info(logger).Log("err", err, "msg", "DEP watcher failed") - } + err := sync.Run() + // the DEP sync should never end without an error, but log + // unconditionally anyway so we never silently stop watching + level.Info(logger).Log("err", err, "msg", "DEP watcher stopped") }() return sync, nil } @@ -177,6 +178,10 @@ func isCursorExpired(err error) bool { return strings.Contains(err.Error(), "EXPIRED_CURSOR") } +func isCursorInvalid(err error) bool { + return strings.Contains(err.Error(), "INVALID_CURSOR") +} + // Process DEP messages and pull out filter-matching serial numbers // associated to profile UUIDs for auto-assignment. func (w *watcher) filteredAutoAssignments(devices []dep.Device) (map[string][]string, error) { @@ -287,6 +292,15 @@ FETCH: resp, err := w.client.FetchDevices(dep.Limit(100), dep.Cursor(w.conf.Cursor.Value)) if err != nil && isCursorExhausted(err) { goto SYNC + } else if err != nil && isCursorInvalid(err) { + level.Info(w.logger).Log( + "msg", "DEP fetch cursor response", + "cursor", w.conf.Cursor.Value, + "err", err, + "msg", "retrying DEP fetch with empty cursor", + ) + w.conf.Cursor.Value = "" + goto FETCH } else if err != nil { return err } @@ -312,7 +326,13 @@ FETCH: SYNC: for { resp, err := w.client.SyncDevices(w.conf.Cursor.Value, dep.Cursor(w.conf.Cursor.Value)) - if err != nil && isCursorExpired(err) { + if err != nil && (isCursorExpired(err) || isCursorInvalid(err)) { + level.Info(w.logger).Log( + "msg", "DEP sync cursor response", + "cursor", w.conf.Cursor.Value, + "err", err, + "msg", "retrying DEP fetch with empty cursor", + ) w.conf.Cursor.Value = "" goto FETCH } else if err != nil {