package updates import ( "errors" "sync" "time" ) // PackageUpdate is one pending update. On Linux it is a package with a version // on each side. On Windows CurrentVersion is empty and NewVersion carries the // KB article ID: a Windows update is not a version bump of a named package, // and inventing a current version would put a wrong string in front of an // operator. type PackageUpdate struct { Name string CurrentVersion string NewVersion string Phased bool // Ubuntu phased update this host is not yet selected for } // CheckAvailable lists pending OS updates. func CheckAvailable() ([]PackageUpdate, error) { return checkAvailable() } // ApplyOptions selects what an Apply run installs and when it must stop. type ApplyOptions struct { // SecurityOnly installs security fixes only. A host with no security // metadata reports Unsupported and installs nothing: it never falls back // to installing everything. SecurityOnly bool // Deadline is the end of the maintenance window. It only gates the start // of each phase (index refresh, upgrade, Windows install): a phase that // has not started by then is not started, and one already running is // allowed to finish, bounded by defaultApplyCap from its own start. Zero // means a manual run with no window. Deadline time.Time } // Result is what one Apply run did. Output is the tail of the package // manager's combined output, for the operator to read when something failed. type Result struct { Output string Unsupported bool Reason string // why Unsupported, in words for the run page } // ErrBusy means another Apply is already running on this host. var ErrBusy = errors.New("an update run is already in progress on this host") // defaultApplyCap is the backstop for one started upgrade command, counted // from that command's own start. It exists for a package manager that hangs, // not to enforce the window. const defaultApplyCap = 2 * time.Hour var applyMu sync.Mutex // Apply installs pending updates. It never reboots: ScheduleReboot is a // separate decision taken by the caller, and only when the command asked. func Apply(opts ApplyOptions) (Result, error) { if !applyMu.TryLock() { return Result{}, ErrBusy } defer applyMu.Unlock() return apply(opts.SecurityOnly, opts.Deadline) } // ScheduleReboot restarts the host after a short grace period, so a result // sent just before it has time to leave. func ScheduleReboot() error { return scheduleReboot() } // RebootRequired reports whether this host is waiting on a restart. func RebootRequired() bool { return rebootRequired() }