11
"github.com/containers/common/pkg/parse"
12
"github.com/containers/common/pkg/secrets"
13
"github.com/containers/podman/v5/libpod"
14
v1 "github.com/containers/podman/v5/pkg/k8s.io/api/core/v1"
15
"github.com/containers/storage/pkg/fileutils"
17
"github.com/sirupsen/logrus"
23
kubeDirectoryPermission = 0755
25
kubeFilePermission = 0644
29
type KubeVolumeType int
32
KubeVolumeTypeBindMount KubeVolumeType = iota
34
KubeVolumeTypeConfigMap
35
KubeVolumeTypeBlockDevice
36
KubeVolumeTypeCharDevice
38
KubeVolumeTypeEmptyDir
39
KubeVolumeTypeEmptyDirTmpfs
43
type KubeVolume struct {
52
Items map[string][]byte
62
func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource, mountLabel string) (*KubeVolume, error) {
63
if hostPath.Type != nil {
64
switch *hostPath.Type {
65
case v1.HostPathDirectoryOrCreate:
66
if err := os.MkdirAll(hostPath.Path, kubeDirectoryPermission); err != nil {
70
if err := libpod.LabelVolumePath(hostPath.Path, mountLabel); err != nil {
71
return nil, fmt.Errorf("giving %s a label: %w", hostPath.Path, err)
73
case v1.HostPathFileOrCreate:
74
if err := fileutils.Exists(hostPath.Path); errors.Is(err, fs.ErrNotExist) {
75
f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission)
77
return nil, fmt.Errorf("creating HostPath: %w", err)
79
if err := f.Close(); err != nil {
80
logrus.Warnf("Error in closing newly created HostPath file: %v", err)
85
if err := libpod.LabelVolumePath(hostPath.Path, mountLabel); err != nil {
86
return nil, fmt.Errorf("giving %s a label: %w", hostPath.Path, err)
88
case v1.HostPathSocket:
89
st, err := os.Stat(hostPath.Path)
91
return nil, fmt.Errorf("checking HostPathSocket: %w", err)
93
if st.Mode()&os.ModeSocket != os.ModeSocket {
94
return nil, fmt.Errorf("checking HostPathSocket: path %s is not a socket", hostPath.Path)
96
case v1.HostPathBlockDev:
97
dev, err := os.Stat(hostPath.Path)
99
return nil, fmt.Errorf("checking HostPathBlockDevice: %w", err)
101
if dev.Mode()&os.ModeCharDevice == os.ModeCharDevice {
102
return nil, fmt.Errorf("checking HostPathDevice: path %s is not a block device", hostPath.Path)
105
Type: KubeVolumeTypeBlockDevice,
106
Source: hostPath.Path,
108
case v1.HostPathCharDev:
109
dev, err := os.Stat(hostPath.Path)
111
return nil, fmt.Errorf("checking HostPathCharDevice: %w", err)
113
if dev.Mode()&os.ModeCharDevice != os.ModeCharDevice {
114
return nil, fmt.Errorf("checking HostPathCharDevice: path %s is not a character device", hostPath.Path)
117
Type: KubeVolumeTypeCharDevice,
118
Source: hostPath.Path,
120
case v1.HostPathDirectory:
121
case v1.HostPathFile:
122
case v1.HostPathUnset:
126
return nil, fmt.Errorf("invalid HostPath type %v", hostPath.Type)
130
if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil {
131
return nil, fmt.Errorf("in parsing HostPath in YAML: %w", err)
135
Type: KubeVolumeTypeBindMount,
136
Source: hostPath.Path,
141
func VolumeFromSecret(secretSource *v1.SecretVolumeSource, secretsManager *secrets.SecretsManager) (*KubeVolume, error) {
143
Type: KubeVolumeTypeSecret,
144
Source: secretSource.SecretName,
145
Items: map[string][]byte{},
146
DefaultMode: v1.SecretVolumeSourceDefaultMode,
149
validMode, err := isValidDefaultMode(secretSource.DefaultMode)
151
return nil, fmt.Errorf("invalid DefaultMode for secret %q: %w", secretSource.SecretName, err)
154
kv.DefaultMode = *secretSource.DefaultMode
158
_, secretByte, err := secretsManager.LookupSecretData(secretSource.SecretName)
160
if errors.Is(err, secrets.ErrNoSuchSecret) && secretSource.Optional != nil && *secretSource.Optional {
167
secret := &v1.Secret{}
169
err = yaml.Unmarshal(secretByte, secret)
175
if len(secretSource.Items) > 0 {
176
for _, item := range secretSource.Items {
177
if val, ok := secret.Data[item.Key]; ok {
178
kv.Items[item.Path] = val
179
} else if val, ok := secret.StringData[item.Key]; ok {
180
kv.Items[item.Path] = []byte(val)
185
for key, entry := range secret.Data {
186
kv.Items[key] = entry
189
for key, entry := range secret.StringData {
190
kv.Items[key] = []byte(entry)
198
func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource) (*KubeVolume, error) {
200
Type: KubeVolumeTypeNamed,
201
Source: claim.ClaimName,
205
func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) {
206
var configMap *v1.ConfigMap
208
Type: KubeVolumeTypeConfigMap,
209
Items: map[string][]byte{},
210
DefaultMode: v1.ConfigMapVolumeSourceDefaultMode,
212
for _, cm := range configMaps {
213
if cm.Name == configMapVolumeSource.Name {
217
configMap = &matchedCM
222
validMode, err := isValidDefaultMode(configMapVolumeSource.DefaultMode)
224
return nil, fmt.Errorf("invalid DefaultMode for configMap %q: %w", configMapVolumeSource.Name, err)
227
kv.DefaultMode = *configMapVolumeSource.DefaultMode
230
if configMap == nil {
232
if configMapVolumeSource.Optional != nil && *configMapVolumeSource.Optional {
233
kv.Source = configMapVolumeSource.Name
234
kv.Optional = *configMapVolumeSource.Optional
237
return nil, fmt.Errorf("no such ConfigMap %q", configMapVolumeSource.Name)
241
for k := range configMap.Data {
242
if _, ok := configMap.BinaryData[k]; ok {
243
return nil, fmt.Errorf("the ConfigMap %q is invalid: duplicate key %q present in data and binaryData", configMap.Name, k)
248
if len(configMapVolumeSource.Items) > 0 {
249
for _, item := range configMapVolumeSource.Items {
250
if val, ok := configMap.Data[item.Key]; ok {
251
kv.Items[item.Path] = []byte(val)
252
} else if val, ok := configMap.BinaryData[item.Key]; ok {
253
kv.Items[item.Path] = val
257
for k, v := range configMap.Data {
258
kv.Items[k] = []byte(v)
260
for k, v := range configMap.BinaryData {
268
func VolumeFromEmptyDir(emptyDirVolumeSource *v1.EmptyDirVolumeSource, name string) (*KubeVolume, error) {
269
if emptyDirVolumeSource.Medium == v1.StorageMediumMemory {
271
Type: KubeVolumeTypeEmptyDirTmpfs,
276
Type: KubeVolumeTypeEmptyDir,
283
func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager, volName, mountLabel string) (*KubeVolume, error) {
285
case volumeSource.HostPath != nil:
286
return VolumeFromHostPath(volumeSource.HostPath, mountLabel)
287
case volumeSource.PersistentVolumeClaim != nil:
288
return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim)
289
case volumeSource.ConfigMap != nil:
290
return VolumeFromConfigMap(volumeSource.ConfigMap, configMaps)
291
case volumeSource.Secret != nil:
292
return VolumeFromSecret(volumeSource.Secret, secretsManager)
293
case volumeSource.EmptyDir != nil:
294
return VolumeFromEmptyDir(volumeSource.EmptyDir, volName)
296
return nil, errors.New("HostPath, ConfigMap, EmptyDir, Secret, and PersistentVolumeClaim are currently the only supported VolumeSource")
301
func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager, mountLabel string) (map[string]*KubeVolume, error) {
302
volumes := make(map[string]*KubeVolume)
304
for _, specVolume := range specVolumes {
305
volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps, secretsManager, specVolume.Name, mountLabel)
307
return nil, fmt.Errorf("failed to create volume %q: %w", specVolume.Name, err)
310
volumes[specVolume.Name] = volume
317
func isValidDefaultMode(mode *int32) (bool, error) {
321
if *mode >= 0 && *mode <= int32(os.ModePerm) {
324
return false, errors.New("must be between 0000 and 0777")