Skip to content

Commit 62ced5a

Browse files
committed
Adds fsGroup options to filesystem
Signed-off-by: joshvanl <[email protected]>
1 parent 04caec6 commit 62ced5a

File tree

2 files changed

+149
-15
lines changed

2 files changed

+149
-15
lines changed

storage/filesystem.go

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"io/ioutil"
2525
"os"
2626
"path/filepath"
27+
"strconv"
2728

2829
"github.com/go-logr/logr"
2930
apiequality "k8s.io/apimachinery/pkg/api/equality"
@@ -47,6 +48,18 @@ type Filesystem struct {
4748

4849
// used by the 'read only' methods
4950
fs fs.FS
51+
52+
// FixedFSGroup is an optional field which will set the gid ownership of all
53+
// volume's data directories to this value.
54+
// If this value is set, FSGroupVolumeAttributeKey has no effect.
55+
FixedFSGroup *int64
56+
57+
// FSGroupVolumeAttributeKey is an optional well-known key in the volume
58+
// attributes. If this attribute is present in the context when writing
59+
// files, gid ownership of the volume's data directory will be changed to
60+
// the value. Attribute value must be a valid int64 value.
61+
// If FixedFSGroup is defined, this field has no effect.
62+
FSGroupVolumeAttributeKey *string
5063
}
5164

5265
// Ensure the Filesystem implementation is fully featured
@@ -177,27 +190,32 @@ func (f *Filesystem) RegisterMetadata(meta metadata.Metadata) (bool, error) {
177190
}
178191

179192
// WriteFiles writes the given data to filesystem files within the volume's
180-
// data directory. Filesystem supports setting custom fsUser UID to these
181-
// files.
182-
func (f *Filesystem) WriteFiles(volumeID string, files map[string][]byte, fsUser *int64) error {
183-
// Data directory should be read, write and execute only to the fs user
184-
if err := os.MkdirAll(f.dataPathForVolumeID(volumeID), 0700); err != nil {
193+
// data directory. Filesystem supports changing ownership of the data directory
194+
// to a custom gid.
195+
func (f *Filesystem) WriteFiles(meta metadata.Metadata, files map[string][]byte) error {
196+
// Data directory should be read, write and execute only to the fs user; read and executable to group
197+
if err := os.MkdirAll(f.dataPathForVolumeID(meta.VolumeID), 0750); err != nil {
198+
return err
199+
}
200+
201+
fsGroup, err := f.fsGroupForMetadata(meta)
202+
if err != nil {
185203
return err
186204
}
187205

188-
// If a fsUser is defined, Chown the directory to that user.
189-
if fsUser != nil {
190-
if err := os.Chown(f.dataPathForVolumeID(volumeID), int(*fsUser), -1); err != nil {
191-
return fmt.Errorf("failed to chown data dir to uid %v: %w", *fsUser, err)
206+
// If a fsGroup is defined, Chown the directory to that group.
207+
if fsGroup != nil {
208+
if err := os.Chown(f.dataPathForVolumeID(meta.VolumeID), -1, int(*fsGroup)); err != nil {
209+
return fmt.Errorf("failed to chown data dir to gid %v: %w", *fsGroup, err)
192210
}
193211
}
194212

195-
writer, err := util.NewAtomicWriter(f.dataPathForVolumeID(volumeID), fmt.Sprintf("volumeID %v", volumeID))
213+
writer, err := util.NewAtomicWriter(f.dataPathForVolumeID(meta.VolumeID), fmt.Sprintf("volumeID %v", meta.VolumeID))
196214
if err != nil {
197215
return err
198216
}
199217

200-
payload := makePayload(files, fsUser)
218+
payload := makePayload(files, fsGroup)
201219
return writer.Write(payload)
202220
}
203221

@@ -234,14 +252,42 @@ func (f *Filesystem) tempfsPath() string {
234252
return filepath.Join(f.baseDir, "inmemfs")
235253
}
236254

237-
func makePayload(in map[string][]byte, fsUser *int64) map[string]util.FileProjection {
255+
func makePayload(in map[string][]byte, fsGroup *int64) map[string]util.FileProjection {
238256
out := make(map[string]util.FileProjection, len(in))
239257
for name, data := range in {
240258
out[name] = util.FileProjection{
241-
Data: data,
242-
FsUser: fsUser,
243-
Mode: readOnlyUserAndGroupFileMode,
259+
Data: data,
260+
FsGroup: fsGroup,
261+
Mode: readOnlyUserAndGroupFileMode,
244262
}
245263
}
246264
return out
247265
}
266+
267+
// fsGroupForMetadata returns the gid that ownership of the volume data
268+
// directory should be changed to. Returns nil if ownership should not be
269+
// changed.
270+
func (f *Filesystem) fsGroupForMetadata(meta metadata.Metadata) (*int64, error) {
271+
// FixedFSGroup takes precedence over attribute key.
272+
if f.FixedFSGroup != nil {
273+
return f.FixedFSGroup, nil
274+
}
275+
276+
// If the FSGroupVolumeAttributeKey is not defined, no ownership can change.
277+
if f.FSGroupVolumeAttributeKey == nil {
278+
return nil, nil
279+
}
280+
281+
fsGroupStr, ok := meta.VolumeContext[*f.FSGroupVolumeAttributeKey]
282+
if !ok {
283+
// If the attribute has not been set, return no ownership change.
284+
return nil, nil
285+
}
286+
287+
fsGroup, err := strconv.ParseInt(fsGroupStr, 10, 64)
288+
if err != nil {
289+
return nil, fmt.Errorf("failed to parse %q, value must be a valid integer: %w", *f.FSGroupVolumeAttributeKey, err)
290+
}
291+
292+
return &fsGroup, nil
293+
}

storage/filesystem_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,91 @@ func TestFilesystem_ListVolumes(t *testing.T) {
117117
t.Errorf("expected only entry to be 'fake-volume' but got: %s", vols[0])
118118
}
119119
}
120+
121+
func Test_fsGroupForMetadata(t *testing.T) {
122+
intPtr := func(i int64) *int64 {
123+
return &i
124+
}
125+
strPtr := func(s string) *string {
126+
return &s
127+
}
128+
129+
tests := map[string]struct {
130+
fixedFSGroup *int64
131+
fsGroupVolumeAttributeKey *string
132+
volumeContext map[string]string
133+
134+
expGID *int64
135+
expErr bool
136+
}{
137+
"FixedFSGroup=nil FSGroupVolumeAttributeKey=nil, should return nil gid": {
138+
fixedFSGroup: nil,
139+
fsGroupVolumeAttributeKey: nil,
140+
volumeContext: map[string]string{},
141+
expGID: nil,
142+
expErr: false,
143+
},
144+
"FixedFSGroup=10 FSGroupVolumeAttributeKey=nil, should return 10": {
145+
fixedFSGroup: intPtr(10),
146+
fsGroupVolumeAttributeKey: nil,
147+
volumeContext: map[string]string{},
148+
expGID: intPtr(10),
149+
expErr: false,
150+
},
151+
"FixedFSGroup=nil FSGroupVolumeAttributeKey=defined but not present in context, should return nil": {
152+
fixedFSGroup: nil,
153+
fsGroupVolumeAttributeKey: strPtr("fs-gid"),
154+
volumeContext: map[string]string{},
155+
expGID: nil,
156+
expErr: false,
157+
},
158+
"FixedFSGroup=nil FSGroupVolumeAttributeKey=defined and present in context, should return 20": {
159+
fixedFSGroup: nil,
160+
fsGroupVolumeAttributeKey: strPtr("fs-gid"),
161+
volumeContext: map[string]string{
162+
"fs-gid": "20",
163+
},
164+
expGID: intPtr(20),
165+
expErr: false,
166+
},
167+
"FixedFSGroup=nil FSGroupVolumeAttributeKey=defined and present in context but with bad value, should return error": {
168+
fixedFSGroup: nil,
169+
fsGroupVolumeAttributeKey: strPtr("fs-gid"),
170+
volumeContext: map[string]string{
171+
"fs-gid": "bad-value",
172+
},
173+
expGID: nil,
174+
expErr: true,
175+
},
176+
"FixedFSGroup=10 FSGroupVolumeAttributeKey=defined and present in context, should return superseding FixedFSGroup (10)": {
177+
fixedFSGroup: intPtr(10),
178+
fsGroupVolumeAttributeKey: strPtr("fs-gid"),
179+
volumeContext: map[string]string{
180+
"fs-gid": "20",
181+
},
182+
expGID: intPtr(10),
183+
expErr: false,
184+
},
185+
}
186+
187+
for name, test := range tests {
188+
t.Run(name, func(t *testing.T) {
189+
f := Filesystem{
190+
FixedFSGroup: test.fixedFSGroup,
191+
FSGroupVolumeAttributeKey: test.fsGroupVolumeAttributeKey,
192+
}
193+
194+
gid, err := f.fsGroupForMetadata(metadata.Metadata{
195+
VolumeContext: test.volumeContext,
196+
})
197+
198+
if (err != nil) != test.expErr {
199+
t.Errorf("unexpected error, exp=%t got=%v", test.expErr, err)
200+
}
201+
202+
if !reflect.DeepEqual(gid, test.expGID) {
203+
t.Errorf("unexpected gid, exp=%v got=%v", test.expGID, gid)
204+
}
205+
})
206+
}
207+
}

0 commit comments

Comments
 (0)