-
Notifications
You must be signed in to change notification settings - Fork 103
/
volume.go
148 lines (123 loc) · 4.36 KB
/
volume.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
package merger
import (
"fmt"
corev1 "k8s.io/api/core/v1"
)
// VolumeManager use to add a Volume to Pod and associated containers.
type VolumeManager interface {
// Add the volume to the PodTemplate.
AddVolume(volume *corev1.Volume)
// Add the volume to the PodTemplate.
// Provide merge functions if the merge is specific.
AddVolumeWithMergeFunc(volume *corev1.Volume, volumeMergeFunc VolumeMergeFunction) error
}
// NewVolumeManager returns a new instance of the VolumeManager
func NewVolumeManager(podTmpl *corev1.PodTemplateSpec) VolumeManager {
return &volumeManagerImpl{
podTmpl: podTmpl,
}
}
type volumeManagerImpl struct {
podTmpl *corev1.PodTemplateSpec
}
func (impl *volumeManagerImpl) AddVolume(volume *corev1.Volume) {
_ = impl.AddVolumeWithMergeFunc(volume, DefaultVolumeMergeFunction)
}
func (impl *volumeManagerImpl) AddVolumeWithMergeFunc(volume *corev1.Volume, volumeMergeFunc VolumeMergeFunction) error {
_, err := AddVolumeToPod(&impl.podTmpl.Spec, volume, volumeMergeFunc)
if err != nil {
return err
}
return nil
}
// VolumeMergeFunction signature for corev1.Volume merge function
type VolumeMergeFunction func(current, newVolume *corev1.Volume) (*corev1.Volume, error)
// DefaultVolumeMergeFunction default corev1.Volume merge function
// default correspond to OverrideCurrentVolumeMergeOption
func DefaultVolumeMergeFunction(current, newVolume *corev1.Volume) (*corev1.Volume, error) {
return OverrideCurrentVolumeMergeFunction(current, newVolume)
}
// OverrideCurrentVolumeMergeFunction used when the existing corev1.Volume new to be replace by the new one.
func OverrideCurrentVolumeMergeFunction(current, newVolume *corev1.Volume) (*corev1.Volume, error) {
return newVolume.DeepCopy(), nil
}
// MergeConfigMapItemsVolumeMergeFunction used when the existing corev1.Volume needs to be replace by the new one.
func MergeConfigMapItemsVolumeMergeFunction(current, newVolume *corev1.Volume) (*corev1.Volume, error) {
if current.ConfigMap.Name != newVolume.ConfigMap.Name {
return newVolume.DeepCopy(), nil
}
mergedVolume := current.DeepCopy()
var err error
mergedVolume.ConfigMap, err = mergeConfigMapVolumeSource(current.ConfigMap, newVolume.ConfigMap)
return mergedVolume, err
}
// IgnoreNewVolumeMergeFunction used when the existing corev1.Volume needs to be kept.
func IgnoreNewVolumeMergeFunction(current, newVolume *corev1.Volume) (*corev1.Volume, error) {
return current.DeepCopy(), nil
}
// ErrorOnMergeAttemptdVolumeMergeFunction used to avoid replacing an existing Volume
func ErrorOnMergeAttemptdVolumeMergeFunction(current, newVolume *corev1.Volume) (*corev1.Volume, error) {
return nil, errMergeAttempted
}
// AddVolumeToPod use to add a corev1.Volume to a Pod
// the mergeFunc can be provided to change the default merge behavior
func AddVolumeToPod(podSpec *corev1.PodSpec, volume *corev1.Volume, mergeFunc VolumeMergeFunction) ([]corev1.Volume, error) {
var found bool
for id, cVolume := range podSpec.Volumes {
if volume.Name == cVolume.Name {
if mergeFunc == nil {
mergeFunc = DefaultVolumeMergeFunction
}
newVolume, err := mergeFunc(&cVolume, volume)
if err != nil {
return nil, err
}
podSpec.Volumes[id] = *newVolume
found = true
}
}
if !found {
podSpec.Volumes = append(podSpec.Volumes, *volume)
}
return podSpec.Volumes, nil
}
func mergeConfigMapVolumeSource(a, b *corev1.ConfigMapVolumeSource) (*corev1.ConfigMapVolumeSource, error) {
newCMS := a.DeepCopy()
allPath := make(map[string]string)
for _, item := range a.Items {
allPath[item.Path] = item.Key
}
for key, item := range b.Items {
if oldKey, found := allPath[item.Path]; found {
if item.Key != oldKey {
return nil, fmt.Errorf("path %s already used", item.Path)
}
// else we need to merge it
for id, tmpItem := range newCMS.Items {
if tmpItem.Key == item.Key {
newCMS.Items[id].Mode = mergeMode(tmpItem.Mode, item.Mode)
}
}
} else {
newCMS.Items = append(newCMS.Items, b.Items[key])
}
allPath[item.Path] = item.Key
}
return newCMS, nil
}
func mergeMode(a, b *int32) *int32 {
if a == nil {
return b
}
if b == nil {
return a
}
if *b > *a {
return b
}
return a
}