forked from project-stacker/stacker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
storage.go
161 lines (134 loc) · 4.38 KB
/
storage.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
package stacker
import (
"io/ioutil"
"os"
"path"
"github.com/pkg/errors"
"github.com/project-stacker/stacker/log"
"github.com/project-stacker/stacker/overlay"
"github.com/project-stacker/stacker/storage"
"github.com/project-stacker/stacker/types"
)
var storageTypeFile = "storage.type"
// openStorage just opens a storage type, without doing any pre-existing
// storage checks
func openStorage(c types.StackerConfig, storageType string) (types.Storage, error) {
switch storageType {
case "overlay":
err := overlay.Check(c)
if err != nil {
return nil, err
}
return overlay.NewOverlay(c)
default:
return nil, errors.Errorf("unknown storage type %s", storageType)
}
}
// tryToDetectStorageType tries to detect the storage type for a configuration
// in the absence of the storage type file. there's a special value of "" when
// the roots directory didn't exist, meaning that there wasn't an old storage
// configuration and it's fine to start fresh.
func tryToDetectStorageType(c types.StackerConfig) (string, error) {
// older versions of stacker left a few clues: if there's a
// .stacker/btrfs.loop file, it was probably btrfs. if any of the roots
// dirs have an overlay_metadata.json file in them, the backend was
// overlay. if not, then it's probably btrfs.
if _, err := os.Stat(path.Join(c.StackerDir, "btrfs.loop")); err == nil {
log.Debugf("autodetected previous storage type of btrfs")
return "btrfs", nil
}
ents, err := ioutil.ReadDir(c.RootFSDir)
if err != nil {
if !os.IsNotExist(err) {
return "", errors.Wrapf(err, "couldn't read roots dir")
}
log.Debugf("no previous storage type detected")
return "", nil
}
// nothing has been built (1 is for the lock file), probably a new
// stacker, so let's use whatever we want
if len(ents) <= 1 {
log.Debugf("no previous storage type detected")
return "", nil
}
for _, ent := range ents {
if _, err := os.Stat(path.Join(c.RootFSDir, ent.Name(), "overlay")); err == nil {
log.Debugf("detected some overlay layers, assuming previous storage type overlay")
return "overlay", nil
}
}
log.Debugf("no overlay layers detected, assuming previous storage type btrfs")
return "btrfs", nil
}
// errorOnStorageTypeSwitch returns an error if there was a previous stacker
// run with a different storage type.
func errorOnStorageTypeSwitch(c types.StackerConfig) error {
var storageType string
content, err := ioutil.ReadFile(path.Join(c.StackerDir, storageTypeFile))
if err != nil {
// older versions of stacker didn't write this file
if !os.IsNotExist(err) {
return errors.Wrapf(err, "couldn't read storage type")
}
storageType, err = tryToDetectStorageType(c)
if err != nil {
return err
}
// no previous storage is fine
if storageType == "" {
return nil
}
} else {
storageType = string(content)
}
if storageType != c.StorageType {
return errors.Errorf("previous storage type %s not compatible with requested storage %s", storageType, c.StorageType)
}
return nil
}
func NewStorage(c types.StackerConfig) (types.Storage, *StackerLocks, error) {
if err := os.MkdirAll(c.RootFSDir, 0755); err != nil {
return nil, nil, err
}
err := errorOnStorageTypeSwitch(c)
if err != nil {
return nil, nil, err
}
err = os.MkdirAll(c.StackerDir, 0755)
if err != nil {
return nil, nil, errors.Wrapf(err, "couldn't make stacker dir")
}
err = os.MkdirAll(c.RootFSDir, 0755)
if err != nil {
return nil, nil, errors.Wrapf(err, "couldn't make rootfs dir")
}
err = ioutil.WriteFile(path.Join(c.StackerDir, storageTypeFile), []byte(c.StorageType), 0644)
if err != nil {
return nil, nil, errors.Wrapf(err, "couldn't write storage type")
}
s, err := openStorage(c, c.StorageType)
if err != nil {
return nil, nil, err
}
// needed to attach the storage first, so we get the roots lock in the
// right place. storage attachment mostly isn't racy (the kernel will
// tell us EBUSY if we try to do the same btrfs loop mount twice, and
// there is no attachment for overlay), so that's safe.
locks, err := lock(c)
if err != nil {
return nil, nil, err
}
return s, locks, nil
}
func UnprivSetup(c types.StackerConfig, username string, uid, gid int) error {
err := storage.UidmapSetup(username, uid, gid)
if err != nil {
return err
}
switch c.StorageType {
case "overlay":
return overlay.UnprivSetup(c, uid, gid)
default:
return errors.Errorf("unknown storage type %s", c.StorageType)
}
}