-
Notifications
You must be signed in to change notification settings - Fork 88
/
fs.go
205 lines (175 loc) · 5.55 KB
/
fs.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package repo
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/google/uuid"
"github.com/mitchellh/go-homedir"
"github.com/rs/zerolog/log"
"github.com/bacalhau-project/bacalhau/pkg/config"
"github.com/bacalhau-project/bacalhau/pkg/telemetry"
)
const (
repoPermission = 0755
defaultRunInfoFilename = "bacalhau.run"
runInfoFilePermissions = 0755
// UpdateCheckStatePath is the update check paths.
UpdateCheckStatePath = "update.json"
)
type FsRepo struct {
path string
}
func NewFS(path string) (*FsRepo, error) {
expandedPath, err := homedir.Expand(path)
if err != nil {
return nil, err
}
return &FsRepo{
path: expandedPath,
}, nil
}
func (fsr *FsRepo) Path() (string, error) {
if exists, err := fsr.Exists(); err != nil {
return "", err
} else if !exists {
return "", fmt.Errorf("repo is uninitialized")
}
return fsr.path, nil
}
func (fsr *FsRepo) Exists() (bool, error) {
// check if the path is present
if _, err := os.Stat(fsr.path); os.IsNotExist(err) {
return false, nil
} else if err != nil {
return false, err
}
// check if the repo version file is present
versionPath := filepath.Join(fsr.path, RepoVersionFile)
if _, err := os.Stat(versionPath); os.IsNotExist(err) {
return false, nil
} else if err != nil {
return false, err
}
version, err := fsr.readVersion()
if err != nil {
return false, err
}
if version != RepoVersion1 && version != RepoVersion2 {
return false, fmt.Errorf("unknown repo version %d", version)
}
return true, nil
}
func (fsr *FsRepo) Init() error {
if exists, err := fsr.Exists(); err != nil {
return err
} else if exists {
return fmt.Errorf("cannot init repo: repo already exists")
}
log.Info().Msgf("Initializing repo at '%s' for environment '%s'", fsr.path, config.GetConfigEnvironment())
// 0755: Owner can read, write, execute. Others can read and execute.
if err := os.MkdirAll(fsr.path, repoPermission); err != nil && !os.IsExist(err) {
return err
}
cfg, err := config.Init(fsr.path)
if err != nil {
return err
}
if err := initRepoFiles(cfg); err != nil {
return fmt.Errorf("failed to initialize repo: %w", err)
}
// TODO this should be a part of the config.
telemetry.SetupFromEnvs()
return fsr.writeVersion(RepoVersion2)
}
func (fsr *FsRepo) Open() error {
// if the repo does not exist we cannot open it.
if exists, err := fsr.Exists(); err != nil {
return err
} else if !exists {
return fmt.Errorf("repo does not exist")
}
if repoVersion, err := fsr.readVersion(); err != nil {
return fmt.Errorf("failed to read repo version: %w", err)
} else if repoVersion == RepoVersion1 {
if err := config.Migrate(fsr.path); err != nil {
return fmt.Errorf("failed to migrate config: %w", err)
}
if err := fsr.writeVersion(RepoVersion2); err != nil {
return fmt.Errorf("failed to update repo version: %w", err)
}
}
// load the configuration for the repo.
cfg, err := config.Load(fsr.path)
if err != nil {
return err
}
// ensure the loaded config has valid fields as they pertain to the filesystem
// e.g. user key and libp2p files exists, storage paths exist, etc.
if err := validateRepoConfig(cfg); err != nil {
return fmt.Errorf("failed to validate repo config: %w", err)
}
// derive an installationID from the client ID loaded from the repo.
if cfg.User.InstallationID == "" {
ID, _ := config.GetClientID()
uuidFromUserID := uuid.NewSHA1(uuid.New(), []byte(ID))
config.SetIntallationID(uuidFromUserID.String())
}
// TODO we should be initializing the file as a part of creating the repo, instead of sometime later.
if cfg.Update.CheckStatePath == "" {
cfg.Update.CheckStatePath = filepath.Join(fsr.path, UpdateCheckStatePath)
config.SetUpdateCheckStatePath(cfg.Update.CheckStatePath)
}
// TODO this should be a part of the config.
telemetry.SetupFromEnvs()
return nil
}
func (fsr *FsRepo) WriteRunInfo(ctx context.Context, summaryShellVariablesString string) (string, error) {
runInfoPath := filepath.Join(fsr.path, defaultRunInfoFilename)
// TODO kill this
devStackRunInfoPath := os.Getenv("DEVSTACK_ENV_FILE")
if devStackRunInfoPath != "" {
runInfoPath = devStackRunInfoPath
}
// Use os.Create to truncate the file if it already exists
f, err := os.Create(runInfoPath)
if err != nil {
return "", err
}
defer func() {
err = f.Close()
if err != nil {
log.Ctx(ctx).Err(err).Msgf("Failed to close run info file %s", runInfoPath)
}
}()
// Set permissions to constant for read read/write only by user
err = f.Chmod(runInfoFilePermissions)
if err != nil {
return "", err
}
_, err = f.Write([]byte(summaryShellVariablesString))
if err != nil {
return "", err
}
return runInfoPath, nil
// TODO previous behavior put it in these places, we may consider creating a symlink later
/*
if writeable, _ := filefs.IsWritable("/run"); writeable {
writePath = "/run" // Linux
} else if writeable, _ := filefs.IsWritable("/var/run"); writeable {
writePath = "/var/run" // Older Linux
} else if writeable, _ := filefs.IsWritable("/private/var/run"); writeable {
writePath = "/private/var/run" // MacOS
} else {
// otherwise write to the user's dir, which should be available on all systems
userDir, err := os.UserHomeDir()
if err != nil {
log.Ctx(ctx).Err(err).Msg("Could not write to /run, /var/run, or /private/var/run, and could not get user's home dir")
return nil
}
log.Warn().Msgf("Could not write to /run, /var/run, or /private/var/run, writing to %s dir instead. "+
"This file contains sensitive information, so please ensure it is limited in visibility.", userDir)
writePath = userDir
}
*/
}