Add policy support to workflow steps
This updates the workflow decorator service to check policy rules to determine whether or not to display a workflow step. Each workflow step can have a policy property which specifies the policy rule to check. Related to blueprint add-scheduler-hints Change-Id: Id9270a4f20d785283372c182d178fe9b59e3259b
This commit is contained in:
parent
a59195914e
commit
52f988cd78
@ -29,7 +29,9 @@
|
|||||||
});
|
});
|
||||||
return spec;
|
return spec;
|
||||||
};
|
};
|
||||||
$provide.value('horizon.app.core.openstack-service-api.serviceCatalog', {});
|
$provide.value('horizon.app.core.openstack-service-api.serviceCatalog', {
|
||||||
|
ifTypeEnabled: angular.noop
|
||||||
|
});
|
||||||
$provide.value('horizon.framework.util.workflow.service', workflow);
|
$provide.value('horizon.framework.util.workflow.service', workflow);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
|
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -26,14 +27,16 @@
|
|||||||
* @kind function
|
* @kind function
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* A workflow decorator function that adds checkReadiness method to step in
|
* A workflow decorator function that looks for the requiredServiceTypes or policy
|
||||||
* the work flow. checkReadiness function will check if a bunch of certain
|
* properties on each step in the workflow. If either of these properties exist then
|
||||||
* types of OpenStack services is enabled in the cloud for that step to show
|
* the checkReadiness method is added to the step. The checkReadiness method will
|
||||||
* on the user interface.
|
* make sure the necessary OpenStack services are enabled and the policy check passes
|
||||||
|
* in order for the step to be displayed.
|
||||||
*
|
*
|
||||||
* Injected dependencies:
|
* Injected dependencies:
|
||||||
* - $q
|
* - $q
|
||||||
* - serviceCatalog horizon.app.core.openstack-service-api.serviceCatalog
|
* - serviceCatalog horizon.app.core.openstack-service-api.serviceCatalog
|
||||||
|
* - policy horizon.app.core.openstack-service-api.policy
|
||||||
*
|
*
|
||||||
* @param {Object} spec The input workflow specification object.
|
* @param {Object} spec The input workflow specification object.
|
||||||
* @returns {Object} The decorated workflow specification object, the same
|
* @returns {Object} The decorated workflow specification object, the same
|
||||||
@ -46,12 +49,13 @@
|
|||||||
|
|
||||||
dashboardWorkflowDecorator.$inject = [
|
dashboardWorkflowDecorator.$inject = [
|
||||||
'$q',
|
'$q',
|
||||||
'horizon.app.core.openstack-service-api.serviceCatalog'
|
'horizon.app.core.openstack-service-api.serviceCatalog',
|
||||||
|
'horizon.app.core.openstack-service-api.policy'
|
||||||
];
|
];
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
|
|
||||||
function dashboardWorkflowDecorator($q, serviceCatalog) {
|
function dashboardWorkflowDecorator($q, serviceCatalog, policy) {
|
||||||
return decorator;
|
return decorator;
|
||||||
|
|
||||||
function decorator(spec) {
|
function decorator(spec) {
|
||||||
@ -64,12 +68,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function decorateStep(step) {
|
function decorateStep(step) {
|
||||||
|
var promises = [];
|
||||||
var types = step.requiredServiceTypes;
|
var types = step.requiredServiceTypes;
|
||||||
if (types && types.length > 0) {
|
if (types && types.length > 0) {
|
||||||
|
promises = promises.concat(types.map(function checkServiceEnabled(type) {
|
||||||
|
return serviceCatalog.ifTypeEnabled(type);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (step.policy) {
|
||||||
|
promises.push(policy.ifAllowed(step.policy));
|
||||||
|
}
|
||||||
|
if (promises.length > 0) {
|
||||||
step.checkReadiness = function () {
|
step.checkReadiness = function () {
|
||||||
return $q.all(types.map(function (type) {
|
return $q.all(promises);
|
||||||
return serviceCatalog.ifTypeEnabled(type);
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('Workflow Decorator', function () {
|
||||||
|
var decoratorService, catalogService, policyService, $scope, deferred;
|
||||||
|
var steps = [
|
||||||
|
{ id: '1' },
|
||||||
|
{ id: '2', requiredServiceTypes: ['foo-service'] },
|
||||||
|
{ id: '3', policy: 'foo-policy' }
|
||||||
|
];
|
||||||
|
var spec = { steps: steps };
|
||||||
|
|
||||||
|
beforeEach(module('horizon.app.core'));
|
||||||
|
beforeEach(module('horizon.framework.util'));
|
||||||
|
beforeEach(module('horizon.framework.conf'));
|
||||||
|
beforeEach(module('horizon.framework.widgets.toast'));
|
||||||
|
|
||||||
|
beforeEach(inject(function($injector) {
|
||||||
|
$scope = $injector.get('$rootScope').$new();
|
||||||
|
deferred = $injector.get('$q').defer();
|
||||||
|
decoratorService = $injector.get('horizon.app.core.workflow.decorator');
|
||||||
|
catalogService = $injector.get('horizon.app.core.openstack-service-api.serviceCatalog');
|
||||||
|
policyService = $injector.get('horizon.app.core.openstack-service-api.policy');
|
||||||
|
spyOn(catalogService, 'ifTypeEnabled').and.returnValue(deferred.promise);
|
||||||
|
spyOn(policyService, 'ifAllowed').and.returnValue(deferred.promise);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('is a function', function() {
|
||||||
|
expect(angular.isFunction(decoratorService)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks each step for required services and policies', function() {
|
||||||
|
decoratorService(spec);
|
||||||
|
expect(steps[0].checkReadiness).toBeUndefined();
|
||||||
|
expect(steps[1].checkReadiness).toBeDefined();
|
||||||
|
expect(steps[2].checkReadiness).toBeDefined();
|
||||||
|
expect(catalogService.ifTypeEnabled.calls.count()).toBe(1);
|
||||||
|
expect(catalogService.ifTypeEnabled).toHaveBeenCalledWith('foo-service');
|
||||||
|
expect(policyService.ifAllowed.calls.count()).toBe(1);
|
||||||
|
expect(policyService.ifAllowed).toHaveBeenCalledWith('foo-policy');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('step checkReadiness function returns correct results', function() {
|
||||||
|
decoratorService(spec);
|
||||||
|
var readinessResult;
|
||||||
|
deferred.resolve('foo');
|
||||||
|
steps[1].checkReadiness().then(function(result) {
|
||||||
|
readinessResult = result;
|
||||||
|
});
|
||||||
|
$scope.$apply();
|
||||||
|
expect(readinessResult).toEqual(['foo']);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -28,6 +28,35 @@
|
|||||||
* - dashboardWorkflowDecorator {@link horizon.app.core.workflow.factory
|
* - dashboardWorkflowDecorator {@link horizon.app.core.workflow.factory
|
||||||
* :horizon.app.core.workflow.decorator `dashboardWorkflowDecorator`}
|
* :horizon.app.core.workflow.decorator `dashboardWorkflowDecorator`}
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* var workflow = workflowService({
|
||||||
|
* title: gettext('Create Volume'),
|
||||||
|
* btnText: { finish: gettext('Create Volume') },
|
||||||
|
* steps: [{
|
||||||
|
* title: gettext('Step 1'),
|
||||||
|
* templateUrl: basePath + 'steps/create-volume/step1.html',
|
||||||
|
* helpUrl: basePath + 'steps/create-volume/step1.help.html',
|
||||||
|
* formName: 'step1Form'
|
||||||
|
* },{
|
||||||
|
* title: gettext('Step 2'),
|
||||||
|
* templateUrl: basePath + 'steps/create-volume/step2.html',
|
||||||
|
* helpUrl: basePath + 'steps/create-volume/step2.help.html',
|
||||||
|
* formName: 'step2Form',
|
||||||
|
* requiredServiceTypes: ['network']
|
||||||
|
* },{
|
||||||
|
* title: gettext('Step 3'),
|
||||||
|
* templateUrl: basePath + 'steps/create-volume/step3.html',
|
||||||
|
* helpUrl: basePath + 'steps/create-volume/step3.help.html',
|
||||||
|
* formName: 'step3Form',
|
||||||
|
* policy: { rules: [['compute', 'os_compute_api:os-scheduler-hints:discoverable']] }
|
||||||
|
* }]
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
* For each step, the requiredServiceTypes property specifies the service types that must
|
||||||
|
* be available in the service catalog for the step to be displayed. The policy property
|
||||||
|
* specifies the policy check that must pass in order for the step to be displayed.
|
||||||
|
*
|
||||||
* @param {Object} The input workflow specification object
|
* @param {Object} The input workflow specification object
|
||||||
* @returns {Object} The decorated workflow specification object, the same
|
* @returns {Object} The decorated workflow specification object, the same
|
||||||
* reference to the input spec object.
|
* reference to the input spec object.
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added policy support to the angular workflow service so each step in a
|
||||||
|
workflow can specify a policy check that must pass in order for the step
|
||||||
|
to be displayed.
|
Loading…
x
Reference in New Issue
Block a user