Support setting more visibility options for edit/create image
The edit and create image pages could only set public or private visibility for an image. With Glance v2, we have 'shared' and 'community' available to us. This commit adds buttons for those pages selectively when the policy allows it. It also only displays 'public' visibility if policy allows. Closes-Bug: #1792411 Depends-On: https://review.openstack.org/#/c/614688/ Change-Id: I193bc0580e4bf9351ad7f17b148a5062e95313ab
This commit is contained in:
parent
d58539fa49
commit
04fe1156bf
@ -54,7 +54,6 @@
|
|||||||
ctrl.diskFormats = [];
|
ctrl.diskFormats = [];
|
||||||
ctrl.prepareUpload = prepareUpload;
|
ctrl.prepareUpload = prepareUpload;
|
||||||
ctrl.apiVersion = 0;
|
ctrl.apiVersion = 0;
|
||||||
ctrl.allowPublicizeImage = true;
|
|
||||||
|
|
||||||
$scope.stepModels.imageForm = ctrl.image = {
|
$scope.stepModels.imageForm = ctrl.image = {
|
||||||
source_type: '',
|
source_type: '',
|
||||||
@ -66,7 +65,7 @@
|
|||||||
min_ram: 0,
|
min_ram: 0,
|
||||||
container_format: '',
|
container_format: '',
|
||||||
disk_format: '',
|
disk_format: '',
|
||||||
visibility: 'public'
|
visibility: 'shared'
|
||||||
};
|
};
|
||||||
|
|
||||||
ctrl.uploadProgress = -1;
|
ctrl.uploadProgress = -1;
|
||||||
@ -84,8 +83,8 @@
|
|||||||
ctrl.imageSourceOptions = [];
|
ctrl.imageSourceOptions = [];
|
||||||
|
|
||||||
ctrl.imageVisibilityOptions = [
|
ctrl.imageVisibilityOptions = [
|
||||||
{ label: gettext('Public'), value: 'public'},
|
{ label: gettext('Private'), value: 'private' },
|
||||||
{ label: gettext('Private'), value: 'private' }
|
{ label: gettext('Shared'), value: 'shared'}
|
||||||
];
|
];
|
||||||
|
|
||||||
ctrl.kernelImages = [];
|
ctrl.kernelImages = [];
|
||||||
@ -148,11 +147,14 @@
|
|||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
glance.getImages({paginate: false}).success(onGetImages);
|
glance.getImages({paginate: false}).success(onGetImages);
|
||||||
policyAPI.ifAllowed({rules: [['image', 'publicize_image']]}).then(
|
policyAPI.ifAllowed({rules: [['image', 'communitize_image']]}).then(
|
||||||
angular.noop,
|
|
||||||
function () {
|
function () {
|
||||||
ctrl.image.visibility = "private";
|
ctrl.imageVisibilityOptions.push({ label: gettext('Community'), value: 'community' });
|
||||||
ctrl.allowPublicizeImage = false;
|
}
|
||||||
|
);
|
||||||
|
policyAPI.ifAllowed({rules: [['image', 'publicize_image']]}).then(
|
||||||
|
function () {
|
||||||
|
ctrl.imageVisibilityOptions.push({ label: gettext('Public'), value: 'public' });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
it('should have options for visibility, protected and copying', function() {
|
it('should have options for visibility, protected and copying', function() {
|
||||||
var ctrl = createController();
|
var ctrl = createController();
|
||||||
|
|
||||||
expect(ctrl.imageVisibilityOptions.length).toEqual(2);
|
expect(ctrl.imageVisibilityOptions.length).toEqual(4);
|
||||||
expect(ctrl.imageProtectedOptions.length).toEqual(2);
|
expect(ctrl.imageProtectedOptions.length).toEqual(2);
|
||||||
expect(ctrl.imageCopyOptions.length).toEqual(2);
|
expect(ctrl.imageCopyOptions.length).toEqual(2);
|
||||||
});
|
});
|
||||||
@ -124,7 +124,7 @@
|
|||||||
expect(ctrl.imageFormats).toBeDefined();
|
expect(ctrl.imageFormats).toBeDefined();
|
||||||
expect(ctrl.validationRules).toBeDefined();
|
expect(ctrl.validationRules).toBeDefined();
|
||||||
expect(ctrl.diskFormats).toEqual([]);
|
expect(ctrl.diskFormats).toEqual([]);
|
||||||
expect(ctrl.image.visibility).toEqual('public');
|
expect(ctrl.image.visibility).toEqual('shared');
|
||||||
expect(ctrl.image.min_disk).toEqual(0);
|
expect(ctrl.image.min_disk).toEqual(0);
|
||||||
expect(ctrl.image.min_ram).toEqual(0);
|
expect(ctrl.image.min_ram).toEqual(0);
|
||||||
});
|
});
|
||||||
@ -214,6 +214,16 @@
|
|||||||
$timeout.flush();
|
$timeout.flush();
|
||||||
expect(ctrl.imageSourceOptions).toEqual([fileSourceOption, urlSourceOption]);
|
expect(ctrl.imageSourceOptions).toEqual([fileSourceOption, urlSourceOption]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('test image visibility is private if set as default', function() {
|
||||||
|
var ctrl = createController();
|
||||||
|
settingsCall.resolve({
|
||||||
|
OPENSTACK_IMAGE_FORMATS: [],
|
||||||
|
CREATE_IMAGE_DEFAULTS: { image_visibility: 'private' }
|
||||||
|
});
|
||||||
|
$timeout.flush();
|
||||||
|
expect(ctrl.image.visibility).toEqual('private');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@
|
|||||||
|
|
||||||
<div class="selected-source">
|
<div class="selected-source">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6 col-sm-6" ng-show='ctrl.allowPublicizeImage'>
|
<div class="col-xs-6 col-sm-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label required">
|
<label class="control-label required">
|
||||||
<translate>Visibility</translate>
|
<translate>Visibility</translate>
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
'$scope',
|
'$scope',
|
||||||
'horizon.app.core.images.imageFormats',
|
'horizon.app.core.images.imageFormats',
|
||||||
'horizon.app.core.images.validationRules',
|
'horizon.app.core.images.validationRules',
|
||||||
'horizon.app.core.openstack-service-api.settings'
|
'horizon.app.core.openstack-service-api.settings',
|
||||||
|
'horizon.app.core.openstack-service-api.policy'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +39,8 @@
|
|||||||
$scope,
|
$scope,
|
||||||
imageFormats,
|
imageFormats,
|
||||||
validationRules,
|
validationRules,
|
||||||
settings
|
settings,
|
||||||
|
policy
|
||||||
) {
|
) {
|
||||||
var ctrl = this;
|
var ctrl = this;
|
||||||
|
|
||||||
@ -52,12 +54,11 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
ctrl.imageVisibilityOptions = [
|
ctrl.imageVisibilityOptions = [
|
||||||
{ label: gettext('Public'), value: 'public' },
|
{ label: gettext('Private'), value: 'private' },
|
||||||
{ label: gettext('Private'), value: 'private' }
|
{ label: gettext('Shared'), value: 'shared' }
|
||||||
];
|
];
|
||||||
|
|
||||||
ctrl.setFormats = setFormats;
|
ctrl.setFormats = setFormats;
|
||||||
ctrl.allowPublicizeImage = { rules: [['image', 'image:publicize_image']] };
|
|
||||||
|
|
||||||
$scope.imagePromise.then(init);
|
$scope.imagePromise.then(init);
|
||||||
|
|
||||||
@ -80,13 +81,26 @@
|
|||||||
ctrl.image.kernel = ctrl.image.properties.kernel_id;
|
ctrl.image.kernel = ctrl.image.properties.kernel_id;
|
||||||
ctrl.image.ramdisk = ctrl.image.properties.ramdisk_id;
|
ctrl.image.ramdisk = ctrl.image.properties.ramdisk_id;
|
||||||
ctrl.image.architecture = ctrl.image.properties.architecture;
|
ctrl.image.architecture = ctrl.image.properties.architecture;
|
||||||
ctrl.image.visibility = ctrl.image.is_public ? 'public' : 'private';
|
|
||||||
ctrl.image_format = ctrl.image.disk_format;
|
ctrl.image_format = ctrl.image.disk_format;
|
||||||
if (ctrl.image.container_format === 'docker') {
|
if (ctrl.image.container_format === 'docker') {
|
||||||
ctrl.image_format = 'docker';
|
ctrl.image_format = 'docker';
|
||||||
ctrl.image.disk_format = 'raw';
|
ctrl.image.disk_format = 'raw';
|
||||||
}
|
}
|
||||||
setFormats();
|
setFormats();
|
||||||
|
getVisibilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVisibilities() {
|
||||||
|
policy.ifAllowed({rules: [['image', 'communitize_image']]}).then(
|
||||||
|
function() {
|
||||||
|
ctrl.imageVisibilityOptions.push({ label: gettext('Community'), value: 'community' });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
policy.ifAllowed({rules: [['image', 'publicize_image']]}).then(
|
||||||
|
function() {
|
||||||
|
ctrl.imageVisibilityOptions.push({ label: gettext('Public'), value: 'public' });
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFormats() {
|
function setFormats() {
|
||||||
|
@ -19,7 +19,15 @@
|
|||||||
|
|
||||||
describe('horizon.app.core.images edit image controller', function() {
|
describe('horizon.app.core.images edit image controller', function() {
|
||||||
|
|
||||||
var controller, $scope, $q, settingsCall, $timeout;
|
function policyIfAllowed() {
|
||||||
|
return {
|
||||||
|
then: function(callback) {
|
||||||
|
callback({allowed: true});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var controller, $scope, $q, settingsCall, $timeout, policy;
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
||||||
@ -35,6 +43,9 @@
|
|||||||
$timeout = _$timeout_;
|
$timeout = _$timeout_;
|
||||||
|
|
||||||
controller = $injector.get('$controller');
|
controller = $injector.get('$controller');
|
||||||
|
|
||||||
|
policy = $injector.get('horizon.app.core.openstack-service-api.policy');
|
||||||
|
spyOn(policy, 'ifAllowed').and.callFake(policyIfAllowed);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function createController() {
|
function createController() {
|
||||||
@ -57,19 +68,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should have options for visibility and protected', function() {
|
it('should have options for visibility and protected', function() {
|
||||||
setImagePromise({id: '1', container_format: 'bare', is_public: false, properties: []});
|
setImagePromise({id: '1', container_format: 'bare', visibility: 'shared', properties: []});
|
||||||
var ctrl = createController();
|
|
||||||
|
|
||||||
expect(ctrl.imageVisibilityOptions.length).toEqual(2);
|
|
||||||
expect(ctrl.imageProtectedOptions.length).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should map is_public', function() {
|
|
||||||
setImagePromise({id: '1', container_format: 'bare', is_public: false, properties: []});
|
|
||||||
var ctrl = createController();
|
var ctrl = createController();
|
||||||
$timeout.flush();
|
$timeout.flush();
|
||||||
|
|
||||||
expect(ctrl.image.visibility).toEqual('private');
|
expect(ctrl.imageVisibilityOptions.length).toEqual(4);
|
||||||
|
expect(ctrl.imageProtectedOptions.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reads the data format settings', function() {
|
it('reads the data format settings', function() {
|
||||||
@ -87,14 +91,14 @@
|
|||||||
id: '1',
|
id: '1',
|
||||||
container_format: 'bare',
|
container_format: 'bare',
|
||||||
disk_format: 'ova',
|
disk_format: 'ova',
|
||||||
is_public: true,
|
visibility: 'private',
|
||||||
properties: []
|
properties: []
|
||||||
});
|
});
|
||||||
var ctrl = createController();
|
var ctrl = createController();
|
||||||
$timeout.flush();
|
$timeout.flush();
|
||||||
|
|
||||||
expect(ctrl.image.disk_format).toEqual('ova');
|
expect(ctrl.image.disk_format).toEqual('ova');
|
||||||
expect(ctrl.image.visibility).toEqual('public');
|
expect(ctrl.image.visibility).toEqual('private');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set local image_format to docker when container is docker', function() {
|
it('should set local image_format to docker when container is docker', function() {
|
||||||
|
@ -123,7 +123,7 @@
|
|||||||
|
|
||||||
<div class="selected-source clearfix">
|
<div class="selected-source clearfix">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6 col-sm-6" hz-if-policies="ctrl.allowPublicizeImage">
|
<div class="col-xs-6 col-sm-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label required" translate>Visibility</label>
|
<label class="control-label required" translate>Visibility</label>
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
|
@ -121,7 +121,7 @@
|
|||||||
* The minimum memory size required to boot the image. Optional.
|
* The minimum memory size required to boot the image. Optional.
|
||||||
*
|
*
|
||||||
* @param {boolean} image.visibility
|
* @param {boolean} image.visibility
|
||||||
* values of 'public', 'private', and 'shared' are valid. Required.
|
* values of 'public', 'private', 'shared' and 'community' are valid. Required.
|
||||||
*
|
*
|
||||||
* @param {boolean} image.protected
|
* @param {boolean} image.protected
|
||||||
* True if the image is protected, false otherwise. Required.
|
* True if the image is protected, false otherwise. Required.
|
||||||
@ -217,7 +217,7 @@
|
|||||||
* The minimum memory size required to boot the image. Optional.
|
* The minimum memory size required to boot the image. Optional.
|
||||||
*
|
*
|
||||||
* @param {boolean} image.visibility
|
* @param {boolean} image.visibility
|
||||||
* Values of 'public', 'private', and 'shared' are valid. Required.
|
* Values of 'public', 'private', 'shared' and 'community' are valid. Required.
|
||||||
*
|
*
|
||||||
* @param {boolean} image.protected
|
* @param {boolean} image.protected
|
||||||
* True if the image is protected, false otherwise. Required.
|
* True if the image is protected, false otherwise. Required.
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
other:
|
||||||
|
- |
|
||||||
|
The default visibility when creating new images has been changed from
|
||||||
|
`private` to `shared` to bring it inline with the default changing in
|
||||||
|
Glance since Image API v2.5.
|
Loading…
Reference in New Issue
Block a user