Merge pull request #1852 from sosan/feature-1794-auto-configmaps

add configmaps derived from file and dir
This commit is contained in:
Kubernetes Prow Robot
2024-04-25 05:56:20 -07:00
committed by GitHub
18 changed files with 1070 additions and 7 deletions
+78
View File
@@ -1173,3 +1173,81 @@ func getHpaMetricSpec(hpaValues HpaValues) []hpa.MetricSpec {
}
return metrics
}
// isConfigFile checks if the given filePath should be used as a configMap
// if dir is not empty, withindir are treated as cofigmaps
// if it's configMap, mount readonly as default
func isConfigFile(filePath string) (useConfigMap bool, readonly bool, skip bool) {
if filePath == "" || strings.HasSuffix(filePath, ".sock") {
skip = true
return
}
fi, err := os.Stat(filePath)
if err != nil {
log.Warnf("File don't exist or failed to check if the directory is empty: %v", err)
// dir/file not exist
// here not assigned skip to true,
// maybe dont want to skip
return
}
if !fi.Mode().IsRegular() { // is dir
isDirEmpty, err := checkIsEmptyDir(filePath)
if err != nil {
log.Warnf("Failed to check if the directory is empty: %v", err)
skip = true
return
}
if isDirEmpty {
return
}
}
return true, true, skip
}
// checkIsEmptyDir checks if filepath is empty
func checkIsEmptyDir(filePath string) (bool, error) {
files, err := os.ReadDir(filePath)
if err != nil {
return false, err
}
if len(files) == 0 {
return true, err
}
for _, file := range files {
if !file.IsDir() {
return false, nil
}
_, err := checkIsEmptyDir(file.Name())
if err != nil {
return false, err
}
}
return true, nil
}
// setVolumeAccessMode sets the access mode for a volume based on the mode string
// current types:
// ReadOnly RO and ReadOnlyMany ROX can be mounted in read-only mode to many hosts
// ReadWriteMany RWX can be mounted in read/write mode to many hosts
// ReadWriteOncePod RWOP can be mounted in read/write mode to exactly 1 pod
// ReadWriteOnce RWO can be mounted in read/write mode to exactly 1 host
// https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
func setVolumeAccessMode(mode string, volumeAccesMode []api.PersistentVolumeAccessMode) []api.PersistentVolumeAccessMode {
switch mode {
case "ro", "rox":
volumeAccesMode = []api.PersistentVolumeAccessMode{api.ReadOnlyMany}
case "rwx":
volumeAccesMode = []api.PersistentVolumeAccessMode{api.ReadWriteMany}
case "rwop":
volumeAccesMode = []api.PersistentVolumeAccessMode{api.ReadWriteOncePod}
case "rwo":
volumeAccesMode = []api.PersistentVolumeAccessMode{api.ReadWriteOnce}
default:
volumeAccesMode = []api.PersistentVolumeAccessMode{api.ReadWriteOnce}
}
return volumeAccesMode
}
+218
View File
@@ -2222,3 +2222,221 @@ func Test_createHPAResources(t *testing.T) {
})
}
}
func Test_setVolumeAccessMode(t *testing.T) {
type args struct {
mode string
volumeAccesMode []api.PersistentVolumeAccessMode
}
tests := []struct {
name string
args args
want []api.PersistentVolumeAccessMode
}{
{
name: "readonly",
args: args{
mode: "ro",
volumeAccesMode: []api.PersistentVolumeAccessMode{},
},
want: []api.PersistentVolumeAccessMode{api.ReadOnlyMany},
},
{
name: "not acceptable",
args: args{
mode: "wrong",
volumeAccesMode: []api.PersistentVolumeAccessMode{},
},
want: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
},
{
name: "readonly many",
args: args{
mode: "rox",
volumeAccesMode: []api.PersistentVolumeAccessMode{},
},
want: []api.PersistentVolumeAccessMode{api.ReadOnlyMany},
},
{
name: "readwrite many",
args: args{
mode: "rwx",
volumeAccesMode: []api.PersistentVolumeAccessMode{},
},
want: []api.PersistentVolumeAccessMode{api.ReadWriteMany},
},
{
name: "readwrite once in pod",
args: args{
mode: "rwop",
volumeAccesMode: []api.PersistentVolumeAccessMode{},
},
want: []api.PersistentVolumeAccessMode{api.ReadWriteOncePod},
},
{
name: "readwrite once",
args: args{
mode: "rwo",
volumeAccesMode: []api.PersistentVolumeAccessMode{},
},
want: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := setVolumeAccessMode(tt.args.mode, tt.args.volumeAccesMode); !reflect.DeepEqual(got, tt.want) {
t.Errorf("setVolumeAccessMode() = %v, want %v", got, tt.want)
}
})
}
}
func Test_isConfigFile(t *testing.T) {
type args struct {
filePath string
}
tests := []struct {
name string
args args
wantUseConfigMap bool
wantReadonly bool
wantSkip bool
}{
{
name: "dir not empty",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/certs",
},
wantUseConfigMap: true,
wantReadonly: true,
wantSkip: false,
},
{
name: "sock",
args: args{
filePath: "./docker.sock",
},
wantUseConfigMap: false,
wantReadonly: false,
wantSkip: true,
},
{
name: "cannot resolve filepath",
args: args{
filePath: "./certs/cert1.pem",
},
wantUseConfigMap: false,
wantReadonly: false,
wantSkip: false,
},
{
name: "file cert",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/certs/cert1.pem",
},
wantUseConfigMap: true,
wantReadonly: true,
wantSkip: false,
},
{
name: "docker sock",
args: args{
filePath: "/var/run/docker.sock",
},
wantUseConfigMap: false,
wantReadonly: false,
wantSkip: true,
},
{
name: "dir sys",
args: args{
filePath: "/sys",
},
wantUseConfigMap: false,
wantReadonly: false,
wantSkip: true,
},
{
name: "dir root",
args: args{
filePath: "/root",
},
wantUseConfigMap: false,
wantReadonly: false,
wantSkip: true,
},
{
name: "docker var lib",
args: args{
filePath: "/var/lib/docker",
},
wantUseConfigMap: false,
wantReadonly: false,
wantSkip: true,
},
{
name: "file from 3 levels",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/certs-level1/certs-level2/certs-level3/cert2.pem",
},
wantUseConfigMap: true,
wantReadonly: true,
wantSkip: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotUseConfigMap, gotReadonly, gotSkip := isConfigFile(tt.args.filePath)
if gotUseConfigMap != tt.wantUseConfigMap {
t.Errorf("isConfigFile() gotUseConfigMap = %v, want %v", gotUseConfigMap, tt.wantUseConfigMap)
}
if gotReadonly != tt.wantReadonly {
t.Errorf("isConfigFile() gotReadonly = %v, want %v", gotReadonly, tt.wantReadonly)
}
if gotSkip != tt.wantSkip {
t.Errorf("isConfigFile() gotSkip = %v, want %v", gotSkip, tt.wantSkip)
}
})
}
}
func Test_checkIsEmptyDir(t *testing.T) {
type args struct {
filePath string
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
{
name: "dir not found",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/notfound",
},
want: false,
wantErr: true,
},
{
name: "dir not empty",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/certs",
},
want: false,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := checkIsEmptyDir(tt.args.filePath)
if (err != nil) != tt.wantErr {
t.Errorf("checkIsEmptyDir() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("checkIsEmptyDir() = %v, want %v", got, tt.want)
}
})
}
}
+14 -6
View File
@@ -635,11 +635,7 @@ func (k *Kubernetes) CreatePVC(name string, mode string, size string, selectorVa
}
}
if mode == "ro" {
pvc.Spec.AccessModes = []api.PersistentVolumeAccessMode{api.ReadOnlyMany}
} else {
pvc.Spec.AccessModes = []api.PersistentVolumeAccessMode{api.ReadWriteOnce}
}
pvc.Spec.AccessModes = setVolumeAccessMode(mode, pvc.Spec.AccessModes)
if len(storageClassName) > 0 {
pvc.Spec.StorageClassName = &storageClassName
@@ -955,10 +951,22 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
volumes = append(volumes, secretsVolumes...)
var count int
skip := false
//iterating over array of `Vols` struct as it contains all necessary information about volumes
for _, volume := range service.Volumes {
// check if ro/rw mode is defined, default rw
readonly := len(volume.Mode) > 0 && volume.Mode == "ro"
readonly := len(volume.Mode) > 0 && (volume.Mode == "ro" || volume.Mode == "rox")
mountHost := volume.Host
if mountHost == "" {
mountHost = volume.MountPath
}
// return useconfigmap and readonly,
// not used asigned readonly because dont break e2e
useConfigMap, _, skip = isConfigFile(mountHost)
if skip {
log.Warnf("Skip file in path %s ", volume.Host)
continue
}
if volume.VolumeName == "" {
if useEmptyVolumes {
volumeName = strings.Replace(volume.PVCName, "claim", "empty", 1)
@@ -757,7 +757,7 @@ func TestMultipleContainersInPod(t *testing.T) {
config.Volumes = []kobject.Volumes{
{
VolumeName: "mountVolume",
MountPath: "/data",
MountPath: "/data-dir",
},
}
return config