Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add annotation for setting access mode on automounted configmap/secret files #6750

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/configAutomount/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type AutomountInfo struct {
ReadOnly bool
// Keys defines the list of keys to mount when MountAs is Subpath
Keys []string
// MountAccessMode indicates the access mode for configmap and secret mounted as files
MountAccessMode *int32
}

type Client interface {
Expand Down
65 changes: 50 additions & 15 deletions pkg/configAutomount/kubernetes.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package configAutomount

import (
"fmt"
"path/filepath"
"sort"
"strconv"

"github.com/redhat-developer/odo/pkg/kclient"
)
Expand All @@ -11,9 +13,10 @@ const (
labelMountName = "devfile.io/auto-mount"
labelMountValue = "true"

annotationMountPathName = "devfile.io/mount-path"
annotationMountAsName = "devfile.io/mount-as"
annotationReadOnlyName = "devfile.io/read-only"
annotationMountPathName = "devfile.io/mount-path"
annotationMountAsName = "devfile.io/mount-as"
annotationReadOnlyName = "devfile.io/read-only"
annotationMountAccessMode = "devfile.io/mount-access-mode"
)

type KubernetesClient struct {
Expand Down Expand Up @@ -96,13 +99,20 @@ func (o KubernetesClient) getAutomountingSecrets() ([]AutomountInfo, error) {
}
sort.Strings(keys)
}

mountAccessMode, err := getMountAccessModeFromAnnotation(secret.Annotations)
if err != nil {
return nil, err
}

result = append(result, AutomountInfo{
VolumeType: VolumeTypeSecret,
VolumeName: secret.Name,
MountPath: mountPath,
MountAs: mountAs,
ReadOnly: secret.Annotations[annotationReadOnlyName] == "true",
Keys: keys,
VolumeType: VolumeTypeSecret,
VolumeName: secret.Name,
MountPath: mountPath,
MountAs: mountAs,
ReadOnly: secret.Annotations[annotationReadOnlyName] == "true",
Keys: keys,
MountAccessMode: mountAccessMode,
})
}
return result, nil
Expand Down Expand Up @@ -131,13 +141,20 @@ func (o KubernetesClient) getAutomountingConfigmaps() ([]AutomountInfo, error) {
}
sort.Strings(keys)
}

mountAccessMode, err := getMountAccessModeFromAnnotation(cm.Annotations)
if err != nil {
return nil, err
}

result = append(result, AutomountInfo{
VolumeType: VolumeTypeConfigmap,
VolumeName: cm.Name,
MountPath: mountPath,
MountAs: mountAs,
ReadOnly: cm.Annotations[annotationReadOnlyName] == "true",
Keys: keys,
VolumeType: VolumeTypeConfigmap,
VolumeName: cm.Name,
MountPath: mountPath,
MountAs: mountAs,
ReadOnly: cm.Annotations[annotationReadOnlyName] == "true",
Keys: keys,
MountAccessMode: mountAccessMode,
})
}
return result, nil
Expand All @@ -158,3 +175,21 @@ func getMountAsFromAnnotation(annotations map[string]string) MountAs {
return MountAsFile
}
}

func getMountAccessModeFromAnnotation(annotations map[string]string) (*int32, error) {
accessModeStr, found := annotations[annotationMountAccessMode]
if !found {
return nil, nil
}
accessMode64, err := strconv.ParseInt(accessModeStr, 0, 32)
if err != nil {
return nil, err
}

if accessMode64 < 0 || accessMode64 > 0777 {
return nil, fmt.Errorf("invalid access mode annotation: value '%s' parsed to %o (octal). Must be in range 0000-0777", accessModeStr, accessMode64)
}

accessMode32 := int32(accessMode64)
return &accessMode32, nil
}
94 changes: 94 additions & 0 deletions pkg/configAutomount/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/kclient"
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/pointer"
)

func TestKubernetesClient_GetAutomountingVolumes(t *testing.T) {
Expand Down Expand Up @@ -93,6 +94,24 @@ func TestKubernetesClient_GetAutomountingVolumes(t *testing.T) {
annotationReadOnlyName: "true",
})

secretMountAccessMode := corev1.Secret{}
secretMountAccessMode.SetName("secretMountAccessMode")
secretMountAccessMode.SetLabels(map[string]string{
labelMountName: labelMountValue,
})
secretMountAccessMode.SetAnnotations(map[string]string{
annotationMountAccessMode: "0400",
})

secretMountAccessModeInvalid := corev1.Secret{}
secretMountAccessModeInvalid.SetName("secretMountAccessModeInvalid")
secretMountAccessModeInvalid.SetLabels(map[string]string{
labelMountName: labelMountValue,
})
secretMountAccessModeInvalid.SetAnnotations(map[string]string{
annotationMountAccessMode: "01444",
})

defaultCM1 := corev1.ConfigMap{}
defaultCM1.SetName("defaultCM1")
defaultCM1.SetLabels(map[string]string{
Expand Down Expand Up @@ -145,6 +164,24 @@ func TestKubernetesClient_GetAutomountingVolumes(t *testing.T) {
annotationReadOnlyName: "true",
})

cmMountAccessMode := corev1.ConfigMap{}
cmMountAccessMode.SetName("cmMountAccessMode")
cmMountAccessMode.SetLabels(map[string]string{
labelMountName: labelMountValue,
})
cmMountAccessMode.SetAnnotations(map[string]string{
annotationMountAccessMode: "0444",
})

cmMountAccessModeInvalid := corev1.ConfigMap{}
cmMountAccessModeInvalid.SetName("cmMountAccessModeInvalid")
cmMountAccessModeInvalid.SetLabels(map[string]string{
labelMountName: labelMountValue,
})
cmMountAccessModeInvalid.SetAnnotations(map[string]string{
annotationMountAccessMode: "01444",
})

type fields struct {
kubeClient func(ctrl *gomock.Controller) kclient.ClientInterface
}
Expand Down Expand Up @@ -330,6 +367,63 @@ func TestKubernetesClient_GetAutomountingVolumes(t *testing.T) {
},
wantErr: false,
},
{
name: "Secret and ConfigMap with mount-access-mode annotations",
fields: fields{
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
client := kclient.NewMockClientInterface(ctrl)
client.EXPECT().ListPVCs(gomock.Any()).Return([]corev1.PersistentVolumeClaim{}, nil).AnyTimes()
client.EXPECT().ListSecrets(gomock.Any()).Return([]corev1.Secret{secretMountAccessMode}, nil).AnyTimes()
client.EXPECT().ListConfigMaps(gomock.Any()).Return([]corev1.ConfigMap{cmMountAccessMode}, nil).AnyTimes()
return client
},
},
want: []AutomountInfo{
{
VolumeType: VolumeTypeSecret,
VolumeName: "secretMountAccessMode",
MountPath: "/etc/secret/secretMountAccessMode",
MountAs: MountAsFile,
MountAccessMode: pointer.Int32(0400),
},
{
VolumeType: VolumeTypeConfigmap,
VolumeName: "cmMountAccessMode",
MountPath: "/etc/config/cmMountAccessMode",
MountAs: MountAsFile,
MountAccessMode: pointer.Int32(0444),
},
},
wantErr: false,
},
{
name: "Secret with invalid mount-access-mode annotation",
fields: fields{
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
client := kclient.NewMockClientInterface(ctrl)
client.EXPECT().ListPVCs(gomock.Any()).Return([]corev1.PersistentVolumeClaim{}, nil).AnyTimes()
client.EXPECT().ListSecrets(gomock.Any()).Return([]corev1.Secret{secretMountAccessModeInvalid}, nil).AnyTimes()
client.EXPECT().ListConfigMaps(gomock.Any()).Return([]corev1.ConfigMap{}, nil).AnyTimes()
return client
},
},
want: nil,
wantErr: true,
},
{
name: "Configmap with invalid mount-access-mode annotation",
fields: fields{
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
client := kclient.NewMockClientInterface(ctrl)
client.EXPECT().ListPVCs(gomock.Any()).Return([]corev1.PersistentVolumeClaim{}, nil).AnyTimes()
client.EXPECT().ListSecrets(gomock.Any()).Return([]corev1.Secret{}, nil).AnyTimes()
client.EXPECT().ListConfigMaps(gomock.Any()).Return([]corev1.ConfigMap{cmMountAccessModeInvalid}, nil).AnyTimes()
return client
},
},
want: nil,
wantErr: true,
},
{
name: "PVC, Secret and ConfigMap read-only",
fields: fields{
Expand Down
8 changes: 6 additions & 2 deletions pkg/devfile/adapters/kubernetes/storage/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ func mountSecretAsFile(volumeInfo configAutomount.AutomountInfo, containers, ini
Name: volumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: volumeInfo.VolumeName,
SecretName: volumeInfo.VolumeName,
DefaultMode: volumeInfo.MountAccessMode,
},
},
})
Expand Down Expand Up @@ -352,7 +353,8 @@ func mountSecretAsSubpath(volumeInfo configAutomount.AutomountInfo, containers,
Name: volumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: volumeInfo.VolumeName,
SecretName: volumeInfo.VolumeName,
DefaultMode: volumeInfo.MountAccessMode,
},
},
})
Expand Down Expand Up @@ -386,6 +388,7 @@ func mountConfigMapAsFile(volumeInfo configAutomount.AutomountInfo, containers,
Name: volumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
DefaultMode: volumeInfo.MountAccessMode,
LocalObjectReference: corev1.LocalObjectReference{
Name: volumeInfo.VolumeName,
},
Expand Down Expand Up @@ -429,6 +432,7 @@ func mountConfigMapAsSubpath(volumeInfo configAutomount.AutomountInfo, container
LocalObjectReference: corev1.LocalObjectReference{
Name: volumeInfo.VolumeName,
},
DefaultMode: volumeInfo.MountAccessMode,
},
},
})
Expand Down
Loading