fix: harden thothctl pi lifecycle
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -30,9 +31,19 @@ type Image struct {
|
||||
ID string `json:"id"`
|
||||
Reference string `json:"reference"`
|
||||
Volumes []string `json:"volumes"`
|
||||
Mounts []Mount `json:"mounts"`
|
||||
ConfigurationSHA string `json:"configuration_sha256,omitempty"`
|
||||
}
|
||||
|
||||
// Mount is the complete persistence identity relevant to safe core recreation.
|
||||
type Mount struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Source string `json:"source"`
|
||||
Destination string `json:"destination"`
|
||||
RW bool `json:"rw"`
|
||||
}
|
||||
|
||||
// Target records the immutable input selected by the operator. Source is either build or a
|
||||
// digest-pinned image reference; it intentionally never contains credentials.
|
||||
type Target struct {
|
||||
@@ -96,11 +107,38 @@ func writeState(path string, state State) error {
|
||||
temporary.Close()
|
||||
return errors.New("could not write update recovery state")
|
||||
}
|
||||
if err := temporary.Sync(); err != nil {
|
||||
temporary.Close()
|
||||
return errors.New("could not durably write update recovery state")
|
||||
}
|
||||
if err := temporary.Close(); err != nil {
|
||||
return errors.New("could not write update recovery state")
|
||||
}
|
||||
if err := os.Rename(temporaryName, path); err != nil {
|
||||
return errors.New("could not finalize update recovery state")
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
if directoryHandle, err := os.Open(directory); err == nil {
|
||||
_ = directoryHandle.Sync()
|
||||
_ = directoryHandle.Close()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateLock struct{ path string }
|
||||
|
||||
func acquireLock(statePath string) (*updateLock, error) {
|
||||
if err := os.MkdirAll(filepath.Dir(statePath), 0o700); err != nil {
|
||||
return nil, errors.New("could not create Pi update recovery directory")
|
||||
}
|
||||
path := statePath + ".lock"
|
||||
if err := os.Mkdir(path, 0o700); err != nil {
|
||||
if errors.Is(err, os.ErrExist) {
|
||||
return nil, errors.New("another Pi update or rollback is already in progress; recovery lock retained")
|
||||
}
|
||||
return nil, errors.New("could not acquire Pi update lock")
|
||||
}
|
||||
return &updateLock{path: path}, nil
|
||||
}
|
||||
func (l *updateLock) Release() { _ = os.Remove(l.path) }
|
||||
|
||||
Reference in New Issue
Block a user