-
Notifications
You must be signed in to change notification settings - Fork 18
/
state.go
122 lines (104 loc) · 3.35 KB
/
state.go
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
Copyright © 2022 - 2024 SUSE LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package register
import (
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/rancher/elemental-operator/pkg/log"
"github.com/twpayne/go-vfs"
"gopkg.in/yaml.v3"
)
type State struct {
InitialRegistration time.Time `yaml:"initialRegistration,omitempty"`
LastUpdate time.Time `yaml:"lastUpdate,omitempty"`
EmulatedTPM bool `yaml:"emulatedTPM,omitempty"`
EmulatedTPMSeed int64 `yaml:"emulatedTPMSeed,omitempty"`
}
func (s *State) IsUpdatable() bool {
return !s.InitialRegistration.IsZero()
}
func (s *State) HasLastUpdateElapsed(suppress time.Duration) bool {
return time.Now().After(s.LastUpdate.Add(suppress))
}
type StateHandler interface {
Init(location string) error
Load() (State, error)
Save(State) error
}
var errDecodingState = errors.New("decoding state")
var _ StateHandler = (*filesystemStateHandler)(nil)
func NewFileStateHandler(fs vfs.FS) StateHandler {
return &filesystemStateHandler{
fs: fs,
}
}
type filesystemStateHandler struct {
fs vfs.FS
stateFilePath string
}
func (h *filesystemStateHandler) Init(path string) error {
h.stateFilePath = path
// Check if directory exists
directory := filepath.Dir(path)
if _, err := h.fs.Stat(directory); os.IsNotExist(err) {
log.Debugf("Registration state dir '%s' does not exist. Creating now.", directory)
if err := vfs.MkdirAll(h.fs, directory, 0700); err != nil {
return fmt.Errorf("creating registration config directory: %w", err)
}
}
// Check if we can actually open the file
_, err := h.fs.Open(path)
if os.IsNotExist(err) {
return h.Save(State{}) // Create empty state if not exist
}
if err != nil {
return fmt.Errorf("opening registration state file '%s': %w", path, err)
}
return nil
}
func (h *filesystemStateHandler) Load() (State, error) {
stateFile := h.stateFilePath
file, err := h.fs.Open(stateFile)
if err != nil {
return State{}, fmt.Errorf("loading registration state file '%s': %w", stateFile, err)
}
dec := yaml.NewDecoder(file)
var state State
if err := dec.Decode(&state); err != nil {
return State{}, fmt.Errorf("%w from file '%s': %s", errDecodingState, stateFile, err)
}
if err := file.Close(); err != nil {
return State{}, fmt.Errorf("closing file '%s': %w", stateFile, err)
}
return state, nil
}
func (h *filesystemStateHandler) Save(state State) error {
file, err := h.fs.Create(h.stateFilePath)
if err != nil {
return fmt.Errorf("creating registration state file: %w", err)
}
enc := yaml.NewEncoder(file)
if err := enc.Encode(state); err != nil {
return fmt.Errorf("writing RegistrationState to file '%s': %w", h.stateFilePath, err)
}
if err := enc.Close(); err != nil {
return fmt.Errorf("closing encoder: %w", err)
}
if err := file.Close(); err != nil {
return fmt.Errorf("closing file '%s': %w", h.stateFilePath, err)
}
return nil
}