mirror of https://github.com/apache/nifi.git
NIFI-11122 Corrected provided parameter context inheritance after creation
This closes #6913 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
027e2b9bc1
commit
2609fd5f55
|
@ -348,7 +348,22 @@ public class StandardParameterProviderNode extends AbstractComponentNode impleme
|
||||||
if (groupConfiguration == null) {
|
if (groupConfiguration == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
reference.verifyCanSetParameters(getFetchedParameterUpdateMap(reference, groupConfiguration));
|
final Map<String, Parameter> parameterUpdates = getFetchedParameterUpdateMap(reference, groupConfiguration);
|
||||||
|
final Collection<String> removedParametersWithReferences = new HashSet<>();
|
||||||
|
for (final Map.Entry<String, Parameter> entry : parameterUpdates.entrySet()) {
|
||||||
|
final String parameterName = entry.getKey();
|
||||||
|
if (entry.getValue() == null) {
|
||||||
|
reference.getParameter(parameterName).ifPresent(currentParameter -> {
|
||||||
|
if (reference.hasReferencingComponents(currentParameter)) {
|
||||||
|
removedParametersWithReferences.add(parameterName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Any deletions of parameters with referencing components should be removed from consideration,
|
||||||
|
// since we do not remove provided parameters that are deleted until they are no longer referenced
|
||||||
|
removedParametersWithReferences.forEach(parameterUpdates::remove);
|
||||||
|
reference.verifyCanSetParameters(parameterUpdates);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
readLock.unlock();
|
readLock.unlock();
|
||||||
|
|
|
@ -640,7 +640,8 @@ public class StandardParameterContext implements ParameterContext {
|
||||||
// If a current parameter is not in the proposed parameters, it was effectively removed
|
// If a current parameter is not in the proposed parameters, it was effectively removed
|
||||||
if (!effectiveProposedParameters.containsKey(currentParameterDescriptor)) {
|
if (!effectiveProposedParameters.containsKey(currentParameterDescriptor)) {
|
||||||
final Parameter parameter = entry.getValue();
|
final Parameter parameter = entry.getValue();
|
||||||
if (parameter.isProvided() && hasReferencingComponents(parameter)) {
|
final boolean isParameterInherited = !parameter.getParameterContextId().equals(id);
|
||||||
|
if (!isParameterInherited && parameter.isProvided() && hasReferencingComponents(parameter)) {
|
||||||
logger.info("Provided parameter [{}] was removed from the source, but it is referenced by a component, so the parameter will be preserved",
|
logger.info("Provided parameter [{}] was removed from the source, but it is referenced by a component, so the parameter will be preserved",
|
||||||
currentParameterDescriptor.getName());
|
currentParameterDescriptor.getName());
|
||||||
} else {
|
} else {
|
||||||
|
@ -651,7 +652,8 @@ public class StandardParameterContext implements ParameterContext {
|
||||||
return effectiveParameterUpdates;
|
return effectiveParameterUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasReferencingComponents(final Parameter parameter) {
|
@Override
|
||||||
|
public boolean hasReferencingComponents(final Parameter parameter) {
|
||||||
if (parameter == null) {
|
if (parameter == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,6 +174,12 @@ public interface ParameterContext extends ParameterLookup, ComponentAuthorizable
|
||||||
*/
|
*/
|
||||||
List<String> getInheritedParameterContextNames();
|
List<String> getInheritedParameterContextNames();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param parameter A parameter
|
||||||
|
* @return True if the parameter has referencing components
|
||||||
|
*/
|
||||||
|
boolean hasReferencingComponents(Parameter parameter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this ParameterContext inherits from the given parameter context, either
|
* Returns true if this ParameterContext inherits from the given parameter context, either
|
||||||
* directly or indirectly.
|
* directly or indirectly.
|
||||||
|
|
|
@ -337,7 +337,8 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final boolean hasProvidedParameters = parameters.stream()
|
final boolean hasProvidedParameters = parameters.stream()
|
||||||
.anyMatch(parameter -> parameter.getParameter().getProvided() != null && parameter.getParameter().getProvided());
|
.anyMatch(parameter -> parameter.getParameter().getProvided() != null && parameter.getParameter().getProvided()
|
||||||
|
&& !parameter.getParameter().getInherited());
|
||||||
if (hasProvidedParameters) {
|
if (hasProvidedParameters) {
|
||||||
throw new IllegalArgumentException(String.format("Provided Parameters may not be set on Context [%s] because its " +
|
throw new IllegalArgumentException(String.format("Provided Parameters may not be set on Context [%s] because its " +
|
||||||
"parameters can only be user-entered", parameterContextDTO.getName()));
|
"parameters can only be user-entered", parameterContextDTO.getName()));
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.nifi.web.dao.impl;
|
||||||
|
|
||||||
|
import org.apache.nifi.authorization.AuthorizationRequest;
|
||||||
|
import org.apache.nifi.authorization.AuthorizationResult;
|
||||||
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
|
import org.apache.nifi.authorization.user.NiFiUser;
|
||||||
|
import org.apache.nifi.authorization.user.NiFiUserDetails;
|
||||||
|
import org.apache.nifi.authorization.user.StandardNiFiUser;
|
||||||
|
import org.apache.nifi.controller.FlowController;
|
||||||
|
import org.apache.nifi.controller.flow.FlowManager;
|
||||||
|
import org.apache.nifi.parameter.Parameter;
|
||||||
|
import org.apache.nifi.parameter.ParameterContext;
|
||||||
|
import org.apache.nifi.parameter.ParameterDescriptor;
|
||||||
|
import org.apache.nifi.parameter.ParameterReferenceManager;
|
||||||
|
import org.apache.nifi.parameter.StandardParameterContext;
|
||||||
|
import org.apache.nifi.parameter.StandardParameterContextManager;
|
||||||
|
import org.apache.nifi.parameter.StandardParameterReferenceManager;
|
||||||
|
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||||
|
import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO;
|
||||||
|
import org.apache.nifi.web.api.dto.ParameterDTO;
|
||||||
|
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||||
|
import org.apache.nifi.web.api.entity.ParameterEntity;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public class TestStandardParameterContextDAO {
|
||||||
|
|
||||||
|
private StandardParameterContextDAO dao;
|
||||||
|
|
||||||
|
@Mock(answer = RETURNS_DEEP_STUBS)
|
||||||
|
private FlowController flowController;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Authentication authentication;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Authorizer authorizer;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
dao = new StandardParameterContextDAO();
|
||||||
|
dao.setFlowController(flowController);
|
||||||
|
dao.setAuthorizer(authorizer);
|
||||||
|
when(authorizer.authorize(any(AuthorizationRequest.class))).thenReturn(AuthorizationResult.approved());
|
||||||
|
|
||||||
|
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||||
|
securityContext.setAuthentication(authentication);
|
||||||
|
final NiFiUser user = new StandardNiFiUser.Builder().identity("user").build();
|
||||||
|
final NiFiUserDetails userDetail = new NiFiUserDetails(user);
|
||||||
|
when(authentication.getPrincipal()).thenReturn(userDetail);
|
||||||
|
|
||||||
|
final ParameterReferenceManager parameterReferenceManager = new StandardParameterReferenceManager(flowController.getFlowManager());
|
||||||
|
|
||||||
|
final FlowManager flowManager = flowController.getFlowManager();
|
||||||
|
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||||
|
when(flowManager.getParameterContextManager()).thenReturn(parameterContextLookup);
|
||||||
|
parameterContextLookup.addParameterContext(new StandardParameterContext.Builder().id("id")
|
||||||
|
.name("Context")
|
||||||
|
.parameterReferenceManager(parameterReferenceManager)
|
||||||
|
.build());
|
||||||
|
final ParameterContext inheritedContext = new StandardParameterContext.Builder().id("inherited-id")
|
||||||
|
.parameterReferenceManager(parameterReferenceManager)
|
||||||
|
.name("Inherited")
|
||||||
|
.build();
|
||||||
|
final Map<String, Parameter> parameters = new HashMap<>();
|
||||||
|
parameters.put("inherited-param", new Parameter(new ParameterDescriptor.Builder().name("inherited-param").build(),
|
||||||
|
"value", null, true));
|
||||||
|
inheritedContext.setParameters(parameters);
|
||||||
|
parameterContextLookup.addParameterContext(inheritedContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVerifyUpdateInheritedProvidedParameter() {
|
||||||
|
final ParameterContextDTO dto = new ParameterContextDTO();
|
||||||
|
dto.setId("id");
|
||||||
|
dto.setName("Context");
|
||||||
|
|
||||||
|
final List<ParameterContextReferenceEntity> refs = new ArrayList<>();
|
||||||
|
final ParameterContextReferenceEntity ref = new ParameterContextReferenceEntity();
|
||||||
|
ref.setId("inherited-id");
|
||||||
|
ref.setComponent(new ParameterContextReferenceDTO());
|
||||||
|
ref.getComponent().setId("inherited-id");
|
||||||
|
ref.getComponent().setName("Inherited");
|
||||||
|
refs.add(ref);
|
||||||
|
dto.setInheritedParameterContexts(refs);
|
||||||
|
|
||||||
|
// Updating a provided parameter that is inherited is allowed
|
||||||
|
dao.verifyUpdate(dto, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVerifyUpdateNonInheritedProvidedParameter() {
|
||||||
|
final ParameterContextDTO dto = new ParameterContextDTO();
|
||||||
|
dto.setId("id");
|
||||||
|
dto.setName("Context");
|
||||||
|
final Set<ParameterEntity> parameters = new HashSet<>();
|
||||||
|
final ParameterEntity parameter = new ParameterEntity();
|
||||||
|
parameter.setCanWrite(true);
|
||||||
|
final ParameterDTO parameterDto = new ParameterDTO();
|
||||||
|
parameterDto.setProvided(true);
|
||||||
|
parameterDto.setName("param");
|
||||||
|
parameterDto.setValue("value");
|
||||||
|
parameterDto.setInherited(false);
|
||||||
|
parameter.setParameter(parameterDto);
|
||||||
|
parameters.add(parameter);
|
||||||
|
dto.setParameters(parameters);
|
||||||
|
|
||||||
|
final List<ParameterContextReferenceEntity> refs = new ArrayList<>();
|
||||||
|
final ParameterContextReferenceEntity ref = new ParameterContextReferenceEntity();
|
||||||
|
ref.setId("inherited-id");
|
||||||
|
ref.setComponent(new ParameterContextReferenceDTO());
|
||||||
|
ref.getComponent().setId("inherited-id");
|
||||||
|
ref.getComponent().setName("Inherited");
|
||||||
|
refs.add(ref);
|
||||||
|
dto.setInheritedParameterContexts(refs);
|
||||||
|
|
||||||
|
|
||||||
|
// Updating a provided parameter that is not inherited should fail
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> dao.verifyUpdate(dto, true));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue