Skip to content

Commit

Permalink
Bug 1527689 - Let users add the same PVC multiple times
Browse files Browse the repository at this point in the history
Reuse the same volume name if the PVC has already been added as a volume
to a pod template. This lets users add the same volume more than once
using different mount paths / subpaths.

Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1527689
  • Loading branch information
spadgett committed Feb 27, 2018
1 parent a5502e9 commit 286a579
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 15 deletions.
36 changes: 31 additions & 5 deletions app/scripts/controllers/attachPVC.js
Expand Up @@ -118,6 +118,32 @@ angular.module('openshiftConsole')
$scope.$watchGroup(['attach.resource', 'attach.allContainers'], updateMountPaths);
$scope.$watch('attach.containers', updateMountPaths, true);

var updateVolumeName = function() {
var pvc = _.get($scope, 'attach.persistentVolumeClaim');
if (!pvc) {
return;
}

// Check if there is already a volume for this PVC.
var volumes = _.get($scope, 'attach.resource.spec.template.spec.volumes');
var volume = _.find(volumes, {
persistentVolumeClaim: {
claimName: pvc.metadata.name
}
});

if (volume) {
// If there's already a volume, reuse the volume name.
$scope.attach.volumeName = volume.name;
$scope.volumeAlreadyMounted = true;
} else if ($scope.volumeAlreadyMounted) {
// Clear the volume name value since it was associated with the previously selected PVC.
$scope.attach.volumeName = '';
$scope.volumeAlreadyMounted = false;
}
};
$scope.onPVCSelected = updateVolumeName;

// load resources required to show the page (list of pvcs and deployment or deployment config)
var load = function() {
DataService.get(resourceGroupVersion, $routeParams.name, context).then(
Expand All @@ -130,6 +156,7 @@ angular.module('openshiftConsole')
});
var podTemplate = _.get(resource, 'spec.template');
$scope.existingVolumeNames = StorageService.getVolumeNames(podTemplate);
updateVolumeName();
},
function(e) {
displayError($routeParams.name + " could not be loaded.", getErrorDetails(e));
Expand All @@ -140,6 +167,7 @@ angular.module('openshiftConsole')
$scope.pvcs = orderByDisplayName(pvcs.by("metadata.name"));
if (!_.isEmpty($scope.pvcs) && !$scope.attach.persistentVolumeClaim) {
$scope.attach.persistentVolumeClaim = _.head($scope.pvcs);
updateVolumeName();
}
});

Expand Down Expand Up @@ -188,17 +216,15 @@ angular.module('openshiftConsole')
}

// add the new volume to the pod template
var newVolume = StorageService.createVolume(name, persistentVolumeClaim);
if (!podTemplate.spec.volumes) {
podTemplate.spec.volumes = [];
if (!$scope.volumeAlreadyMounted) {
podTemplate.spec.volumes = podTemplate.spec.volumes || [];
podTemplate.spec.volumes.push(StorageService.createVolume(name, persistentVolumeClaim));
}
podTemplate.spec.volumes.push(newVolume);

DataService.update(resourceGroupVersion, resource.metadata.name, $scope.attach.resource, context).then(
function() {
var details;
if (!mountPath) {
// FIXME: This seems like a bad experience since we don't give users a way to mount it later.
details = "No mount path was provided. The volume reference was added to the configuration, but it will not be mounted into running pods.";
}
NotificationsService.addNotification({
Expand Down
8 changes: 6 additions & 2 deletions app/views/attach-pvc.html
Expand Up @@ -44,9 +44,10 @@ <h1>Add Storage to {{name}}</h1>
name="persistentVolumeClaim"
ng-model="attach.persistentVolumeClaim"
ng-value="pvc"
ng-change="onPVCSelected()"
aria-describedby="pvc-help">
</td>
<td><a ng-href="{{pvc | navigateResourceURL}}">{{pvc.metadata.name}}</a></td>
<td><a ng-href="{{pvc | navigateResourceURL}}" target="_blank">{{pvc.metadata.name}}</a></td>
<td ng-if="pvc.spec.volumeName">{{pvc.status.capacity['storage'] | usageWithUnits: 'storage'}}</td>
<td ng-if="!pvc.spec.volumeName">{{pvc.spec.resources.requests['storage'] | usageWithUnits: 'storage'}}</td>
<td>({{pvc.spec.accessModes | accessModes | join}})</td>
Expand Down Expand Up @@ -135,15 +136,18 @@ <h3>Volume</h3>
Volume name must conform to a DNS label
https://github.com/kubernetes/kubernetes/blob/master/docs/design/identifiers.md
https://github.com/kubernetes/kubernetes/blob/d7a87c228506ed11240049ae95cbb4efb07fd178/pkg/util/validation/validation.go#L61-L70
Reuse the volume name and disable uniqueness validation if it's already mounted under another mount path / subpath.
-->
<input
id="volume-path"
class="form-control"
type="text"
name="volumeName"
ng-model="attach.volumeName"
osc-unique="existingVolumeNames"
ng-pattern="/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/"
ng-readonly="volumeAlreadyMounted"
osc-unique="existingVolumeNames"
osc-unique-disabled="volumeAlreadyMounted"
maxlength="63"
placeholder="(generated if empty)"
autocorrect="off"
Expand Down
20 changes: 15 additions & 5 deletions dist/scripts/scripts.js
Expand Up @@ -8684,18 +8684,30 @@ var e = _.get(n, "attach.resource.spec.template");
n.existingMountPaths = m.getMountPaths(e, P);
};
n.$watchGroup([ "attach.resource", "attach.allContainers" ], j), n.$watch("attach.containers", j, !0);
var k = function() {
var e = _.get(n, "attach.persistentVolumeClaim");
if (e) {
var t = _.get(n, "attach.resource.spec.template.spec.volumes"), r = _.find(t, {
persistentVolumeClaim: {
claimName: e.metadata.name
}
});
r ? (n.attach.volumeName = r.name, n.volumeAlreadyMounted = !0) : n.volumeAlreadyMounted && (n.attach.volumeName = "", n.volumeAlreadyMounted = !1);
}
};
n.onPVCSelected = k;
s.get(v, t.name, d).then(function(e) {
n.attach.resource = e, n.breadcrumbs = i.getBreadcrumbs({
object: e,
project: a,
subpage: "Add Storage"
});
var t = _.get(e, "spec.template");
n.existingVolumeNames = m.getVolumeNames(t);
n.existingVolumeNames = m.getVolumeNames(t), k();
}, function(e) {
S(t.name + " could not be loaded.", f(e));
}), s.list(n.pvcVersion, d).then(function(e) {
n.pvcs = p(e.by("metadata.name")), _.isEmpty(n.pvcs) || n.attach.persistentVolumeClaim || (n.attach.persistentVolumeClaim = _.head(n.pvcs));
n.pvcs = p(e.by("metadata.name")), _.isEmpty(n.pvcs) || n.attach.persistentVolumeClaim || (n.attach.persistentVolumeClaim = _.head(n.pvcs), k());
}), s.list(h, {
namespace: n.projectName
}, function(e) {
Expand All @@ -8713,9 +8725,7 @@ if (P(e)) {
var t = m.createVolumeMount(o, i, c, l);
e.volumeMounts || (e.volumeMounts = []), e.volumeMounts.push(t);
}
});
var p = m.createVolume(o, a);
r.spec.volumes || (r.spec.volumes = []), r.spec.volumes.push(p), s.update(v, e.metadata.name, n.attach.resource, d).then(function() {
}), n.volumeAlreadyMounted || (r.spec.volumes = r.spec.volumes || [], r.spec.volumes.push(m.createVolume(o, a))), s.update(v, e.metadata.name, n.attach.resource, d).then(function() {
var e;
i || (e = "No mount path was provided. The volume reference was added to the configuration, but it will not be mounted into running pods."), u.addNotification({
type: "success",
Expand Down
6 changes: 3 additions & 3 deletions dist/scripts/templates.js
Expand Up @@ -943,9 +943,9 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
"<tbody>\n" +
"<tr ng-repeat=\"pvc in pvcs track by (pvc | uid)\">\n" +
"<td style=\"padding-left:0\">\n" +
"<input type=\"radio\" name=\"persistentVolumeClaim\" ng-model=\"attach.persistentVolumeClaim\" ng-value=\"pvc\" aria-describedby=\"pvc-help\">\n" +
"<input type=\"radio\" name=\"persistentVolumeClaim\" ng-model=\"attach.persistentVolumeClaim\" ng-value=\"pvc\" ng-change=\"onPVCSelected()\" aria-describedby=\"pvc-help\">\n" +
"</td>\n" +
"<td><a ng-href=\"{{pvc | navigateResourceURL}}\">{{pvc.metadata.name}}</a></td>\n" +
"<td><a ng-href=\"{{pvc | navigateResourceURL}}\" target=\"_blank\">{{pvc.metadata.name}}</a></td>\n" +
"<td ng-if=\"pvc.spec.volumeName\">{{pvc.status.capacity['storage'] | usageWithUnits: 'storage'}}</td>\n" +
"<td ng-if=\"!pvc.spec.volumeName\">{{pvc.spec.resources.requests['storage'] | usageWithUnits: 'storage'}}</td>\n" +
"<td>({{pvc.spec.accessModes | accessModes | join}})</td>\n" +
Expand Down Expand Up @@ -1002,7 +1002,7 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
"<div class=\"form-group\">\n" +
"<label for=\"volume-name\">Volume Name</label>\n" +
"\n" +
"<input id=\"volume-path\" class=\"form-control\" type=\"text\" name=\"volumeName\" ng-model=\"attach.volumeName\" osc-unique=\"existingVolumeNames\" ng-pattern=\"/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/\" maxlength=\"63\" placeholder=\"(generated if empty)\" autocorrect=\"off\" autocapitalize=\"none\" spellcheck=\"false\" aria-describedby=\"volume-name-help\">\n" +
"<input id=\"volume-path\" class=\"form-control\" type=\"text\" name=\"volumeName\" ng-model=\"attach.volumeName\" ng-pattern=\"/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/\" ng-readonly=\"volumeAlreadyMounted\" osc-unique=\"existingVolumeNames\" osc-unique-disabled=\"volumeAlreadyMounted\" maxlength=\"63\" placeholder=\"(generated if empty)\" autocorrect=\"off\" autocapitalize=\"none\" spellcheck=\"false\" aria-describedby=\"volume-name-help\">\n" +
"<div>\n" +
"<span id=\"volume-name-help\" class=\"help-block\">Unique name used to identify this volume. If not specified, a volume name is generated.</span>\n" +
"</div>\n" +
Expand Down

0 comments on commit 286a579

Please sign in to comment.