The window deadline no longer kills a running package manager: it only gates the start of each phase, and a started upgrade runs under a 2 hour backstop that sends SIGTERM on Linux. A PatchResult whose send fails is queued and flushed on the next command stream, retaking the reboot decision. deb822 folded Suites continuation lines are filtered with the field. The startup static inventory report is retried until it succeeds.
71 lines
2.5 KiB
Go
71 lines
2.5 KiB
Go
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
|
|
}
|
|
|
|
// 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() }
|