Skip to content

Commit c649418

Browse files
committed
pass machine-type and disable-autoconfig mountOptions from driver to gcsfuse to enable
intelligent defaults for high-performance machine types
1 parent ffd676e commit c649418

13 files changed

Lines changed: 240 additions & 13 deletions

File tree

cmd/csi_driver/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ var (
4848
fuseSocketDir = flag.String("fuse-socket-dir", "/sockets", "FUSE socket directory")
4949
metricsEndpoint = flag.String("metrics-endpoint", "", "The TCP network address where the Prometheus metrics endpoint will listen (example: `:8080`). The default is empty string, which means that the metrics endpoint is disabled.")
5050
maximumNumberOfCollectors = flag.Int("max-metric-collectors", -1, "Maximum number of prometheus metric collectors exporting metrics at a time, less than 0 (e.g -1) means no limit.")
51-
51+
disableAutoconfig = flag.Bool("disable-autoconfig", false, "Disable gcsfuse's defaulting based on machine type")
5252
// These are set at compile time.
5353
version = "unknown"
5454
)
@@ -126,6 +126,7 @@ func main() {
126126
Mounter: mounter,
127127
K8sClients: clientset,
128128
MetricsManager: mm,
129+
DisableAutoconfig: *disableAutoconfig,
129130
}
130131

131132
gcfsDriver, err := driver.NewGCSDriver(config)

cmd/sidecar_mounter/main.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"syscall"
2929
"time"
3030

31+
driver "github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/csi_driver"
3132
sidecarmounter "github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/sidecar_mounter"
3233
"github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/webhook"
3334
"k8s.io/klog/v2"
@@ -55,12 +56,24 @@ func main() {
5556
mounter := sidecarmounter.New(*gcsfusePath)
5657
ctx, cancel := context.WithCancel(context.Background())
5758

59+
flagsFromDriver := map[string]string{}
60+
defaultingFlagFilePath := *volumeBasePath + "/" + driver.FlagFileForDefaultingPath
61+
klog.Infof("Checking if defaulting-flag file %q exists", defaultingFlagFilePath)
62+
if _, err := os.Stat(defaultingFlagFilePath); err == nil {
63+
machineTypeBytes, err := os.ReadFile(defaultingFlagFilePath)
64+
if err != nil {
65+
klog.Fatalf("failed to read defaulting-flag file: %v", err)
66+
}
67+
fileContent := string(machineTypeBytes)
68+
flagsFromDriver = driver.ParseFlagMapFromFlagFile(fileContent)
69+
}
70+
5871
for _, sp := range socketPaths {
5972
// sleep 1.5 seconds before launch the next gcsfuse to avoid
6073
// 1. different gcsfuse logs mixed together.
6174
// 2. memory usage peak.
6275
time.Sleep(1500 * time.Millisecond)
63-
mc := sidecarmounter.NewMountConfig(sp)
76+
mc := sidecarmounter.NewMountConfig(sp, flagsFromDriver)
6477
if mc != nil {
6578
if err := mounter.Mount(ctx, mc); err != nil {
6679
mc.ErrWriter.WriteMsg(fmt.Sprintf("failed to mount bucket %q for volume %q: %v\n", mc.BucketName, mc.VolumeName, err))

pkg/cloud_provider/clientset/clientset.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type Clientset struct {
5959
}
6060

6161
const GkeMetaDataServerKey = "iam.gke.io/gke-metadata-server-enabled"
62+
const MachineTypeKey = "node.kubernetes.io/instance-type"
6263

6364
func (c *Clientset) ConfigureNodeLister(nodeName string) {
6465
trim := func(obj interface{}) (interface{}, error) {
@@ -81,6 +82,10 @@ func (c *Clientset) ConfigureNodeLister(nodeName string) {
8182
if ok {
8283
newLabels[GkeMetaDataServerKey] = isGkeMetaDataServerEnabled
8384
}
85+
machineType, ok := nodeObj.ObjectMeta.Labels[MachineTypeKey]
86+
if ok {
87+
newLabels[MachineTypeKey] = machineType
88+
}
8489

8590
nodeObj.Spec = corev1.NodeSpec{}
8691
nodeObj.Status = corev1.NodeStatus{}

pkg/cloud_provider/clientset/fake.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@ package clientset
1919

2020
import (
2121
"context"
22+
"strconv"
2223

2324
"github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/webhook"
2425
authenticationv1 "k8s.io/api/authentication/v1"
2526
corev1 "k8s.io/api/core/v1"
2627
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2728
)
2829

30+
type FakeNodeConfig struct {
31+
IsWorkloadIdentityEnabled bool
32+
MachineType string
33+
}
34+
2935
type FakeClientset struct {
3036
fakePod *corev1.Pod
3137
fakeNode *corev1.Node
@@ -35,7 +41,7 @@ func NewFakeClientset() *FakeClientset {
3541
fakeClientSet := &FakeClientset{}
3642
// Default setting for most unit tests is pod doesn't use host network & workload identity is enabled on the node
3743
fakeClientSet.CreatePod( /*hostNetworkEnabled */ false)
38-
fakeClientSet.CreateNode( /* isWorkloadIdentityEnabledOnNode */ true)
44+
fakeClientSet.CreateNode(FakeNodeConfig{IsWorkloadIdentityEnabled: true})
3945

4046
return fakeClientSet
4147
}
@@ -74,16 +80,18 @@ func (c *FakeClientset) CreatePod(hostNetworkEnabled bool) {
7480
}
7581
}
7682

77-
func (c *FakeClientset) CreateNode(isWorkloadIdentityEnabled bool) {
83+
func (c *FakeClientset) CreateNode(nodeConfig FakeNodeConfig) {
7884
c.fakeNode = &corev1.Node{
7985
ObjectMeta: metav1.ObjectMeta{
8086
Name: "",
8187
Labels: map[string]string{},
8288
},
8389
}
8490

85-
if isWorkloadIdentityEnabled {
86-
c.fakeNode.Labels[GkeMetaDataServerKey] = "true"
91+
c.fakeNode.Labels[GkeMetaDataServerKey] = strconv.FormatBool(nodeConfig.IsWorkloadIdentityEnabled)
92+
c.fakeNode.Labels[MachineTypeKey] = nodeConfig.MachineType
93+
if c.fakeNode.Labels[MachineTypeKey] == "" {
94+
c.fakeNode.Labels[MachineTypeKey] = "e2-medium"
8795
}
8896
}
8997

pkg/csi_driver/gcs_fuse_driver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type GCSDriverConfig struct {
4545
Mounter mount.Interface
4646
K8sClients clientset.Interface
4747
MetricsManager metrics.Manager
48+
DisableAutoconfig bool
4849
}
4950

5051
type GCSDriver struct {

pkg/csi_driver/node.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package driver
2020
import (
2121
"fmt"
2222
"os"
23+
"strconv"
2324
"strings"
2425
"time"
2526

@@ -182,6 +183,20 @@ func (s *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublish
182183
}
183184
}
184185

186+
// Only pass mountOptions flags for defaulting if sidecar container is managed and satisifies min version requirement
187+
if s.shouldPassDefaultingFlags(pod) {
188+
shouldDisableAutoConfig := s.driver.config.DisableAutoconfig
189+
machineType, ok := node.Labels[clientset.MachineTypeKey]
190+
if ok {
191+
flagMap := map[string]string{"machine-type": machineType, "disable-autoconfig": strconv.FormatBool(shouldDisableAutoConfig)}
192+
if err := PutFlagsFromDriverToTargetPath(flagMap, targetPath, FlagFileForDefaultingPath); err != nil {
193+
return nil, status.Error(codes.Internal, err.Error())
194+
}
195+
} else {
196+
klog.Warningf("Unable to fetch target node %v's machine type", node.Name)
197+
}
198+
}
199+
185200
// Check if there is any error from the gcsfuse
186201
code, err := checkGcsFuseErr(isInitContainer, pod, targetPath)
187202
if code != codes.OK {
@@ -330,3 +345,16 @@ func (s *nodeServer) shouldStartTokenServer(pod *corev1.Pod) bool {
330345

331346
return tokenVolumeInjected && sidecarVersionSupported
332347
}
348+
349+
func (s *nodeServer) shouldPassDefaultingFlags(pod *corev1.Pod) bool {
350+
var sidecarVersionSupported bool
351+
for _, container := range pod.Spec.InitContainers {
352+
if container.Name == webhook.GcsFuseSidecarName {
353+
sidecarVersionSupported = isSidecarVersionSupportedForGivenFeature(container.Image, AutoconfigDefaultingSidecarMinVersion)
354+
355+
break
356+
}
357+
}
358+
359+
return sidecarVersionSupported
360+
}

pkg/csi_driver/node_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func TestNodePublishVolumeWIDisabledOnNode(t *testing.T) {
247247
}
248248
for _, test := range cases {
249249
fakeClientSet := &clientset.FakeClientset{}
250-
fakeClientSet.CreateNode( /* workloadIdentityEnabled */ test.workloadIdentityEnabledOnNode)
250+
fakeClientSet.CreateNode( /* workloadIdentityEnabled */ clientset.FakeNodeConfig{IsWorkloadIdentityEnabled: test.workloadIdentityEnabledOnNode})
251251
fakeClientSet.CreatePod( /* hostNetworkEnabled */ test.hostNetworkEnabledOnPod)
252252
testEnv := initTestNodeServerWithCustomClientset(t, fakeClientSet)
253253

pkg/csi_driver/utils.go

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ const (
6666
VolumeContextKeyEphemeral = "csi.storage.k8s.io/ephemeral"
6767
VolumeContextKeyBucketName = "bucketName"
6868
tokenServerSidecarMinVersion = "v1.12.2-gke.0" // #nosec G101
69+
// TODO: Update with actual minimum sidecar version after the first feature release
70+
AutoconfigDefaultingSidecarMinVersion = "v1.99.0-gke.0"
71+
FlagFileForDefaultingPath = "flags-for-defaulting"
6972
)
7073

7174
var volumeIDRegEx = regexp.MustCompile(`:.*$`)
@@ -473,22 +476,73 @@ func getSidecarContainerStatus(isInitContainer bool, pod *corev1.Pod) (*corev1.C
473476
}
474477

475478
func isSidecarVersionSupportedForTokenServer(imageName string) bool {
479+
return isSidecarVersionSupportedForGivenFeature(imageName, tokenServerSidecarMinVersion)
480+
}
481+
482+
func isSidecarVersionSupportedForGivenFeature(imageName string, sidecarMinSupportedVersion string) bool {
476483
managedSidecarPattern := `.*/gke-release(-staging)?/gcs-fuse-csi-driver-sidecar-mounter:v\d+.\d+.\d+-gke\.\d+.*`
477484
re := regexp.MustCompile(managedSidecarPattern)
478485
isManagedSidecar := re.MatchString(imageName)
479486

480487
if !isManagedSidecar {
481488
klog.Infof("mountOptions should not be passed because this is a private sidecar image %q", imageName)
482-
483489
return false
484490
}
485491
imageVersion := strings.Split(strings.Split(imageName, ":")[1], "@")[0]
486492
klog.Infof("sidecar image version: %v", imageVersion)
487-
if semver.Compare(imageVersion, tokenServerSidecarMinVersion) >= 0 {
493+
if semver.Compare(imageVersion, sidecarMinSupportedVersion) >= 0 {
488494
klog.Infof("sidecar version is supported for token server")
489-
490495
return true
491496
}
492497

493498
return false
494499
}
500+
501+
func PutFlagsFromDriverToTargetPath(flagMap map[string]string, targetPath string, fileName string) error {
502+
emptyDirBasePath, err := util.PrepareEmptyDir(targetPath, true)
503+
if err != nil {
504+
return fmt.Errorf("failed to get emptyDir path: %w", err)
505+
}
506+
507+
absolutePath := filepath.Dir(emptyDirBasePath) + "/" + fileName
508+
klog.V(4).Infof("Writing flags needed for gcsfuse defaulting logic to file %q: %v", absolutePath, flagMap)
509+
510+
f, err := os.Create(absolutePath)
511+
if err != nil {
512+
return fmt.Errorf("failed to create defaulting-flag file: %w", err)
513+
}
514+
content := prepareFileContentFromFlagMap(flagMap)
515+
if _, err := f.WriteString(content); err != nil {
516+
return fmt.Errorf("failed to write defaulting-flag file: %w", err)
517+
}
518+
519+
f.Close()
520+
521+
return nil
522+
}
523+
524+
func prepareFileContentFromFlagMap(flagMap map[string]string) string {
525+
var sb strings.Builder
526+
for key, value := range flagMap {
527+
sb.WriteString(key)
528+
sb.WriteString(":")
529+
sb.WriteString(value)
530+
sb.WriteString("\n")
531+
}
532+
return sb.String()
533+
}
534+
535+
func ParseFlagMapFromFlagFile(flagFileContent string) map[string]string {
536+
configFlags := make(map[string]string)
537+
lines := strings.Split(flagFileContent, "\n")
538+
for _, line := range lines {
539+
if line == "" { // Skip empty lines
540+
continue
541+
}
542+
parts := strings.Split(line, ":")
543+
key := parts[0]
544+
value := parts[1]
545+
configFlags[key] = value
546+
}
547+
return configFlags
548+
}

pkg/csi_driver/utils_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,47 @@ func TestIsSidecarVersionSupportedForTokenServer(t *testing.T) {
156156
})
157157
}
158158

159+
func TestIsSidecarVersionSupportedForDefaultingFlags(t *testing.T) {
160+
t.Parallel()
161+
t.Run("checking if sidecar version is supported for token server", func(t *testing.T) {
162+
t.Parallel()
163+
testCases := []struct {
164+
name string
165+
imageName string
166+
expectedSupported bool
167+
}{
168+
{
169+
name: "should return true for supported sidecar version",
170+
imageName: "us-central1-artifactregistry.gcr.io/gke-release/gke-release/gcs-fuse-csi-driver-sidecar-mounter:v1.99.0-gke.2@sha256:abcd",
171+
expectedSupported: true,
172+
},
173+
{
174+
name: "should return true for supported sidecar version in staging gcr",
175+
imageName: "gcr.io/gke-release-staging/gcs-fuse-csi-driver-sidecar-mounter:v1.99.0-gke.0@sha256:abcd",
176+
expectedSupported: true,
177+
},
178+
{
179+
name: "should return false for unsupported sidecar version",
180+
imageName: "us-central1-artifactregistry.gcr.io/gke-release/gke-release/gcs-fuse-csi-driver-sidecar-mounter:v1.14.0-gke.1@sha256:abcd",
181+
expectedSupported: false,
182+
},
183+
{
184+
name: "should return false for private sidecar",
185+
imageName: "customer.gcr.io/dir/gcs-fuse-csi-driver-sidecar-mounter:v1.12.2-gke.0@sha256:abcd",
186+
expectedSupported: false,
187+
},
188+
}
189+
190+
for _, tc := range testCases {
191+
t.Logf("test case: %s", tc.name)
192+
actual := isSidecarVersionSupportedForGivenFeature(tc.imageName, AutoconfigDefaultingSidecarMinVersion)
193+
if actual != tc.expectedSupported {
194+
t.Errorf("Got supported %v, but expected %v", actual, tc.expectedSupported)
195+
}
196+
}
197+
})
198+
}
199+
159200
func TestParseVolumeAttributes(t *testing.T) {
160201
t.Parallel()
161202
t.Run("parsing volume attributes into mount options", func(t *testing.T) {

pkg/sidecar_mounter/sidecar_mounter_config.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,15 @@ var boolFlags = map[string]bool{
8888
"debug_http": true,
8989
"debug_invariants": true,
9090
"debug_mutex": true,
91+
"disable-autoconfig": true,
9192
}
9293

9394
// Fetch the following information from a given socket path:
9495
// 1. Pod volume name
9596
// 2. The file descriptor
9697
// 3. GCS bucket name
9798
// 4. Mount options passing to gcsfuse (passed by the csi mounter).
98-
func NewMountConfig(sp string) *MountConfig {
99+
func NewMountConfig(sp string, flagMapFromDriver map[string]string) *MountConfig {
99100
// socket path pattern: /gcsfuse-tmp/.volumes/<volume-name>/socket
100101
tempDir := filepath.Dir(sp)
101102
volumeName := filepath.Base(tempDir)
@@ -143,6 +144,7 @@ func NewMountConfig(sp string) *MountConfig {
143144
}
144145

145146
mc.prepareMountArgs()
147+
mergeFlags(mc.ConfigFileFlagMap, flagMapFromDriver)
146148
if err := mc.prepareConfigFile(); err != nil {
147149
mc.ErrWriter.WriteMsg(fmt.Sprintf("failed to create config file %q: %v", mc.ConfigFile, err))
148150

@@ -152,6 +154,16 @@ func NewMountConfig(sp string) *MountConfig {
152154
return &mc
153155
}
154156

157+
func mergeFlags(mountConfigFlagMap map[string]string, driverFlagMap map[string]string) {
158+
for key, value := range driverFlagMap {
159+
_, ok := mountConfigFlagMap[key]
160+
// Only overwrite values not set in mountConfigMap
161+
if !ok {
162+
mountConfigFlagMap[key] = value
163+
}
164+
}
165+
}
166+
155167
func (mc *MountConfig) prepareMountArgs() {
156168
flagMap := map[string]string{
157169
"app-name": GCSFuseAppName,

0 commit comments

Comments
 (0)