Skip to content

Commit b8b6ce4

Browse files
committed
Support volume mount subpaths and read-only flag
Show subpath and read-only values for volume mounts. Allow users to set these fields on the add storage page.
1 parent 487f7df commit b8b6ce4

File tree

10 files changed

+171
-58
lines changed

10 files changed

+171
-58
lines changed

app/scripts/app.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,14 @@ angular
438438
// as a sanity test and shouldn't block submitting the form. Rely on the API
439439
// server for any additional validation.
440440
.constant('SOURCE_URL_PATTERN', /^[a-z][a-z0-9+.-@]*:(\/\/)?[0-9a-z_-]+/i)
441+
// RELATIVE_PATH_PATTERN matches any paths not starting with `/` or
442+
// containing `..` as path elements. Use negative lookaheads to assert that
443+
// the value does not match those patterns.
444+
//
445+
// (?!\/) do not match strings starting with `/`
446+
// (?!\.\.(\/|$)) do not match strings starting with `../` or exactly `..`
447+
// (?!.*\/\.\.(\/|$)) do not match strings containing `/../` or ending in `/..`
448+
.constant('RELATIVE_PATH_PATTERN', /^(?!\/)(?!\.\.(\/|$))(?!.*\/\.\.(\/|$)).*$/)
441449
// http://stackoverflow.com/questions/9038625/detect-if-device-is-ios
442450
.constant('IS_IOS', /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
443451
.constant('amTimeAgoConfig', {

app/scripts/controllers/addConfigVolume.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ angular.module('openshiftConsole')
2020
DataService,
2121
Navigate,
2222
ProjectsService,
23-
StorageService) {
23+
StorageService,
24+
RELATIVE_PATH_PATTERN) {
2425
if (!$routeParams.kind || !$routeParams.name) {
2526
Navigate.toErrorPage("Kind or name parameter missing.");
2627
return;
@@ -52,6 +53,7 @@ angular.module('openshiftConsole')
5253
pickKeys: false
5354
};
5455
$scope.forms = {};
56+
$scope.RELATIVE_PATH_PATTERN = RELATIVE_PATH_PATTERN;
5557

5658
$scope.breadcrumbs = BreadcrumbsService.getBreadcrumbs({
5759
name: $routeParams.name,

app/scripts/controllers/attachPVC.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ angular.module('openshiftConsole')
1919
DataService,
2020
Navigate,
2121
ProjectsService,
22-
StorageService) {
22+
StorageService,
23+
RELATIVE_PATH_PATTERN) {
2324
if (!$routeParams.kind || !$routeParams.name) {
2425
Navigate.toErrorPage("Kind or name parameter missing.");
2526
return;
@@ -50,6 +51,7 @@ angular.module('openshiftConsole')
5051
$scope.projectName = $routeParams.project;
5152
$scope.kind = $routeParams.kind;
5253
$scope.name = $routeParams.name;
54+
$scope.RELATIVE_PATH_PATTERN = RELATIVE_PATH_PATTERN;
5355

5456
$scope.attach = {
5557
persistentVolumeClaim: null,
@@ -149,11 +151,14 @@ angular.module('openshiftConsole')
149151
var persistentVolumeClaim = $scope.attach.persistentVolumeClaim;
150152
var name = $scope.attach.volumeName;
151153
var mountPath = $scope.attach.mountPath;
154+
var subPath = $scope.attach.subPath;
155+
var readOnly = $scope.attach.readOnly;
152156
if (mountPath) {
153157
// for each container in the pod spec, add the new volume mount
154158
angular.forEach(podTemplate.spec.containers, function(container) {
155159
if (isContainerSelected(container)) {
156-
var newVolumeMount = StorageService.createVolumeMount(name, mountPath);
160+
var newVolumeMount =
161+
StorageService.createVolumeMount(name, mountPath, subPath, readOnly);
157162
if (!container.volumeMounts) {
158163
container.volumeMounts = [];
159164
}

app/scripts/filters/resources.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,4 +1422,28 @@ angular.module('openshiftConsole')
14221422
_.has(build, 'spec.postCommit.script') ||
14231423
_.has(build, 'spec.postCommit.args');
14241424
};
1425+
})
1426+
.filter('volumeMountMode', function() {
1427+
var isConfigVolume = function(volume) {
1428+
return _.has(volume, 'configMap') || _.has(volume, 'secret');
1429+
};
1430+
1431+
return function(mount, volumes) {
1432+
if (!mount) {
1433+
return '';
1434+
}
1435+
1436+
// Config maps and secrets are always read-only, even if not explicitly
1437+
// set in the volume mount.
1438+
var volume = _.find(volumes, { name: mount.name });
1439+
if (isConfigVolume(volume)) {
1440+
return 'read-only';
1441+
}
1442+
1443+
if (_.get(volume, 'persistentVolumeClaim.readOnly')) {
1444+
return 'read-only';
1445+
}
1446+
1447+
return mount.readOnly ? 'read-only' : 'read-write';
1448+
};
14251449
});

app/scripts/services/storage.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,18 @@ angular.module("openshiftConsole")
1212
};
1313
},
1414

15-
createVolumeMount: function(name, mountPath) {
16-
return {
15+
createVolumeMount: function(name, mountPath, subPath, readOnly) {
16+
var mount = {
1717
name: name,
18-
mountPath: mountPath
18+
mountPath: mountPath,
19+
readOnly: !!readOnly
1920
};
21+
22+
if (subPath) {
23+
mount.subPath = subPath;
24+
}
25+
26+
return mount;
2027
},
2128

2229
// Gets the volume names currently defined in the pod template.

app/views/_pod-template.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@
127127
<div flex class="word-break">
128128
<span class="pod-template-key">Mount:</span>
129129
<span>
130-
{{mount.name}}&#8201;&#8594;&#8201;<span>{{mount.mountPath}}</span>
130+
{{mount.name}}<span ng-if="mount.subPath">, subpath {{mount.subPath}}</span>&#8201;&#8594;&#8201;<span>{{mount.mountPath}}</span>
131+
<small class="text-muted">{{mount | volumeMountMode : podTemplate.spec.volumes}}</small>
131132
</span>
132133
</div>
133134
</div>

app/views/add-config-volume.html

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,14 @@ <h3>Keys and Paths</h3>
145145
</div>
146146
<div class="form-group col-md-6">
147147
<label ng-attr-for="path-{{$id}}" class="required">Path</label>
148-
<!--
149-
Regex matches any paths not starting with `/` or containing `..` as path elements.
150-
Use negative lookaheads to assert that the value does not match those patterns.
151-
152-
(?!(\.\.)?\/) do not match strings starting with `/`
153-
(?!\.\.(\/|$)) do not match strings starting with `../` or exactly `..`
154-
(?!.*\/\.\.(\/|$)) do not match strings containing `/../` or ending in `/..`
155-
-->
156148
<input
157149
ng-attr-id="path-{{$id}}"
158150
class="form-control"
159151
ng-class="{ 'has-error': forms.addConfigVolumeForm['path-' + $id].$invalid && forms.addConfigVolumeForm['path-' + $id].$touched }"
160152
type="text"
161153
name="path-{{$id}}"
162154
ng-model="item.path"
163-
ng-pattern="/^(?!\/)(?!\.\.(\/|$))(?!.*\/\.\.(\/|$)).*$/"
155+
ng-pattern="RELATIVE_PATH_PATTERN"
164156
required
165157
osc-unique="itemPaths"
166158
placeholder="example: config/app.properties"

app/views/attach-pvc.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,32 @@ <h3>Volume</h3>
112112
</div>
113113
</div>
114114

115+
<div class="form-group">
116+
<label for="sub-path">Subpath</label>
117+
<input
118+
id="sub-path"
119+
class="form-control"
120+
type="text"
121+
name="subPath"
122+
ng-model="attach.subPath"
123+
placeholder="example: application/resources"
124+
ng-pattern="RELATIVE_PATH_PATTERN"
125+
autocorrect="off"
126+
autocapitalize="off"
127+
spellcheck="false"
128+
aria-describedby="sub-path-help">
129+
<div id="sub-path-help" class="help-block">
130+
Optional path within the volume from which it will be mounted into the
131+
container. Defaults to the volume's root.
132+
</div>
133+
<div class="has-error" ng-show="attachPVCForm.subPath.$error.pattern && attachPVCForm.subPath.$touched">
134+
<span class="help-block">
135+
Path must be a relative path. It cannot start with <code>/</code> or
136+
contain <code>..</code> path elements.
137+
</span>
138+
</div>
139+
</div>
140+
115141
<div class="form-group">
116142
<label for="volume-name">Volume Name</label>
117143
<!--
@@ -154,6 +180,18 @@ <h3>Volume</h3>
154180
</div>
155181
</div>
156182

183+
<div class="form-group">
184+
<div class="checkbox">
185+
<label>
186+
<input type="checkbox" ng-model="attach.readOnly" aria-describedby="read-only-help">
187+
Read only
188+
</label>
189+
<div id="read-only-help" class="help-block">
190+
Mount the volume as read-only.
191+
</div>
192+
</div>
193+
</div>
194+
157195
<!-- Prompt for containers only if there is more than one. -->
158196
<div ng-if="attach.resource.spec.template.spec.containers.length > 1">
159197
<div ng-if="attach.allContainers">

0 commit comments

Comments
 (0)