forked from rhd-gitops-example/odo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
volumes.go
185 lines (161 loc) · 6.4 KB
/
volumes.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package occlient
import (
"fmt"
"github.com/golang/glog"
appsv1 "github.com/openshift/api/apps/v1"
"github.com/openshift/odo/pkg/util"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// CreatePVC creates a PVC resource in the cluster with the given name, size and
// labels
func (c *Client) CreatePVC(name string, size string, labels map[string]string, ownerReference ...metav1.OwnerReference) (*corev1.PersistentVolumeClaim, error) {
quantity, err := resource.ParseQuantity(size)
if err != nil {
return nil, errors.Wrapf(err, "unable to parse size: %v", size)
}
pvc := &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: labels,
},
Spec: corev1.PersistentVolumeClaimSpec{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: quantity,
},
},
AccessModes: []corev1.PersistentVolumeAccessMode{
corev1.ReadWriteOnce,
},
},
}
for _, owRf := range ownerReference {
pvc.SetOwnerReferences(append(pvc.GetOwnerReferences(), owRf))
}
createdPvc, err := c.kubeClient.CoreV1().PersistentVolumeClaims(c.Namespace).Create(pvc)
if err != nil {
return nil, errors.Wrap(err, "unable to create PVC")
}
return createdPvc, nil
}
// AddPVCToDeploymentConfig adds the given PVC to the given Deployment Config
// at the given path
func (c *Client) AddPVCToDeploymentConfig(dc *appsv1.DeploymentConfig, pvc string, path string) error {
volumeName := generateVolumeNameFromPVC(pvc)
// Validating dc.Spec.Template is present before dereferencing
if dc.Spec.Template == nil {
return fmt.Errorf("TemplatePodSpec in %s DeploymentConfig is empty", dc.Name)
}
dc.Spec.Template.Spec.Volumes = append(dc.Spec.Template.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: pvc,
},
},
})
// Validating dc.Spec.Template.Spec.Containers[] is present before dereferencing
if len(dc.Spec.Template.Spec.Containers) == 0 {
return fmt.Errorf("DeploymentConfig %s doesn't have any Containers defined", dc.Name)
}
dc.Spec.Template.Spec.Containers[0].VolumeMounts = append(dc.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: volumeName,
MountPath: path,
},
)
return nil
}
// UpdatePVCLabels updates the given PVC with the given labels
func (c *Client) UpdatePVCLabels(pvc *corev1.PersistentVolumeClaim, labels map[string]string) error {
pvc.Labels = labels
_, err := c.kubeClient.CoreV1().PersistentVolumeClaims(c.Namespace).Update(pvc)
if err != nil {
return errors.Wrap(err, "unable to remove storage label from PVC")
}
return nil
}
// DeletePVC deletes the given PVC by name
func (c *Client) DeletePVC(name string) error {
return c.kubeClient.CoreV1().PersistentVolumeClaims(c.Namespace).Delete(name, nil)
}
// IsAppSupervisorDVolume checks if the volume is a supervisorD volume
func (c *Client) IsAppSupervisorDVolume(volumeName, dcName string) bool {
return volumeName == getAppRootVolumeName(dcName)
}
// getVolumeNamesFromPVC returns the name of the volume associated with the given
// PVC in the given Deployment Config
func (c *Client) getVolumeNamesFromPVC(pvc string, dc *appsv1.DeploymentConfig) []string {
var volumes []string
for _, volume := range dc.Spec.Template.Spec.Volumes {
// If PVC does not exist, we skip (as this is either EmptyDir or "shared-data" from SupervisorD
if volume.PersistentVolumeClaim == nil {
glog.V(4).Infof("Volume has no PVC, skipping %s", volume.Name)
continue
}
// If we find the PVC, add to volumes to be returned
if volume.PersistentVolumeClaim.ClaimName == pvc {
volumes = append(volumes, volume.Name)
}
}
return volumes
}
// removeVolumeFromDC removes the volume from the given Deployment Config and
// returns true. If the given volume is not found, it returns false.
func removeVolumeFromDC(vol string, dc *appsv1.DeploymentConfig) bool {
found := false
for i, volume := range dc.Spec.Template.Spec.Volumes {
if volume.Name == vol {
found = true
dc.Spec.Template.Spec.Volumes = append(dc.Spec.Template.Spec.Volumes[:i], dc.Spec.Template.Spec.Volumes[i+1:]...)
}
}
return found
}
// removeVolumeMountsFromDC removes the volumeMounts from all the given containers
// in the given Deployment Config and return true. If any of the volumeMount with the name
// is not found, it returns false.
func removeVolumeMountsFromDC(vm string, dc *appsv1.DeploymentConfig) bool {
found := false
for i, container := range dc.Spec.Template.Spec.Containers {
for j, volumeMount := range container.VolumeMounts {
if volumeMount.Name == vm {
found = true
dc.Spec.Template.Spec.Containers[i].VolumeMounts = append(dc.Spec.Template.Spec.Containers[i].VolumeMounts[:j], dc.Spec.Template.Spec.Containers[i].VolumeMounts[j+1:]...)
}
}
}
return found
}
// generateVolumeNameFromPVC generates a random volume name based on the name
// of the given PVC
func generateVolumeNameFromPVC(pvc string) string {
return fmt.Sprintf("%v-%v-volume", pvc, util.GenerateRandomString(nameLength))
}
// addOrRemoveVolumeAndVolumeMount mounts or unmounts PVCs from the given deploymentConfig
func addOrRemoveVolumeAndVolumeMount(client *Client, dc *appsv1.DeploymentConfig, storageToMount map[string]*corev1.PersistentVolumeClaim, storageUnMount map[string]string) error {
if len(dc.Spec.Template.Spec.Containers) == 0 || len(dc.Spec.Template.Spec.Containers) > 1 {
return fmt.Errorf("more than one container found in dc")
}
// find the volume mount to be unmounted from the dc
for i, volumeMount := range dc.Spec.Template.Spec.Containers[0].VolumeMounts {
if _, ok := storageUnMount[volumeMount.MountPath]; ok {
dc.Spec.Template.Spec.Containers[0].VolumeMounts = append(dc.Spec.Template.Spec.Containers[0].VolumeMounts[:i], dc.Spec.Template.Spec.Containers[0].VolumeMounts[i+1:]...)
// now find the volume to be deleted from the dc
for j, volume := range dc.Spec.Template.Spec.Volumes {
if volume.Name == volumeMount.Name {
dc.Spec.Template.Spec.Volumes = append(dc.Spec.Template.Spec.Volumes[:j], dc.Spec.Template.Spec.Volumes[j+1:]...)
}
}
}
}
for path, pvc := range storageToMount {
err := client.AddPVCToDeploymentConfig(dc, pvc.Name, path)
if err != nil {
return errors.Wrap(err, "unable to add pvc to deployment config")
}
}
return nil
}