add configmaps derived from file and dir

add tests and e2e
function isconfigfile check if we need to use configmap and mount in readonly
readonly not asigned because not fail e2e

Signed-off-by: jose luis <2064537+sosan@users.noreply.github.com>
This commit is contained in:
jose luis
2024-04-07 21:18:01 +02:00
parent 14152d4a81
commit 4cd0b268fc
9 changed files with 375 additions and 6 deletions
+64
View File
@@ -985,3 +985,67 @@ func reformatSecretConfigUnderscoreWithDash(secretConfig types.ServiceSecretConf
return newSecretConfig
}
// 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) {
if strings.HasSuffix(filePath, ".sock") {
return
}
fi, err := os.Stat(filePath)
if err != nil {
log.Warnf("Failed to check if the directory is empty: %v", err)
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)
return
}
if isDirEmpty {
return false, false
}
}
return true, true
}
// checkIsEmptyDir checks if filepath is empty
func checkIsEmptyDir(filePath string) (bool, error) {
entries, err := os.ReadDir(filePath)
if err != nil {
return false, err
}
if len(entries) == 0 {
return true, err
}
return false, err
}
// 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
}
+166
View File
@@ -29,6 +29,7 @@ import (
"github.com/kubernetes/kompose/pkg/testutils"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
api "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
)
@@ -738,3 +739,168 @@ func TestRemoveEmptyInterfaces(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
}{
{
name: "sock",
args: args{
filePath: "./docker.sock",
},
wantUseConfigMap: false,
wantReadonly: false,
},
{
name: "cannot resolve filepath",
args: args{
filePath: "./certs/cert1.pem",
},
wantUseConfigMap: false,
wantReadonly: false,
},
{
name: "file cert",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/certs/cert1.pem",
},
wantUseConfigMap: true,
wantReadonly: true,
},
{
name: "dir not empty",
args: args{
filePath: "../../../script/test/fixtures/configmap-file-configs/certs",
},
wantUseConfigMap: true,
wantReadonly: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotUseConfigMap, gotReadonly := 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)
}
})
}
}
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)
}
})
}
}
+5 -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
@@ -958,7 +954,10 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
//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")
// return useconfigmap and readonly,
// not used asigned readonly because dont break e2e
useConfigMap, _ = isConfigFile(volume.Host)
if volume.VolumeName == "" {
if useEmptyVolumes {
volumeName = strings.Replace(volume.PVCName, "claim", "empty", 1)