diff --git a/drivers/storage/portworx/uninstall.go b/drivers/storage/portworx/uninstall.go index 89f0b8e9f..d1a8f5b92 100644 --- a/drivers/storage/portworx/uninstall.go +++ b/drivers/storage/portworx/uninstall.go @@ -412,6 +412,7 @@ func (u *uninstallPortworx) RunNodeWiper( if strings.Contains(wiperImage, "monitor") { logrus.Warnf("Using oci-monitor %s as node-wiper image", wiperImage) ds.Spec.Template.Spec.Containers[0].Command = []string{"/px-node-wiper"} + pxutil.AppendUserVolumeMounts(&ds.Spec.Template.Spec, u.cluster.Spec.Volumes) } if u.cluster.Spec.ImagePullSecret != nil && *u.cluster.Spec.ImagePullSecret != "" { diff --git a/drivers/storage/portworx/util/util.go b/drivers/storage/portworx/util/util.go index 6a452d42a..efb79a686 100644 --- a/drivers/storage/portworx/util/util.go +++ b/drivers/storage/portworx/util/util.go @@ -1624,6 +1624,7 @@ func GetTLSCipherSuites(cluster *corev1.StorageCluster) (string, error) { } return strings.Join(outList, ","), nil } + func GetKvdbMap(k8sClient client.Client, cluster *corev1.StorageCluster, ) map[string]*kvdb_api.BootstrapEntry { @@ -1654,6 +1655,7 @@ func GetKvdbMap(k8sClient client.Client, } return kvdbNodeMap } + func blobToBootstrapEntries( entriesBlob []byte, ) (map[string]*kvdb_api.BootstrapEntry, error) { @@ -1670,3 +1672,45 @@ func blobToBootstrapEntries( } return retMap, nil } + +// AppendUserVolumeMounts appends "user" vol specs to the pod spec +// - note, the user volume specs will override container mounts, if the mount +// destination directory is the same +// - caveat: caller needs to ensure that the volume specs NAMES are unique +func AppendUserVolumeMounts( + podSpec *v1.PodSpec, + userVolSpecList []corev1.VolumeSpec, +) { + if podSpec == nil { + return + } else if len(userVolSpecList) == 0 { + return + } + + // make map of user-volumes, also append vols to pod spec + usrSpecMap := make(map[string]corev1.VolumeSpec) + for _, v := range userVolSpecList { + usrSpecMap[v.MountPath] = v + podSpec.Volumes = append(podSpec.Volumes, v1.Volume{ + Name: UserVolumeName(v.Name), + VolumeSource: v.VolumeSource, + }) + } + + // update container volumes, when destination-dir matches + for idx1, cntr := range podSpec.Containers { + for idx2, cv := range cntr.VolumeMounts { + if uv, has := usrSpecMap[cv.MountPath]; has { + logrus.Debugf("Replacing container %s:%s mount '%s' with user-mount '%s'", + cntr.Name, cv.MountPath, cv.Name, uv.Name) + + podSpec.Containers[idx1].VolumeMounts[idx2] = v1.VolumeMount{ + Name: UserVolumeName(uv.Name), + MountPath: uv.MountPath, + ReadOnly: uv.ReadOnly, + MountPropagation: uv.MountPropagation, + } + } + } + } +} diff --git a/drivers/storage/portworx/util/util_test.go b/drivers/storage/portworx/util/util_test.go index 8c6c35d03..1e6ed0a70 100644 --- a/drivers/storage/portworx/util/util_test.go +++ b/drivers/storage/portworx/util/util_test.go @@ -612,3 +612,115 @@ func TestGetTLSCipherSuites(t *testing.T) { } } } + +func TestAppendUserVolumeMounts(t *testing.T) { + podSpecReference := &v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "px", + VolumeMounts: []v1.VolumeMount{ + { + Name: "install-vol", + MountPath: "/opt/pwx", + }, + { + Name: "creds-vol", + MountPath: "/var/lib/serviceaccount", + }, + { + Name: "osd-vol", + MountPath: "/var/lib/osd", + }, + }, + }, + }, + Volumes: []v1.Volume{ + { + Name: "install-vol", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/opt/pwx", + }, + }, + }, + { + Name: "creds-vol", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/var/lib/kubelet/pod123/serviceaccount", + }, + }, + }, + { + Name: "osd-vol", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/var/lib/osd", + }, + }, + }, + }, + } + + // no user volume mounts + podSpec := podSpecReference.DeepCopy() + AppendUserVolumeMounts(podSpec, []corev1.VolumeSpec{}) + assert.Equal(t, podSpecReference, podSpec) + + // non-overlapping volume mounts + userMounts := []corev1.VolumeSpec{ + { + Name: "my-vol1", + MountPath: "/mnt/user-vol1", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/mnt/user-vol1", + }, + }, + }, + { + Name: "my-vol2", + MountPath: "/mnt/my-vol2", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/mnt/my-vol2", + }, + }, + }, + } + AppendUserVolumeMounts(podSpec, userMounts) + assert.Equal(t, podSpecReference.Containers, podSpec.Containers) + assert.Equal(t, len(podSpecReference.Volumes)+2, len(podSpec.Volumes)) + + // add destination-overlapping volume mounts + userMounts = []corev1.VolumeSpec{ + { + Name: "custom-install", + MountPath: "/opt/pwx", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/usr/local/portworx", + }, + }, + }, + { + Name: "custom-osd", + MountPath: "/var/lib/osd", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/var/lib/vcap/store/osd", + }, + }, + }, + } + podSpec = podSpecReference.DeepCopy() + AppendUserVolumeMounts(podSpec, userMounts) + assert.NotEqual(t, podSpecReference.Containers, podSpec.Containers) + assert.Equal(t, len(podSpecReference.Volumes)+2, len(podSpec.Volumes)) + assert.Equal(t, "user-custom-install", podSpec.Containers[0].VolumeMounts[0].Name) + assert.Equal(t, "creds-vol", podSpec.Containers[0].VolumeMounts[1].Name) + assert.Equal(t, "user-custom-osd", podSpec.Containers[0].VolumeMounts[2].Name) + assert.Equal(t, podSpecReference.Containers[0].VolumeMounts[0].MountPath, podSpec.Containers[0].VolumeMounts[0].MountPath) + assert.Equal(t, podSpecReference.Containers[0].VolumeMounts[1].MountPath, podSpec.Containers[0].VolumeMounts[1].MountPath) + assert.Equal(t, podSpecReference.Containers[0].VolumeMounts[2].MountPath, podSpec.Containers[0].VolumeMounts[2].MountPath) +}