Skip to content

Support volume mount subpaths and read-only flag #1108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,14 @@ angular
// as a sanity test and shouldn't block submitting the form. Rely on the API
// server for any additional validation.
.constant('SOURCE_URL_PATTERN', /^[a-z][a-z0-9+.-@]*:(\/\/)?[0-9a-z_-]+/i)
// RELATIVE_PATH_PATTERN matches any paths not starting with `/` or
// containing `..` as path elements. Use negative lookaheads to assert that
// the value does not match those patterns.
//
// (?!\/) do not match strings starting with `/`
// (?!\.\.(\/|$)) do not match strings starting with `../` or exactly `..`
// (?!.*\/\.\.(\/|$)) do not match strings containing `/../` or ending in `/..`
.constant('RELATIVE_PATH_PATTERN', /^(?!\/)(?!\.\.(\/|$))(?!.*\/\.\.(\/|$)).*$/)
// http://stackoverflow.com/questions/9038625/detect-if-device-is-ios
.constant('IS_IOS', /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
.constant('amTimeAgoConfig', {
Expand Down
4 changes: 3 additions & 1 deletion app/scripts/controllers/addConfigVolume.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ angular.module('openshiftConsole')
DataService,
Navigate,
ProjectsService,
StorageService) {
StorageService,
RELATIVE_PATH_PATTERN) {
if (!$routeParams.kind || !$routeParams.name) {
Navigate.toErrorPage("Kind or name parameter missing.");
return;
Expand Down Expand Up @@ -52,6 +53,7 @@ angular.module('openshiftConsole')
pickKeys: false
};
$scope.forms = {};
$scope.RELATIVE_PATH_PATTERN = RELATIVE_PATH_PATTERN;

$scope.breadcrumbs = BreadcrumbsService.getBreadcrumbs({
name: $routeParams.name,
Expand Down
9 changes: 7 additions & 2 deletions app/scripts/controllers/attachPVC.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ angular.module('openshiftConsole')
DataService,
Navigate,
ProjectsService,
StorageService) {
StorageService,
RELATIVE_PATH_PATTERN) {
if (!$routeParams.kind || !$routeParams.name) {
Navigate.toErrorPage("Kind or name parameter missing.");
return;
Expand Down Expand Up @@ -50,6 +51,7 @@ angular.module('openshiftConsole')
$scope.projectName = $routeParams.project;
$scope.kind = $routeParams.kind;
$scope.name = $routeParams.name;
$scope.RELATIVE_PATH_PATTERN = RELATIVE_PATH_PATTERN;

$scope.attach = {
persistentVolumeClaim: null,
Expand Down Expand Up @@ -149,11 +151,14 @@ angular.module('openshiftConsole')
var persistentVolumeClaim = $scope.attach.persistentVolumeClaim;
var name = $scope.attach.volumeName;
var mountPath = $scope.attach.mountPath;
var subPath = $scope.attach.subPath;
var readOnly = $scope.attach.readOnly;
if (mountPath) {
// for each container in the pod spec, add the new volume mount
angular.forEach(podTemplate.spec.containers, function(container) {
if (isContainerSelected(container)) {
var newVolumeMount = StorageService.createVolumeMount(name, mountPath);
var newVolumeMount =
StorageService.createVolumeMount(name, mountPath, subPath, readOnly);
if (!container.volumeMounts) {
container.volumeMounts = [];
}
Expand Down
24 changes: 24 additions & 0 deletions app/scripts/filters/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -1422,4 +1422,28 @@ angular.module('openshiftConsole')
_.has(build, 'spec.postCommit.script') ||
_.has(build, 'spec.postCommit.args');
};
})
.filter('volumeMountMode', function() {
var isConfigVolume = function(volume) {
return _.has(volume, 'configMap') || _.has(volume, 'secret');
};

return function(mount, volumes) {
if (!mount) {
return '';
}

// Config maps and secrets are always read-only, even if not explicitly
// set in the volume mount.
var volume = _.find(volumes, { name: mount.name });
if (isConfigVolume(volume)) {
return 'read-only';
}

if (_.get(volume, 'persistentVolumeClaim.readOnly')) {
return 'read-only';
}

return mount.readOnly ? 'read-only' : 'read-write';
};
});
13 changes: 10 additions & 3 deletions app/scripts/services/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@ angular.module("openshiftConsole")
};
},

createVolumeMount: function(name, mountPath) {
return {
createVolumeMount: function(name, mountPath, subPath, readOnly) {
var mount = {
name: name,
mountPath: mountPath
mountPath: mountPath,
readOnly: !!readOnly
};

if (subPath) {
mount.subPath = subPath;
}

return mount;
},

// Gets the volume names currently defined in the pod template.
Expand Down
3 changes: 2 additions & 1 deletion app/views/_pod-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
<div flex class="word-break">
<span class="pod-template-key">Mount:</span>
<span>
{{mount.name}}&#8201;&#8594;&#8201;<span>{{mount.mountPath}}</span>
{{mount.name}}<span ng-if="mount.subPath">, subpath {{mount.subPath}}</span>&#8201;&#8594;&#8201;<span>{{mount.mountPath}}</span>
<small class="text-muted">{{mount | volumeMountMode : podTemplate.spec.volumes}}</small>
</span>
</div>
</div>
Expand Down
10 changes: 1 addition & 9 deletions app/views/add-config-volume.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,22 +145,14 @@ <h3>Keys and Paths</h3>
</div>
<div class="form-group col-md-6">
<label ng-attr-for="path-{{$id}}" class="required">Path</label>
<!--
Regex matches any paths not starting with `/` or containing `..` as path elements.
Use negative lookaheads to assert that the value does not match those patterns.

(?!(\.\.)?\/) do not match strings starting with `/`
(?!\.\.(\/|$)) do not match strings starting with `../` or exactly `..`
(?!.*\/\.\.(\/|$)) do not match strings containing `/../` or ending in `/..`
-->
<input
ng-attr-id="path-{{$id}}"
class="form-control"
ng-class="{ 'has-error': forms.addConfigVolumeForm['path-' + $id].$invalid && forms.addConfigVolumeForm['path-' + $id].$touched }"
type="text"
name="path-{{$id}}"
ng-model="item.path"
ng-pattern="/^(?!\/)(?!\.\.(\/|$))(?!.*\/\.\.(\/|$)).*$/"
ng-pattern="RELATIVE_PATH_PATTERN"
required
osc-unique="itemPaths"
placeholder="example: config/app.properties"
Expand Down
38 changes: 38 additions & 0 deletions app/views/attach-pvc.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,32 @@ <h3>Volume</h3>
</div>
</div>

<div class="form-group">
<label for="sub-path">Subpath</label>
<input
id="sub-path"
class="form-control"
type="text"
name="subPath"
ng-model="attach.subPath"
placeholder="example: application/resources"
ng-pattern="RELATIVE_PATH_PATTERN"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
aria-describedby="sub-path-help">
<div id="sub-path-help" class="help-block">
Optional path within the volume from which it will be mounted into the
container. Defaults to the volume's root.
</div>
<div class="has-error" ng-show="attachPVCForm.subPath.$error.pattern && attachPVCForm.subPath.$touched">
<span class="help-block">
Path must be a relative path. It cannot start with <code>/</code> or
contain <code>..</code> path elements.
</span>
</div>
</div>

<div class="form-group">
<label for="volume-name">Volume Name</label>
<!--
Expand Down Expand Up @@ -154,6 +180,18 @@ <h3>Volume</h3>
</div>
</div>

<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="attach.readOnly" aria-describedby="read-only-help">
Read only
</label>
<div id="read-only-help" class="help-block">
Mount the volume as read-only.
</div>
</div>
</div>

<!-- Prompt for containers only if there is more than one. -->
<div ng-if="attach.resource.spec.template.spec.containers.length > 1">
<div ng-if="attach.allContainers">
Expand Down
Loading