own-take-running has a person's switch, own_take_switch, kept in the vault's store (issue 1126, cause C4)
This commit is contained in:
@@ -218,7 +218,9 @@ The replaced value is kept sealed as the record's `previous` (dropped by any lat
|
||||
`secret-changed` and `own-replaced` are said, and the act is in `secret_handed` (`own-replaced`, `own-same`,
|
||||
`own-take-refused`). A covered bus account so replaced has its hash written again. `own_drift` lists, from every
|
||||
node's latest shadow answer (`<node>.node` in `node-engine.have`), each own secret whose node says another value,
|
||||
with what the vault holds and whether the node's ask would be taken now.
|
||||
with what the vault holds and whether the node's ask would be taken now. **The switch** is the vault's: a person
|
||||
switches every machine's asks off or on with `own_take_switch` (`on`, `why`), kept in the vault's store over a
|
||||
restart; it is on until switched off, and `own_drift` shows it.
|
||||
|
||||
## Events
|
||||
|
||||
|
||||
@@ -415,6 +415,18 @@ func TestANodeEngineHandsTheVaultWhatRunsOnItsOwnMachine(t *testing.T) {
|
||||
if _, err := take("node.anchor", pg, "a-value-older-than-the-vaults"); err == nil || !strings.Contains(err.Error(), "less than") {
|
||||
t.Errorf("a running value over one the vault just took: %v", err)
|
||||
}
|
||||
// Switched off by a person, every ask is refused, saying who and why; on again, taken again.
|
||||
later += time.Hour
|
||||
if _, err := v.SwitchOwnTake("jochen", false, "the test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := take("node.anchor", pg, "after-the-switch"); err == nil || !strings.Contains(err.Error(), "switched off (by jochen") {
|
||||
t.Errorf("an ask while switched off: %v", err)
|
||||
}
|
||||
if _, err := v.SwitchOwnTake("jochen", true, "the test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
later -= time.Hour
|
||||
// own_drift reads it from the node's latest shadow answer, mesh-wide.
|
||||
answer := delivery.CandidateAnswer{Head: "h", Verdict: delivery.CandidateDiffers, Differs: []delivery.ModuleDiffers{{
|
||||
Module: "postgres", Why: "the resource differs", Bodies: []delivery.ResourceBodies{{ID: "needs-superuser-password",
|
||||
|
||||
@@ -22,8 +22,11 @@ package main
|
||||
// (accounts.go), so the bus-accounts key is of the value the bus runs.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -125,10 +128,12 @@ func (v *Vault) OwnTakeOpen(caller string, of OwnTakeOf) (Opened, error) {
|
||||
if err != nil {
|
||||
return Opened{}, err
|
||||
}
|
||||
refused := ""
|
||||
if !held {
|
||||
refused := v.ownTakeOff()
|
||||
switch {
|
||||
case refused != "":
|
||||
case !held:
|
||||
refused = fmt.Sprintf("the vault holds no secret named %s, so there is nothing to replace; nothing is taken", secret)
|
||||
} else {
|
||||
default:
|
||||
refused = ownTakeRefusal(rec, v.Now())
|
||||
}
|
||||
if refused != "" {
|
||||
@@ -237,9 +242,10 @@ type DriftNode struct {
|
||||
|
||||
// Drift is own_drift's answer.
|
||||
type Drift struct {
|
||||
Secrets []DriftRow `json:"secrets"`
|
||||
Nodes []DriftNode `json:"nodes"`
|
||||
Note string `json:"note"`
|
||||
Switch OwnTakeSwitch `json:"switch"`
|
||||
Secrets []DriftRow `json:"secrets"`
|
||||
Nodes []DriftNode `json:"nodes"`
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
// OwnDrift reads every node's own have key (`<node>.node`) and lists, from its latest answers to the placement
|
||||
@@ -303,6 +309,10 @@ func (v *Vault) OwnDrift() (Drift, error) {
|
||||
names = append(names, n)
|
||||
}
|
||||
sort.Strings(names)
|
||||
if out.Switch, err = v.Store.OwnTakeSwitch(); err != nil {
|
||||
return Drift{}, err
|
||||
}
|
||||
off := v.ownTakeOff()
|
||||
for _, n := range names {
|
||||
r := rows[n]
|
||||
sort.Strings(r.Groups)
|
||||
@@ -318,9 +328,70 @@ func (v *Vault) OwnDrift() (Drift, error) {
|
||||
r.Previous = rec.Previous.Generation
|
||||
}
|
||||
r.Refused = ownTakeRefusal(rec, v.Now())
|
||||
if off != "" {
|
||||
r.Refused = off
|
||||
}
|
||||
r.Takeable = r.Refused == ""
|
||||
}
|
||||
out.Secrets = append(out.Secrets, *r)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ---- own_take_switch ----------------------------------------------------------------------------------------
|
||||
|
||||
// OwnTakeSwitch is whether own-take-running takes values, who switched it last, when and why. On until a person
|
||||
// switches it off; kept in the vault's own store, so it holds over a restart.
|
||||
type OwnTakeSwitch struct {
|
||||
On bool `json:"on"`
|
||||
By string `json:"by,omitempty"`
|
||||
At time.Time `json:"at,omitzero"`
|
||||
Why string `json:"why,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Store) ownTakeSwitchPath() string { return filepath.Join(s.dir, "own-take-running.json") }
|
||||
|
||||
// OwnTakeSwitch is the switch as kept: on when nothing was ever switched.
|
||||
func (s *Store) OwnTakeSwitch() (OwnTakeSwitch, error) {
|
||||
raw, err := os.ReadFile(s.ownTakeSwitchPath())
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return OwnTakeSwitch{On: true}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return OwnTakeSwitch{}, err
|
||||
}
|
||||
var sw OwnTakeSwitch
|
||||
if err := json.Unmarshal(raw, &sw); err != nil {
|
||||
return OwnTakeSwitch{}, fmt.Errorf("the switch of %s is not readable: %w", OwnTakeRunningVerb, err)
|
||||
}
|
||||
return sw, nil
|
||||
}
|
||||
|
||||
// SwitchOwnTake switches own-take-running on or off, a person's act with why; the caller is recorded as the bus
|
||||
// proved it.
|
||||
func (v *Vault) SwitchOwnTake(caller string, on bool, why string) (OwnTakeSwitch, error) {
|
||||
why = strings.TrimSpace(why)
|
||||
if why == "" || len(why) > 300 || strings.ContainsAny(why, "\r\n\x00") {
|
||||
return OwnTakeSwitch{}, errors.New("say why in one short line; nothing was switched")
|
||||
}
|
||||
sw := OwnTakeSwitch{On: on, By: someoneOr(caller, stdio.Unproven), At: v.Now().UTC(), Why: why}
|
||||
raw, _ := json.MarshalIndent(sw, "", " ")
|
||||
if err := writeWhole(v.Store.ownTakeSwitchPath(), append(raw, '\n')); err != nil {
|
||||
return OwnTakeSwitch{}, err
|
||||
}
|
||||
v.log("%s is switched %s by %s: %s", OwnTakeRunningVerb, map[bool]string{true: "on", false: "off"}[on], sw.By, why)
|
||||
return sw, nil
|
||||
}
|
||||
|
||||
// ownTakeOff says why own-take-running takes nothing now, or "".
|
||||
func (v *Vault) ownTakeOff() string {
|
||||
sw, err := v.Store.OwnTakeSwitch()
|
||||
if err != nil {
|
||||
return err.Error() + "; nothing is taken"
|
||||
}
|
||||
if !sw.On {
|
||||
return fmt.Sprintf("%s is switched off (by %s at %s: %s); nothing is taken", OwnTakeRunningVerb, sw.By,
|
||||
sw.At.Format(time.RFC3339), sw.Why)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -218,6 +218,24 @@ func definitions(env *Env) []toolDef {
|
||||
return v.OwnTakeOpen(caller, OwnTakeOf{Node: arg(a, "node"), Module: arg(a, "module"), Name: arg(a, "name"),
|
||||
Secret: arg(a, "secret"), Why: arg(a, "why")})
|
||||
}},
|
||||
{Name: "own_take_switch",
|
||||
Description: "Switch own-take-running on or off for every machine, a person's act with why (on until " +
|
||||
"switched off; kept over a restart). While off, every machine's ask is refused, saying who switched it " +
|
||||
"off and why. own_drift shows the switch.",
|
||||
Input: map[string]any{"type": "object", "required": []string{"on", "why"}, "properties": map[string]any{
|
||||
"on": map[string]any{"type": "boolean", "description": "true takes running values, false takes none"},
|
||||
"why": str("why, in one line")}},
|
||||
run: func(caller string, a map[string]any) (any, error) {
|
||||
v, err := env.ready()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
on, ok := a["on"].(bool)
|
||||
if !ok {
|
||||
return nil, errors.New("say on: true or false; nothing was switched")
|
||||
}
|
||||
return v.SwitchOwnTake(caller, on, arg(a, "why"))
|
||||
}},
|
||||
{Name: "own_drift",
|
||||
Description: "Every own secret whose node's latest shadow answer says the vault holds another value than runs " +
|
||||
"there (the masked word \"another value\", issue 1126), for all nodes in one call: the secret, the " +
|
||||
|
||||
@@ -165,7 +165,8 @@
|
||||
"provisioner_delete",
|
||||
"vault_status",
|
||||
"vault_health",
|
||||
"own_drift"
|
||||
"own_drift",
|
||||
"own_take_switch"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user