update: roll back what the restart actually deploys
On the deployment deploy/README.md documents, source_dir and install_dir are
the same tree and the restart command rebuilds the image from it. The
Dockerfile builds from cmd/ and internal/ and .dockerignore keeps the host
binaries out, so restoring the snapshotted binaries restored bytes nothing
reads. A bad commit therefore cost two health timeouts and two image builds
and ended in ErrRollbackFailed with an instruction to copy files back by hand,
which would not have helped either.
A deployment that rebuilds from source now has to say how the source is put
back. source_rollback "git" records the commit before the update and checks it
back out before the rollback restart. It refuses a dirty tree, because the
recorded commit does not describe one and a forced checkout would delete his
work. A build-from-source config that says nothing is refused by Validate, at
startup, rather than at the one rollback that mattered.
Also in this change, all from the same review:
- MethodPing, the one method a locked daemon answers. Preflight passed on an
unlocked daemon and the post-restart Presence read failed on a locked one,
so a good update read as SHE IS PROBABLY DOWN once the env key is gone.
- A dial failure is reported apart from a read failure. The documented
socket is under /var/lib/docker, which a non-root operator cannot
traverse, and "she is not answering" was the wrong diagnosis.
- Verify refuses to run as root over a tree owned by someone else. It runs
make build and make test in place, and root-owned artifacts break his next
ordinary make.
- A rollback no longer reverts config_files. That undid every config edit
since the last apply, phraser.model_path among them.
- The verify-failure path no longer reports rolled_back for a compile error.
- waitHealthy caps each attempt at the remaining budget, so a 90s timeout
cannot run to 99s.
- tail cuts on a rune boundary. Russian test names showed the seam.
- The claim that mavend does not import internal/update is replaced with
what is enforced: mavend constructs no Updater and nothing can call Apply.
- snapshot_dir inside source_dir is refused. It landed in the build context.
Found in review of #69.
This commit is contained in:
@@ -164,11 +164,26 @@ func (st *Store) Load(id string) (Snapshot, error) {
|
||||
// This is the function the whole package exists to be able to run. It uses the
|
||||
// filesystem and nothing else — no toolchain, no build, no cooperation from the
|
||||
// code being replaced.
|
||||
func (s Snapshot) Restore(dstDir string) error {
|
||||
func (s Snapshot) Restore(dstDir string) error { return s.RestoreOnly(dstDir, nil) }
|
||||
|
||||
// RestoreOnly is Restore limited to the named files. A nil list means all of
|
||||
// them. The caller uses it to put binaries back without putting config back:
|
||||
// see Updater.restoreBinaries.
|
||||
func (s Snapshot) RestoreOnly(dstDir string, names []string) error {
|
||||
if s.dir == "" {
|
||||
return errors.New("update: snapshot has no directory (load it through the store)")
|
||||
}
|
||||
var want map[string]bool
|
||||
if names != nil {
|
||||
want = make(map[string]bool, len(names))
|
||||
for _, n := range names {
|
||||
want[n] = true
|
||||
}
|
||||
}
|
||||
for _, f := range s.Files {
|
||||
if want != nil && !want[f.Name] {
|
||||
continue
|
||||
}
|
||||
src := filepath.Join(s.dir, f.Name)
|
||||
sum, err := hashFile(src)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user