mirror of https://github.com/apache/nifi.git
NIFI-2542: - Ensuring transitive referencing components are able to be returned. - Ensuring we can enable/disable services with transitive referencing components. - Ensuring we cannot enable/disable services with unauthorized referencing components.
NIFI-2543: - Ensuring we have permissions before attempting to reload a controller service. This closes #837 Signed-off-by: jpercivall <joepercivall@yahoo.com>
This commit is contained in:
parent
25a2fac453
commit
fa639e2596
|
@ -226,19 +226,32 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
return COUNTERS_AUTHORIZABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getControllerServiceReferencingComponent(String controllerSeriveId, String id) {
|
||||
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerSeriveId);
|
||||
final ControllerServiceReference referencingComponents = controllerService.getReferences();
|
||||
|
||||
private ConfiguredComponent findControllerServiceReferencingComponent(final ControllerServiceReference referencingComponents, final String id) {
|
||||
ConfiguredComponent reference = null;
|
||||
for (final ConfiguredComponent component : referencingComponents.getReferencingComponents()) {
|
||||
if (component.getIdentifier().equals(id)) {
|
||||
reference = component;
|
||||
break;
|
||||
}
|
||||
|
||||
if (component instanceof ControllerServiceNode) {
|
||||
final ControllerServiceNode refControllerService = (ControllerServiceNode) component;
|
||||
reference = findControllerServiceReferencingComponent(refControllerService.getReferences(), id);
|
||||
if (reference != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getControllerServiceReferencingComponent(String controllerSeriveId, String id) {
|
||||
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerSeriveId);
|
||||
final ControllerServiceReference referencingComponents = controllerService.getReferences();
|
||||
final ConfiguredComponent reference = findControllerServiceReferencingComponent(referencingComponents, id);
|
||||
|
||||
if (reference == null) {
|
||||
throw new ResourceNotFoundException("Unable to find referencing component with id " + id);
|
||||
}
|
||||
|
|
|
@ -1676,13 +1676,32 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
final RevisionUpdate<ControllerServiceDTO> snapshot = updateComponent(revision,
|
||||
controllerService,
|
||||
() -> controllerServiceDAO.updateControllerService(controllerServiceDTO),
|
||||
cs -> dtoFactory.createControllerServiceDto(cs));
|
||||
cs -> {
|
||||
final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(cs);
|
||||
final ControllerServiceReference ref = controllerService.getReferences();
|
||||
final ControllerServiceReferencingComponentsEntity referencingComponentsEntity =
|
||||
createControllerServiceReferencingComponentsEntity(ref, Sets.newHashSet(controllerService.getIdentifier()));
|
||||
dto.setReferencingComponents(referencingComponentsEntity.getControllerServiceReferencingComponents());
|
||||
return dto;
|
||||
});
|
||||
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(controllerService);
|
||||
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(controllerServiceDTO.getId()));
|
||||
return entityFactory.createControllerServiceEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, bulletins);
|
||||
}
|
||||
|
||||
private Set<ConfiguredComponent> findAllReferencingComponents(final ControllerServiceReference reference) {
|
||||
final Set<ConfiguredComponent> referencingComponents = new HashSet<>(reference.getReferencingComponents());
|
||||
|
||||
for (final ConfiguredComponent referencingComponent : reference.getReferencingComponents()) {
|
||||
if (referencingComponent instanceof ControllerServiceNode) {
|
||||
referencingComponents.addAll(findAllReferencingComponents(((ControllerServiceNode) referencingComponent).getReferences()));
|
||||
}
|
||||
}
|
||||
|
||||
return referencingComponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerServiceReferencingComponentsEntity updateControllerServiceReferencingComponents(
|
||||
final Map<String, Revision> referenceRevisions, final String controllerServiceId, final ScheduledState scheduledState, final ControllerServiceState controllerServiceState) {
|
||||
|
@ -1705,13 +1724,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
updatedRevisions.put(component.getIdentifier(), currentRevision.incrementRevision(requestRevision.getClientId()));
|
||||
}
|
||||
|
||||
// return the current revision if the component wasn't updated
|
||||
for (final Map.Entry<String, Revision> entry : referenceRevisions.entrySet()) {
|
||||
final String componentId = entry.getKey();
|
||||
if (!updatedRevisions.containsKey(componentId)) {
|
||||
final Revision currentRevision = revisionManager.getRevision(componentId);
|
||||
updatedRevisions.put(componentId, currentRevision);
|
||||
}
|
||||
// ensure the revision for all referencing components is included regardless of whether they were updated in this request
|
||||
for (final ConfiguredComponent component : findAllReferencingComponents(updatedReference)) {
|
||||
updatedRevisions.putIfAbsent(component.getIdentifier(), revisionManager.getRevision(component.getIdentifier()));
|
||||
}
|
||||
|
||||
final ControllerServiceReferencingComponentsEntity entity = createControllerServiceReferencingComponentsEntity(updatedReference, updatedRevisions);
|
||||
|
@ -1757,6 +1772,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
for (final ConfiguredComponent component : reference.getReferencingComponents()) {
|
||||
referencingRevisions.put(component.getIdentifier(), revisionManager.getRevision(component.getIdentifier()));
|
||||
}
|
||||
|
||||
return createControllerServiceReferencingComponentsEntity(reference, referencingRevisions);
|
||||
}
|
||||
|
||||
|
@ -1806,7 +1822,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
|
||||
// if we haven't encountered this service before include it's referencing components
|
||||
if (!dto.getReferenceCycle()) {
|
||||
final ControllerServiceReferencingComponentsEntity references = createControllerServiceReferencingComponentsEntity(node.getReferences(), revisions, visited);
|
||||
final ControllerServiceReference refReferences = node.getReferences();
|
||||
final Map<String, Revision> referencingRevisions = new HashMap<>(revisions);
|
||||
for (final ConfiguredComponent component : refReferences.getReferencingComponents()) {
|
||||
referencingRevisions.putIfAbsent(component.getIdentifier(), revisionManager.getRevision(component.getIdentifier()));
|
||||
}
|
||||
final ControllerServiceReferencingComponentsEntity references = createControllerServiceReferencingComponentsEntity(refReferences, referencingRevisions, visited);
|
||||
dto.setReferencingComponents(references.getControllerServiceReferencingComponents());
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ nf.ControllerService = (function () {
|
|||
};
|
||||
|
||||
/**
|
||||
* Reloads the specified controller service. It's referencing and referenced
|
||||
* Reloads the specified controller service if we have read permissions. It's referencing and referenced
|
||||
* components are NOT reloaded.
|
||||
*
|
||||
* @param {jQuery} serviceTable
|
||||
|
@ -123,8 +123,9 @@ nf.ControllerService = (function () {
|
|||
|
||||
// this may happen if controller service A references another controller
|
||||
// service B that has been removed. attempting to enable/disable/remove A
|
||||
// will attempt to reload B which is no longer a known service
|
||||
if (nf.Common.isUndefined(controllerServiceEntity)) {
|
||||
// will attempt to reload B which is no longer a known service. also ensure
|
||||
// we have permissions to reload the service
|
||||
if (nf.Common.isUndefined(controllerServiceEntity) || controllerServiceEntity.permissions.canRead === false) {
|
||||
return $.Deferred(function (deferred) {
|
||||
deferred.reject();
|
||||
}).promise();
|
||||
|
@ -457,7 +458,8 @@ nf.ControllerService = (function () {
|
|||
if (serviceTwist.hasClass('collapsed')) {
|
||||
var controllerServiceGrid = serviceTable.data('gridInstance');
|
||||
var controllerServiceData = controllerServiceGrid.getData();
|
||||
var referencingService = controllerServiceData.getItemById(referencingComponent.id);
|
||||
var referencingServiceEntity = controllerServiceData.getItemById(referencingComponent.id);
|
||||
var referencingService = referencingServiceEntity.component;
|
||||
|
||||
// create the markup for the references
|
||||
createReferencingComponents(serviceTable, referencingServiceReferencesContainer, referencingService.referencingComponents);
|
||||
|
@ -673,6 +675,33 @@ nf.ControllerService = (function () {
|
|||
return ids;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gathers all referencing component revisions.
|
||||
*
|
||||
* @param referencingComponents
|
||||
* @param referencingComponentRevisions
|
||||
* @param serviceOnly - true includes only services, false includes only schedulable components
|
||||
*/
|
||||
var getReferencingComponentRevisions = function (referencingComponents, referencingComponentRevisions, serviceOnly) {
|
||||
// include the revision of each referencing component
|
||||
$.each(referencingComponents, function (_, referencingComponentEntity) {
|
||||
var referencingComponent = referencingComponentEntity.component;
|
||||
|
||||
if (serviceOnly) {
|
||||
if (referencingComponent.referenceType === 'ControllerService') {
|
||||
referencingComponentRevisions[referencingComponentEntity.id] = nf.Client.getRevision(referencingComponentEntity);
|
||||
}
|
||||
} else {
|
||||
if (referencingComponent.referenceType !== 'ControllerService') {
|
||||
referencingComponentRevisions[referencingComponentEntity.id] = nf.Client.getRevision(referencingComponentEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// recurse
|
||||
getReferencingComponentRevisions(referencingComponent.referencingComponents, referencingComponentRevisions, serviceOnly);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the scheduled state of the processors/reporting tasks referencing
|
||||
* the specified controller service.
|
||||
|
@ -683,17 +712,15 @@ nf.ControllerService = (function () {
|
|||
* @param {function} pollCondition
|
||||
*/
|
||||
var updateReferencingSchedulableComponents = function (serviceTable, controllerServiceEntity, running, pollCondition) {
|
||||
var referencingRevisions = {};
|
||||
getReferencingComponentRevisions(controllerServiceEntity.component.referencingComponents, referencingRevisions, false);
|
||||
|
||||
var referenceEntity = {
|
||||
'id': controllerServiceEntity.id,
|
||||
'state': running ? 'RUNNING' : 'STOPPED',
|
||||
'referencingComponentRevisions': {}
|
||||
'referencingComponentRevisions': referencingRevisions
|
||||
};
|
||||
|
||||
// include the revision of each referencing component
|
||||
$.each(controllerServiceEntity.component.referencingComponents, function (_, referencingComponent) {
|
||||
referenceEntity.referencingComponentRevisions[referencingComponent.id] = nf.Client.getRevision(referencingComponent);
|
||||
});
|
||||
|
||||
// issue the request to update the referencing components
|
||||
var updated = $.ajax({
|
||||
type: 'PUT',
|
||||
|
@ -956,18 +983,16 @@ nf.ControllerService = (function () {
|
|||
* @param {function} pollCondition
|
||||
*/
|
||||
var updateReferencingServices = function (serviceTable, controllerServiceEntity, enabled, pollCondition) {
|
||||
var referencingRevisions = {};
|
||||
getReferencingComponentRevisions(controllerServiceEntity.component.referencingComponents, referencingRevisions, true);
|
||||
|
||||
// build the reference entity
|
||||
var referenceEntity = {
|
||||
'id': controllerServiceEntity.id,
|
||||
'state': enabled ? 'ENABLED' : 'DISABLED',
|
||||
'referencingComponentRevisions': {}
|
||||
'referencingComponentRevisions': referencingRevisions
|
||||
};
|
||||
|
||||
// include the revision of each referencing component
|
||||
$.each(controllerServiceEntity.component.referencingComponents, function (_, referencingComponent) {
|
||||
referenceEntity.referencingComponentRevisions[referencingComponent.id] = nf.Client.getRevision(referencingComponent);
|
||||
});
|
||||
|
||||
// issue the request to update the referencing components
|
||||
var updated = $.ajax({
|
||||
type: 'PUT',
|
||||
|
@ -1029,34 +1054,20 @@ nf.ControllerService = (function () {
|
|||
var referencingComponentsContainer = $('#disable-controller-service-referencing-components');
|
||||
createReferencingComponents(serviceTable, referencingComponentsContainer, controllerService.referencingComponents);
|
||||
|
||||
var hasUnauthorized = false;
|
||||
$.each(controllerService.referencingComponents, function (_, referencingComponent) {
|
||||
if (referencingComponent.permissions.canRead === false || referencingComponent.permissions.canWrite === false) {
|
||||
hasUnauthorized = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// build the button model
|
||||
var buttons = [];
|
||||
|
||||
if (hasUnauthorized === false) {
|
||||
buttons.push({
|
||||
buttonText: 'Disable',
|
||||
color: {
|
||||
base: '#728E9B',
|
||||
hover: '#004849',
|
||||
text: '#ffffff'
|
||||
},
|
||||
handler: {
|
||||
click: function () {
|
||||
disableHandler(serviceTable);
|
||||
}
|
||||
var buttons = [{
|
||||
buttonText: 'Disable',
|
||||
color: {
|
||||
base: '#728E9B',
|
||||
hover: '#004849',
|
||||
text: '#ffffff'
|
||||
},
|
||||
handler: {
|
||||
click: function () {
|
||||
disableHandler(serviceTable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
}
|
||||
}, {
|
||||
buttonText: 'Cancel',
|
||||
color: {
|
||||
base: '#E3E8EB',
|
||||
|
@ -1066,7 +1077,7 @@ nf.ControllerService = (function () {
|
|||
handler: {
|
||||
click: closeModal
|
||||
}
|
||||
});
|
||||
}];
|
||||
|
||||
// show the dialog
|
||||
$('#disable-controller-service-dialog').modal('setButtonModel', buttons).modal('show');
|
||||
|
@ -1197,6 +1208,17 @@ nf.ControllerService = (function () {
|
|||
}]);
|
||||
};
|
||||
|
||||
// ensure we have access to all referencing components before attempting the sequence
|
||||
if (hasUnauthorizedReferencingComponent(controllerService.referencingComponents)) {
|
||||
setCloseButton();
|
||||
|
||||
nf.Dialog.showOkDialog({
|
||||
headerText: 'Controller Service',
|
||||
dialogContent: 'Unable to disable due to unauthorized referencing components.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$('#disable-progress-label').text('Steps to disable ' + controllerService.name);
|
||||
var disableReferencingSchedulable = $('#disable-referencing-schedulable').addClass('ajax-loading');
|
||||
|
||||
|
@ -1247,6 +1269,31 @@ nf.ControllerService = (function () {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if any of the specified referencing components are not authorized.
|
||||
*
|
||||
* @param referencingComponents referencing components
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var hasUnauthorizedReferencingComponent = function (referencingComponents) {
|
||||
var hasUnauthorized = false;
|
||||
|
||||
$.each(referencingComponents, function (_, referencingComponentEntity) {
|
||||
if (referencingComponentEntity.permissions.canRead === false || referencingComponentEntity.permissions.canWrite === false) {
|
||||
hasUnauthorized = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
var referencingComponent = referencingComponentEntity.component;
|
||||
if (hasUnauthorizedReferencingComponent(referencingComponent.referencingComponents)) {
|
||||
hasUnauthorized = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return hasUnauthorized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the enable action of the enable controller service dialog.
|
||||
*
|
||||
|
@ -1263,26 +1310,9 @@ nf.ControllerService = (function () {
|
|||
var controllerServiceEntity = controllerServiceData.getItemById(controllerServiceId);
|
||||
var controllerService = controllerServiceEntity.component;
|
||||
|
||||
var hasUnauthorized = false;
|
||||
$.each(controllerService.referencingComponents, function (_, referencingComponent) {
|
||||
if (referencingComponent.permissions.canRead === false || referencingComponent.permissions.canWrite === false) {
|
||||
hasUnauthorized = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// determine if we want to also activate referencing components
|
||||
var scope = $('#enable-controller-service-scope').combo('getSelectedOption').value;
|
||||
|
||||
// ensure appropriate access
|
||||
if (scope === config.serviceAndReferencingComponents && hasUnauthorized) {
|
||||
nf.Dialog.showOkDialog({
|
||||
headerText: 'Controller Service',
|
||||
dialogContent: 'Unable to enable due to unauthorized referencing components.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// update visibility
|
||||
if (scope === config.serviceOnly) {
|
||||
$('#enable-controller-service-progress li.referencing-component').hide();
|
||||
|
@ -1331,6 +1361,17 @@ nf.ControllerService = (function () {
|
|||
}]);
|
||||
};
|
||||
|
||||
// ensure appropriate access
|
||||
if (scope === config.serviceAndReferencingComponents && hasUnauthorizedReferencingComponent(controllerService.referencingComponents)) {
|
||||
setCloseButton();
|
||||
|
||||
nf.Dialog.showOkDialog({
|
||||
headerText: 'Controller Service',
|
||||
dialogContent: 'Unable to enable due to unauthorized referencing components.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$('#enable-progress-label').text('Steps to enable ' + controllerService.name);
|
||||
var enableControllerService = $('#enable-controller-service').addClass('ajax-loading');
|
||||
|
||||
|
@ -1504,7 +1545,7 @@ nf.ControllerService = (function () {
|
|||
};
|
||||
|
||||
/**
|
||||
* Identifies descritpors that reference controller services.
|
||||
* Identifies descriptors that reference controller services.
|
||||
*
|
||||
* @param {object} component
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue