1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package cloudprovider
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"strings"
)
type FileInstances struct {
Path string
}
func NewFileInstances(path string) *FileInstances {
return &FileInstances{Path: path}
}
func (f *FileInstances) Get(ctx context.Context, nodeName string) (Instance, bool, error) {
if err := ctx.Err(); err != nil {
return Instance{}, false, err
}
if f.Path == "" {
return Instance{}, false, errors.New(
"cloudprovider: the file-backed instance source has no path, so it can observe no " +
"instance and every Node would read as unknown")
}
raw, err := os.ReadFile(f.Path)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return Instance{}, false, fmt.Errorf(
"%w at %s. ABSENT is not EMPTY: the provider writes this file on every provision, "+
"teardown and reap and once at startup, and writes [] for a cluster with no guest, "+
"so a missing file is a state dir removed under a running controller. Reading it "+
"as \"no instance\" would delete every Node of the cluster, so no Node is judged "+
"until the snapshot exists", ErrNoSnapshot, f.Path)
}
return Instance{}, false, fmt.Errorf(
"cloudprovider: reading the instance snapshot at %s: %w. A read that failed is an "+
"UNREADABLE source and not an empty list: treating it as empty would answer "+
"\"the guest is gone\" for every Node of a running cluster", f.Path, err)
}
var all []Instance
if err := json.Unmarshal(raw, &all); err != nil {
return Instance{}, false, fmt.Errorf(
"cloudprovider: the instance snapshot at %s is not a JSON array of instance records: "+
"%w. It is refused rather than read as empty, because an unparseable snapshot and "+
"an absent instance are opposite facts", f.Path, err)
}
for i := range all {
inst := all[i]
if strings.TrimSpace(inst.NodeName) != nodeName {
continue
}
inst.Exists = true
return inst, true, nil
}
return Instance{}, false, nil
}