@@ -29,47 +29,6 @@ type Config struct {
29
29
MountDir string
30
30
}
31
31
32
- func (m Manager ) getVolume (name string ) (vol Volume , err error ) {
33
- volumeDataFilePath := filepath .Join (m .dataDir , name )
34
-
35
- volumeDataFileInfo , err := os .Stat (volumeDataFilePath )
36
-
37
- if err != nil {
38
- if os .IsNotExist (err ) {
39
- err = errors .Errorf ("Volume '%s' does not exist" , name )
40
- }
41
- return
42
- }
43
-
44
- if ! volumeDataFileInfo .Mode ().IsRegular () {
45
- err = errors .Errorf (
46
- "Volume data path expected to point toa file but it appears to be something else: '%s'" ,
47
- volumeDataFilePath )
48
- return
49
- }
50
-
51
- details , ok := volumeDataFileInfo .Sys ().(* syscall.Stat_t )
52
- if ! ok {
53
- err = errors .Errorf (
54
- "An issue occurred while retrieving details about volume '%s' - cannot stat '%s'" ,
55
- name , volumeDataFilePath )
56
- }
57
-
58
- mountPointPath := filepath .Join (m .mountDir , name )
59
-
60
- vol = Volume {
61
- Name : name ,
62
- CurrentSizeInBytes : uint64 (details .Blocks * 512 ),
63
- MaxSizeInBytes : uint64 (details .Size ),
64
- StateDir : filepath .Join (m .stateDir , name ),
65
- DataFilePath : volumeDataFilePath ,
66
- MountPointPath : mountPointPath ,
67
- CreatedAt : volumeDataFileInfo .ModTime (),
68
- }
69
-
70
- return
71
- }
72
-
73
32
func New (cfg Config ) (manager Manager , err error ) {
74
33
// state dir
75
34
if cfg .StateDir == "" {
@@ -127,7 +86,8 @@ func (m Manager) List() ([]Volume, error) {
127
86
128
87
for _ , file := range files {
129
88
if file .Mode ().IsRegular () {
130
- vol , err := m .getVolume (file .Name ())
89
+ name := strings .TrimSuffix (file .Name (), filepath .Ext (file .Name ()))
90
+ vol , err := m .getVolume (name )
131
91
if err != nil {
132
92
return nil , err
133
93
}
@@ -151,7 +111,7 @@ func (m Manager) Get(name string) (vol Volume, err error) {
151
111
return
152
112
}
153
113
154
- func (m Manager ) Create (name string , sizeInBytes int64 , sparse bool , uid , gid int , mode uint32 ) error {
114
+ func (m Manager ) Create (name string , sizeInBytes int64 , sparse bool , fs string , uid , gid int , mode uint32 ) error {
155
115
err := validateName (name )
156
116
if err != nil {
157
117
return errors .Wrapf (err ,
@@ -165,15 +125,27 @@ func (m Manager) Create(name string, sizeInBytes int64, sparse bool, uid, gid in
165
125
name , sizeInBytes )
166
126
}
167
127
128
+ // We perform fs validation and construct mkfs flags array on the way
129
+ var mkfsFlags []string
130
+ if fs == "xfs" {
131
+ mkfsFlags = []string {}
132
+ } else if fs == "ext4" {
133
+ mkfsFlags = []string {"-F" }
134
+ } else {
135
+ return errors .Errorf (
136
+ "Error creating volume '%s' - only xfs and ext4 filesystems are supported, '%s' requested" ,
137
+ name , fs )
138
+ }
139
+
168
140
err = os .MkdirAll (m .dataDir , 0755 )
169
141
if err != nil {
170
142
return errors .Wrapf (err ,
171
- "Error creating volume '%s' - data dir does not exist : '%s'" ,
143
+ "Error creating volume '%s' - cannot create data dir : '%s'" ,
172
144
name , m .dataDir )
173
145
}
174
146
175
147
// create data file
176
- dataFilePath := filepath .Join (m .dataDir , name )
148
+ dataFilePath := filepath .Join (m .dataDir , name + "." + fs )
177
149
dataFileInfo , err := os .Create (dataFilePath )
178
150
if err != nil {
179
151
_ = os .Remove (dataFilePath ) // attempt to cleanup
@@ -207,7 +179,7 @@ func (m Manager) Create(name string, sizeInBytes int64, sparse bool, uid, gid in
207
179
}
208
180
209
181
// Here we assume that FS is unsupported and will fall back to 'dd' which is slow but should work everywhere
210
- of := fmt . Sprintf ( "of=%s" , dataFilePath )
182
+ of := "of=" + dataFilePath
211
183
bs := int64 (1000000 )
212
184
count := sizeInBytes / bs // we lose some precision here but it's likely to be negligible
213
185
errBytes , err = exec .Command (
@@ -226,12 +198,12 @@ func (m Manager) Create(name string, sizeInBytes int64, sparse bool, uid, gid in
226
198
}
227
199
228
200
// format data file
229
- _ , err = exec .Command ("mkfs.ext4 " , "-F" , dataFilePath ).Output ()
201
+ _ , err = exec .Command (fmt . Sprintf ( "mkfs.%s " , fs ), append ( mkfsFlags , dataFilePath ) ... ).Output ()
230
202
if err != nil {
231
203
_ = os .Remove (dataFilePath ) // attempt to cleanup
232
204
return errors .Wrapf (err ,
233
- "Error creating volume '%s' - cannot format datafile as ext4 filesystem" ,
234
- name , sizeInBytes )
205
+ "Error creating volume '%s' - cannot format datafile as %s filesystem" ,
206
+ name , fs )
235
207
}
236
208
237
209
// At this point we're done - last step is to adjust ownership if required.
@@ -243,7 +215,7 @@ func (m Manager) Create(name string, sizeInBytes int64, sparse bool, uid, gid in
243
215
_ = os .Remove (dataFilePath ) // attempt to cleanup
244
216
return errors .Wrapf (err ,
245
217
"Error creating volume '%s' - cannot mount volume to adjust its root owner/permissions" ,
246
- name , sizeInBytes )
218
+ name )
247
219
}
248
220
249
221
if mode > 0 {
@@ -253,7 +225,7 @@ func (m Manager) Create(name string, sizeInBytes int64, sparse bool, uid, gid in
253
225
_ = os .Remove (dataFilePath ) // attempt to cleanup
254
226
return errors .Wrapf (err ,
255
227
"Error creating volume '%s' - cannot adjust volume root permissions" ,
256
- name , sizeInBytes )
228
+ name )
257
229
}
258
230
}
259
231
err = os .Chown (mountPath , uid , gid )
@@ -262,15 +234,15 @@ func (m Manager) Create(name string, sizeInBytes int64, sparse bool, uid, gid in
262
234
_ = os .Remove (dataFilePath ) // attempt to cleanup
263
235
return errors .Wrapf (err ,
264
236
"Error creating volume '%s' - cannot adjust volume root owner" ,
265
- name , sizeInBytes )
237
+ name )
266
238
}
267
239
268
240
err = m .UnMount (name , lease )
269
241
if err != nil {
270
242
_ = os .Remove (dataFilePath ) // attempt to cleanup
271
243
return errors .Wrapf (err ,
272
244
"Error creating volume '%s' - cannot unmount volume after adjusting its root owner/permissions" ,
273
- name , sizeInBytes )
245
+ name )
274
246
}
275
247
}
276
248
@@ -450,3 +422,61 @@ func validateName(name string) error {
450
422
}
451
423
return nil
452
424
}
425
+
426
+ func (m Manager ) getVolume (name string ) (vol Volume , err error ) {
427
+ prefix := filepath .Join (m .dataDir , name ) + ".*"
428
+ matches , err := filepath .Glob (prefix )
429
+ if err != nil {
430
+ err = errors .Wrapf (err ,
431
+ "An issue occurred while retrieving details about volume '%s' - cannot glob data dir" , name )
432
+ return
433
+ }
434
+ if len (matches ) > 1 {
435
+ err = errors .Errorf ("More than 1 data file found for volume '%s'" , name )
436
+ return
437
+ } else if len (matches ) == 0 {
438
+ err = errors .Errorf ("Volume '%s' does not exist" , name )
439
+ return
440
+ }
441
+
442
+ volumeDataFilePath := matches [0 ]
443
+ fs := strings .TrimLeft (filepath .Ext (volumeDataFilePath ), "." )
444
+
445
+ volumeDataFileInfo , err := os .Stat (volumeDataFilePath )
446
+
447
+ if err != nil {
448
+ if os .IsNotExist (err ) { // this should not happen but...
449
+ err = errors .Errorf ("Volume '%s' disappeared just a moment ago" , name )
450
+ }
451
+ return
452
+ }
453
+
454
+ if ! volumeDataFileInfo .Mode ().IsRegular () {
455
+ err = errors .Errorf (
456
+ "Volume data path expected to point to a file but it appears to be something else: '%s'" ,
457
+ volumeDataFilePath )
458
+ return
459
+ }
460
+
461
+ details , ok := volumeDataFileInfo .Sys ().(* syscall.Stat_t )
462
+ if ! ok {
463
+ err = errors .Errorf (
464
+ "An issue occurred while retrieving details about volume '%s' - cannot stat '%s'" ,
465
+ name , volumeDataFilePath )
466
+ }
467
+
468
+ mountPointPath := filepath .Join (m .mountDir , name )
469
+
470
+ vol = Volume {
471
+ Name : name ,
472
+ Fs : fs ,
473
+ AllocatedSizeInBytes : uint64 (details .Blocks * 512 ),
474
+ MaxSizeInBytes : uint64 (details .Size ),
475
+ StateDir : filepath .Join (m .stateDir , name ),
476
+ DataFilePath : volumeDataFilePath ,
477
+ MountPointPath : mountPointPath ,
478
+ CreatedAt : volumeDataFileInfo .ModTime (),
479
+ }
480
+
481
+ return
482
+ }
0 commit comments