This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new 1431ab4 AMBARI-25006. Support component-level provision_action in Add
Service request (#2725)
1431ab4 is described below
commit 1431ab44887c2ff7f9e94f8fcb42e24e3ce33800
Author: Doroszlai, Attila <[email protected]>
AuthorDate: Thu Dec 20 15:56:46 2018 +0100
AMBARI-25006. Support component-level provision_action in Add Service
request (#2725)
---
.../AmbariCustomCommandExecutionHelper.java | 5 +-
.../controller/AmbariManagementControllerImpl.java | 12 +-
.../internal/HostComponentResourceProvider.java | 11 +-
.../controller/internal/ProvisionAction.java | 28 +-
.../internal/ServiceResourceProvider.java | 5 +-
.../server/controller/predicate/OrPredicate.java | 6 +
.../server/controller/predicate/Predicates.java | 50 ++++
.../ambari/server/topology/ProvisionStep.java | 87 ++++++
.../server/topology/addservice/AddServiceInfo.java | 24 +-
.../addservice/AddServiceOrchestrator.java | 17 +-
.../addservice}/AddServiceRequest.java | 165 +---------
.../server/topology/addservice/Component.java | 115 +++++++
.../ambari/server/topology/addservice/Host.java | 68 +++++
.../ProvisionActionPredicateBuilder.java | 331 +++++++++++++++++++++
.../topology/addservice/RequestValidator.java | 36 ++-
.../addservice/RequestValidatorFactory.java | 1 -
.../addservice/ResourceProviderAdapter.java | 57 ++--
.../ambari/server/topology/addservice/Service.java | 96 ++++++
.../addservice}/AddServiceRequestTest.java | 18 +-
.../ProvisionActionPredicateBuilderTest.java | 202 +++++++++++++
.../topology/addservice/RequestValidatorTest.java | 47 ++-
.../addservice/StackAdvisorAdapterTest.java | 33 +-
.../test/resources/add_service_api/request1.json | 3 +-
23 files changed, 1137 insertions(+), 280 deletions(-)
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index 52dd6ce..741f9e6 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -66,6 +66,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.internal.RequestOperationLevel;
import org.apache.ambari.server.controller.internal.RequestResourceFilter;
+import org.apache.ambari.server.controller.internal.RequestResourceProvider;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.metadata.ActionMetadata;
import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
@@ -450,8 +451,8 @@ public class AmbariCustomCommandExecutionHelper {
commandTimeout = Math.max(60, commandTimeout);
}
- if (requestParams != null && requestParams.containsKey("context")) {
- String requestContext = requestParams.get("context");
+ if (requestParams != null &&
requestParams.containsKey(RequestResourceProvider.CONTEXT)) {
+ String requestContext =
requestParams.get(RequestResourceProvider.CONTEXT);
if (StringUtils.isNotEmpty(requestContext) &&
requestContext.toLowerCase().contains("rolling-restart")) {
Config clusterEnvConfig =
cluster.getDesiredConfigByType("cluster-env");
if (clusterEnvConfig != null) {
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 36e2e14..82bd14f 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -127,6 +127,7 @@ import
org.apache.ambari.server.controller.internal.DeleteStatusMetaData;
import
org.apache.ambari.server.controller.internal.HostComponentResourceProvider;
import org.apache.ambari.server.controller.internal.RequestOperationLevel;
import org.apache.ambari.server.controller.internal.RequestResourceFilter;
+import org.apache.ambari.server.controller.internal.RequestResourceProvider;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.controller.internal.URLStreamProvider;
import
org.apache.ambari.server.controller.internal.WidgetLayoutResourceProvider;
@@ -276,11 +277,6 @@ public class AmbariManagementControllerImpl implements
AmbariManagementControlle
LoggerFactory.getLogger(AmbariManagementControllerImpl.class);
private final static Logger configChangeLog =
LoggerFactory.getLogger("configchange");
- /**
- * Property name of request context.
- */
- private static final String REQUEST_CONTEXT_PROPERTY = "context";
-
private static final Type hostAttributesType =
new TypeToken<Map<String, String>>() {}.getType();
@@ -2910,7 +2906,7 @@ public class AmbariManagementControllerImpl implements
AmbariManagementControlle
String clusterHostInfoJson =
StageUtils.getGson().toJson(clusterHostInfo);
Stage stage = createNewStage(requestStages.getLastStageId(), cluster,
- requestStages.getId(),
requestProperties.get(REQUEST_CONTEXT_PROPERTY),
+ requestStages.getId(),
requestProperties.get(RequestResourceProvider.CONTEXT),
"{}", null);
boolean skipFailure = false;
if (requestProperties.containsKey(Setting.SETTING_NAME_SKIP_FAILURE) &&
requestProperties.get(Setting.SETTING_NAME_SKIP_FAILURE).equalsIgnoreCase("true"))
{
@@ -3810,7 +3806,7 @@ public class AmbariManagementControllerImpl implements
AmbariManagementControlle
}
LOG.debug("Refresh include/exclude files action will be executed for " +
serviceMasterMap);
HashMap<String, String> requestProperties = new HashMap<>();
- requestProperties.put("context", "Update Include/Exclude Files for " +
serviceMasterMap.keySet().toString());
+ requestProperties.put(RequestResourceProvider.CONTEXT, "Update
Include/Exclude Files for " + serviceMasterMap.keySet().toString());
HashMap<String, String> params = new HashMap<>();
params.put(AmbariCustomCommandExecutionHelper.UPDATE_FILES_ONLY,
String.valueOf(isDecommission));
@@ -4164,7 +4160,7 @@ public class AmbariManagementControllerImpl implements
AmbariManagementControlle
String requestContext = "";
if (requestProperties != null) {
- requestContext = requestProperties.get(REQUEST_CONTEXT_PROPERTY);
+ requestContext = requestProperties.get(RequestResourceProvider.CONTEXT);
if (requestContext == null) {
// guice needs a non-null value as there is no way to mark this
parameter @Nullable
requestContext = "";
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
index 8ba2623..d223e55 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_INITIAL_INSTALL;
import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_INITIAL_START;
import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_PROPERTY;
+import static
org.apache.ambari.server.controller.internal.RequestResourceProvider.CONTEXT;
import java.util.ArrayList;
import java.util.Collection;
@@ -175,8 +176,8 @@ public class HostComponentResourceProvider extends
AbstractControllerResourcePro
public static final String SKIP_INSTALL_FOR_COMPONENTS =
"skipInstallForComponents";
public static final String DO_NOT_SKIP_INSTALL_FOR_COMPONENTS =
"dontSkipInstallForComponents";
public static final String ALL_COMPONENTS = "ALL";
- public static final String SKIP_INSTALL_FOR_ALL_COMPONENTS =
joinComponentList(ImmutableSet.of(ALL_COMPONENTS));
- public static final String DO_NOT_SKIP_INSTALL_FOR_ANY_COMPONENTS =
joinComponentList(ImmutableSet.of());
+ public static final String FOR_ALL_COMPONENTS =
joinComponentList(ImmutableSet.of(ALL_COMPONENTS));
+ public static final String FOR_NO_COMPONENTS =
joinComponentList(ImmutableSet.of());
/**
* maintenance state helper
@@ -394,7 +395,7 @@ public class HostComponentResourceProvider extends
AbstractControllerResourcePro
installProperties.put(DESIRED_STATE, "INSTALLED");
Map<String, String> requestInfo = new HashMap<>();
- requestInfo.put("context", String.format("Install components on host %s",
hostname));
+ requestInfo.put(CONTEXT, String.format("Install components on host %s",
hostname));
requestInfo.put(CLUSTER_PHASE_PROPERTY, CLUSTER_PHASE_INITIAL_INSTALL);
// although the operation is really for a specific host, the level needs
to be set to HostComponent
// to make sure that any service in maintenance mode does not prevent
install/start on the new host during scale-up
@@ -452,7 +453,7 @@ public class HostComponentResourceProvider extends
AbstractControllerResourcePro
CLUSTER_PHASE_INITIAL_INSTALL.equals(requestProperties.get(CLUSTER_PHASE_PROPERTY))
&&
skipInstallForComponents != null &&
(skipInstallForComponents.contains(searchString) ||
- (skipInstallForComponents.equals(SKIP_INSTALL_FOR_ALL_COMPONENTS) &&
+ (skipInstallForComponents.equals(FOR_ALL_COMPONENTS) &&
!requestProperties.get(DO_NOT_SKIP_INSTALL_FOR_COMPONENTS).contains(searchString))
);
}
@@ -470,7 +471,7 @@ public class HostComponentResourceProvider extends
AbstractControllerResourcePro
UnsupportedPropertyException, NoSuchParentResourceException {
Map<String, String> requestInfo = new HashMap<>();
- requestInfo.put("context", String.format("Start components on host %s",
hostName));
+ requestInfo.put(CONTEXT, String.format("Start components on host %s",
hostName));
requestInfo.put(CLUSTER_PHASE_PROPERTY, CLUSTER_PHASE_INITIAL_START);
// see rationale for marking the operation as HostComponent-level at
"Install components on host"
requestInfo.putAll(RequestOperationLevel.propertiesFor(Resource.Type.HostComponent,
cluster));
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionAction.java
index 193f724..4c34dfc 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionAction.java
@@ -18,27 +18,33 @@
package org.apache.ambari.server.controller.internal;
+import java.util.List;
+
+import org.apache.ambari.server.topology.ProvisionStep;
+
+import com.google.common.collect.ImmutableList;
+
public enum ProvisionAction {
INSTALL_ONLY {
@Override
- public boolean skipStart() {
- return true;
+ public List<ProvisionStep> getSteps() {
+ return ImmutableList.of(ProvisionStep.INSTALL);
}
},
START_ONLY {
@Override
- public boolean skipInstall() {
- return true;
+ public List<ProvisionStep> getSteps() {
+ return ImmutableList.of(ProvisionStep.SKIP_INSTALL, ProvisionStep.START);
+ }
+ },
+ INSTALL_AND_START {
+ @Override
+ public List<ProvisionStep> getSteps() {
+ return ImmutableList.of(ProvisionStep.INSTALL, ProvisionStep.START);
}
},
- INSTALL_AND_START, // Default action
;
- public boolean skipInstall() {
- return false;
- }
+ public abstract List<ProvisionStep> getSteps();
- public boolean skipStart() {
- return false;
- }
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
index 751ca0e..7d0ec62 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
@@ -39,8 +39,6 @@ import org.apache.ambari.server.ParentObjectNotFoundException;
import org.apache.ambari.server.RoleCommand;
import org.apache.ambari.server.ServiceNotFoundException;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
-import org.apache.ambari.server.controller.AddServiceRequest;
-import org.apache.ambari.server.controller.AddServiceRequest.OperationType;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.MaintenanceStateHelper;
@@ -80,6 +78,7 @@ import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.topology.STOMPComponentsDeleteHandler;
import org.apache.ambari.server.topology.addservice.AddServiceOrchestrator;
+import org.apache.ambari.server.topology.addservice.AddServiceRequest;
import org.apache.ambari.server.utils.LoggingPreconditions;
import org.apache.ambari.spi.RepositoryType;
import org.apache.commons.collections.CollectionUtils;
@@ -1235,7 +1234,7 @@ public class ServiceResourceProvider extends
AbstractControllerResourceProvider
}
private static boolean isAddServiceRequest(Map<String, Object> properties) {
- return
OperationType.ADD_SERVICE.name().equals(properties.get(OPERATION_TYPE));
+ return
AddServiceRequest.OperationType.ADD_SERVICE.name().equals(properties.get(OPERATION_TYPE));
}
private RequestStatusResponse processAddServiceRequest(Map<String, Object>
requestProperties, Map<String, String> requestInfoProperties) throws
NoSuchParentResourceException {
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/OrPredicate.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/OrPredicate.java
index ab96cdf..d0c43d3 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/OrPredicate.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/OrPredicate.java
@@ -21,6 +21,8 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import javax.annotation.Nonnull;
+
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Resource;
@@ -40,6 +42,10 @@ public class OrPredicate extends ArrayPredicate {
}
public static Predicate instance(Predicate... predicates) {
+ return of(Arrays.asList(predicates));
+ }
+
+ public static Predicate of(@Nonnull Iterable<? extends Predicate>
predicates) {
List<Predicate> predicateList = new LinkedList<>();
// Simplify the predicate array
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/Predicates.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/Predicates.java
new file mode 100644
index 0000000..dde91ca
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/predicate/Predicates.java
@@ -0,0 +1,50 @@
+/*
+ * 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.ambari.server.controller.predicate;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.apache.ambari.server.controller.spi.Predicate;
+
+public class Predicates {
+
+ /**
+ * Creates an {@link OrPredicate} of the given predicates if any.
+ *
+ * @param predicates collection of predicates to be OR-ed
+ * @return {@link Optional} of the {@code OrPredicate} if any predicates are
given,
+ * otherwise an empty {@code Optional}
+ */
+ public static Optional<Predicate> anyOf(Collection<? extends Predicate>
predicates) {
+ return predicates != null && !predicates.isEmpty() ?
Optional.of(OrPredicate.of(predicates)) : Optional.empty();
+ }
+
+ /**
+ * Creates a {@link Function} which, when called, creates an {@link
AndPredicate} of
+ * its input and the {@code presetPredicate}. The function can then be used
to transform
+ * {@code Optional}s or streams.
+ *
+ * @param presetPredicate this predicate will be AND-ed with the input to
the {@code Function}
+ * @return the {@code Function}
+ */
+ public static Function<Predicate, Predicate> and(Predicate presetPredicate) {
+ return predicate -> new AndPredicate(presetPredicate, predicate);
+ }
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionStep.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionStep.java
new file mode 100644
index 0000000..3e649bbb
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/ProvisionStep.java
@@ -0,0 +1,87 @@
+/*
+ * 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.ambari.server.topology;
+
+import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_INITIAL_INSTALL;
+import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_INITIAL_START;
+import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_PROPERTY;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.DO_NOT_SKIP_INSTALL_FOR_COMPONENTS;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.FOR_ALL_COMPONENTS;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.FOR_NO_COMPONENTS;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.SKIP_INSTALL_FOR_COMPONENTS;
+
+import java.util.Map;
+
+import org.apache.ambari.server.state.State;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Steps of service provisioning.
+ */
+public enum ProvisionStep {
+
+ INSTALL {
+ @Override
+ public State getDesiredStateToSet() {
+ return State.INSTALLED;
+ }
+
+ @Override
+ public Map<String, String> getProvisionProperties() {
+ return ImmutableMap.of(CLUSTER_PHASE_PROPERTY,
CLUSTER_PHASE_INITIAL_INSTALL);
+ }
+ },
+
+ /**
+ * This special step is used for START_ONLY services/components, because
state
+ * transition cannot skip INSTALLED in the INIT -> INSTALLED -> STARTED
sequence.
+ */
+ SKIP_INSTALL {
+ @Override
+ public State getDesiredStateToSet() {
+ return State.INSTALLED;
+ }
+
+ @Override
+ public Map<String, String> getProvisionProperties() {
+ return ImmutableMap.of(
+ SKIP_INSTALL_FOR_COMPONENTS, FOR_ALL_COMPONENTS,
+ DO_NOT_SKIP_INSTALL_FOR_COMPONENTS, FOR_NO_COMPONENTS,
+ CLUSTER_PHASE_PROPERTY, CLUSTER_PHASE_INITIAL_INSTALL
+ );
+ }
+ },
+
+ START {
+ @Override
+ public State getDesiredStateToSet() {
+ return State.STARTED;
+ }
+
+ @Override
+ public Map<String, String> getProvisionProperties() {
+ return ImmutableMap.of(CLUSTER_PHASE_PROPERTY,
CLUSTER_PHASE_INITIAL_START);
+ }
+ },
+ ;
+
+ public abstract State getDesiredStateToSet();
+ public abstract Map<String, String> getProvisionProperties();
+
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceInfo.java
index 25b9a3b..1d675e5 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceInfo.java
@@ -23,7 +23,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import org.apache.ambari.server.controller.AddServiceRequest;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.controller.internal.Stack;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
@@ -46,13 +45,24 @@ public final class AddServiceInfo {
public AddServiceInfo(
AddServiceRequest request,
String clusterName,
+ RequestStageContainer stages,
Stack stack,
Configuration config,
- KerberosDescriptor kerberosDescriptor,
+ Map<String, Map<String, Set<String>>> newServices
+ ) {
+ this(request, clusterName, stages, stack, config, newServices, null, null);
+ }
+
+ AddServiceInfo(
+ AddServiceRequest request,
+ String clusterName,
RequestStageContainer stages,
- Map<String, Map<String,
- Set<String>>> newServices,
- LayoutRecommendationInfo recommendationInfo) {
+ Stack stack,
+ Configuration config,
+ Map<String, Map<String, Set<String>>> newServices,
+ KerberosDescriptor kerberosDescriptor,
+ LayoutRecommendationInfo recommendationInfo
+ ) {
this.request = request;
this.clusterName = clusterName;
this.stack = stack;
@@ -65,11 +75,11 @@ public final class AddServiceInfo {
public AddServiceInfo withLayoutRecommendation(Map<String, Map<String,
Set<String>>> services,
LayoutRecommendationInfo
recommendation) {
- return new AddServiceInfo(request, clusterName, stack, config,
kerberosDescriptor, stages, services, recommendation);
+ return new AddServiceInfo(request, clusterName, stages, stack, config,
services, kerberosDescriptor, recommendation);
}
public AddServiceInfo withConfig(Configuration newConfig) {
- return new AddServiceInfo(request, clusterName, stack, newConfig,
kerberosDescriptor, stages, newServices, recommendationInfo);
+ return new AddServiceInfo(request, clusterName, stages, stack, newConfig,
newServices, kerberosDescriptor, recommendationInfo);
}
@Override
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceOrchestrator.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceOrchestrator.java
index 4ff1301..6eed1af 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceOrchestrator.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceOrchestrator.java
@@ -28,7 +28,6 @@ import javax.inject.Singleton;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.RequestFactory;
-import org.apache.ambari.server.controller.AddServiceRequest;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.RequestStatusResponse;
@@ -41,6 +40,7 @@ import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.ProvisionStep;
import org.apache.ambari.server.utils.LoggingPreconditions;
import org.apache.ambari.server.utils.StageUtils;
import org.slf4j.Logger;
@@ -160,9 +160,8 @@ public class AddServiceOrchestrator {
resourceProviders.createComponents(request);
resourceProviders.updateServiceDesiredState(request, State.INSTALLED);
- if (!request.getRequest().getProvisionAction().skipStart()) {
- resourceProviders.updateServiceDesiredState(request, State.STARTED);
- }
+ resourceProviders.updateServiceDesiredState(request, State.STARTED);
+
resourceProviders.createHostComponents(request);
configureKerberos(request, cluster, existingServices);
@@ -195,11 +194,13 @@ public class AddServiceOrchestrator {
}
private void createHostTasks(AddServiceInfo request) {
- LOG.info("Creating host tasks for {}: {}", request,
request.getRequest().getProvisionAction());
+ LOG.info("Creating host tasks for {}", request);
- resourceProviders.updateHostComponentDesiredState(request,
State.INSTALLED);
- if (!request.getRequest().getProvisionAction().skipStart()) {
- resourceProviders.updateHostComponentDesiredState(request,
State.STARTED);
+ ProvisionActionPredicateBuilder predicates = new
ProvisionActionPredicateBuilder(request);
+ for (ProvisionStep step : ProvisionStep.values()) {
+ predicates.getPredicate(step).ifPresent(predicate ->
+ resourceProviders.updateHostComponentDesiredState(request, predicate,
step)
+ );
}
try {
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceRequest.java
similarity index 72%
rename from
ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java
rename to
ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceRequest.java
index e169f82..e2148e0 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/AddServiceRequest.java
@@ -16,11 +16,10 @@
* limitations under the License.
*/
-package org.apache.ambari.server.controller;
+package org.apache.ambari.server.topology.addservice;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toMap;
-import static java.util.stream.Collectors.toSet;
import static
org.apache.ambari.server.controller.internal.BaseClusterRequest.PROVISION_ACTION_PROPERTY;
import static
org.apache.ambari.server.controller.internal.ClusterResourceProvider.CREDENTIALS;
import static
org.apache.ambari.server.controller.internal.ClusterResourceProvider.SECURITY;
@@ -30,9 +29,7 @@ import static
org.apache.ambari.server.topology.Configurable.CONFIGURATIONS;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -104,25 +101,6 @@ public class AddServiceRequest {
@JsonProperty(CREDENTIALS) Set<Credential> credentials,
@JsonProperty(CONFIGURATIONS) Collection<? extends Map<String, ?>> configs
) {
- this(operationType, recommendationStrategy, provisionAction,
validationType, stackName, stackVersion, services, components,
- security, credentials,
- ConfigurableHelper.parseConfigs(configs)
- );
- }
-
- private AddServiceRequest(
- OperationType operationType,
- ConfigRecommendationStrategy recommendationStrategy,
- ProvisionAction provisionAction,
- ValidationType validationType,
- String stackName,
- String stackVersion,
- Set<Service> services,
- Set<Component> components,
- SecurityConfiguration security,
- Set<Credential> credentials,
- Configuration configuration
- ) {
this.operationType = null != operationType ? operationType :
OperationType.ADD_SERVICE;
this.recommendationStrategy = null != recommendationStrategy ?
recommendationStrategy : ConfigRecommendationStrategy.defaultForAddService();
this.provisionAction = null != provisionAction ? provisionAction :
ProvisionAction.INSTALL_AND_START;
@@ -132,7 +110,7 @@ public class AddServiceRequest {
this.services = null != services ? services : emptySet();
this.components = null != components ? components : emptySet();
this.security = security;
- this.configuration = null != configuration ? configuration : new
Configuration(new HashMap<>(), new HashMap<>());
+ this.configuration = null != configs ?
ConfigurableHelper.parseConfigs(configs) : Configuration.newEmpty();
this.credentials = null != credentials
? credentials.stream().collect(toMap(Credential::getAlias,
Function.identity()))
: ImmutableMap.of();
@@ -312,143 +290,4 @@ public class AddServiceRequest {
public abstract boolean strictValidation();
}
- public static final class Component {
-
- static final String COMPONENT_NAME = "name";
- static final String HOSTS = "hosts";
-
- private final String name;
- private final Set<Host> hosts;
-
- @JsonCreator
- public Component(@JsonProperty(COMPONENT_NAME) String name,
@JsonProperty(HOSTS) Set<Host> hosts) {
- this.name = name;
- this.hosts = hosts != null ? ImmutableSet.copyOf(hosts) :
ImmutableSet.of();
- }
-
- public static Component of(String name, String... hosts) {
- return new Component(name,
Arrays.stream(hosts).map(Host::new).collect(toSet()));
- }
-
- @JsonProperty(COMPONENT_NAME)
- @ApiModelProperty(name = COMPONENT_NAME)
- public String getName() {
- return name;
- }
-
- @JsonProperty(HOSTS)
- @ApiModelProperty(name = HOSTS)
- public Set<Host> getHosts() {
- return hosts;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- Component other = (Component) o;
-
- return Objects.equals(name, other.name) &&
- Objects.equals(hosts, other.hosts);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, hosts);
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- public static final class Host {
-
- static final String FQDN = "fqdn";
-
- private final String fqdn;
-
- @JsonCreator
- public Host(@JsonProperty(FQDN) String fqdn) {
- this.fqdn = fqdn;
- }
-
- @JsonProperty(FQDN)
- @ApiModelProperty(name = FQDN)
- public String getFqdn() {
- return fqdn;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- Host other = (Host) o;
-
- return Objects.equals(fqdn, other.fqdn);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(fqdn);
- }
-
- @Override
- public String toString() {
- return "host: " + fqdn;
- }
-
- }
-
- @ApiModel
- public static final class Service {
-
- static final String NAME = "name";
-
- private final String name;
-
- @JsonCreator
- public Service(@JsonProperty(NAME) String name) {
- this.name = name;
- }
-
- public static Service of(String name) {
- return new Service(name);
- }
-
- @JsonProperty(NAME)
- @ApiModelProperty(name = NAME)
- public String getName() {
- return name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Service service = (Service) o;
- return Objects.equals(name, service.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name);
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Component.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Component.java
new file mode 100644
index 0000000..d467b68
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Component.java
@@ -0,0 +1,115 @@
+/*
+ * 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.ambari.server.topology.addservice;
+
+import static java.util.stream.Collectors.toSet;
+import static
org.apache.ambari.server.controller.internal.BaseClusterRequest.PROVISION_ACTION_PROPERTY;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.ambari.annotations.ApiIgnore;
+import org.apache.ambari.server.controller.internal.ProvisionAction;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableSet;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public final class Component {
+
+ private static final String COMPONENT_NAME = "name";
+ private static final String HOSTS = "hosts";
+
+ private final String name;
+ private final Set<Host> hosts;
+ private final ProvisionAction provisionAction;
+
+ @JsonCreator
+ public Component(
+ @JsonProperty(COMPONENT_NAME) String name,
+ @JsonProperty(PROVISION_ACTION_PROPERTY) ProvisionAction provisionAction,
+ @JsonProperty(HOSTS) Set<Host> hosts
+ ) {
+ this.name = name;
+ this.provisionAction = provisionAction;
+ this.hosts = hosts != null ? ImmutableSet.copyOf(hosts) :
ImmutableSet.of();
+ }
+
+ public static Component of(String name, String... hosts) {
+ return of(name, null, hosts);
+ }
+
+ public static Component of(String name, ProvisionAction provisionAction,
String... hosts) {
+ return new Component(name, provisionAction,
Arrays.stream(hosts).map(Host::new).collect(toSet()));
+ }
+
+ @JsonProperty(COMPONENT_NAME)
+ @ApiModelProperty(name = COMPONENT_NAME)
+ public String getName() {
+ return name;
+ }
+
+ @JsonProperty(HOSTS)
+ @ApiModelProperty(name = HOSTS)
+ public Set<Host> getHosts() {
+ return hosts;
+ }
+
+ @JsonProperty(PROVISION_ACTION_PROPERTY)
+ @ApiModelProperty(name = PROVISION_ACTION_PROPERTY)
+ public ProvisionAction _getProvisionAction() {
+ return provisionAction;
+ }
+
+ @ApiIgnore
+ @JsonIgnore
+ public Optional<ProvisionAction> getProvisionAction() {
+ return Optional.ofNullable(provisionAction);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Component other = (Component) o;
+
+ return Objects.equals(name, other.name) &&
+ Objects.equals(hosts, other.hosts) &&
+ Objects.equals(provisionAction, other.provisionAction);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, hosts, provisionAction);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Host.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Host.java
new file mode 100644
index 0000000..3392a80
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Host.java
@@ -0,0 +1,68 @@
+/*
+ * 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.ambari.server.topology.addservice;
+
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public final class Host {
+
+ private static final String FQDN = "fqdn";
+
+ private final String fqdn;
+
+ @JsonCreator
+ public Host(@JsonProperty(FQDN) String fqdn) {
+ this.fqdn = fqdn;
+ }
+
+ @JsonProperty(FQDN)
+ @ApiModelProperty(name = FQDN)
+ public String getFqdn() {
+ return fqdn;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Host other = (Host) o;
+
+ return Objects.equals(fqdn, other.fqdn);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(fqdn);
+ }
+
+ @Override
+ public String toString() {
+ return "host: " + fqdn;
+ }
+
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilder.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilder.java
new file mode 100644
index 0000000..26c8ea4
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilder.java
@@ -0,0 +1,331 @@
+/*
+ * 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.ambari.server.topology.addservice;
+
+import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.CLUSTER_NAME;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.COMPONENT_NAME;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.HOST_NAME;
+import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.SERVICE_NAME;
+import static org.apache.ambari.server.controller.predicate.Predicates.and;
+import static org.apache.ambari.server.controller.predicate.Predicates.anyOf;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+
+import org.apache.ambari.server.controller.internal.ProvisionAction;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.topology.ProvisionStep;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+/**
+ * Builds predicates to be used in the "update host component state" requests,
one for each {@link ProvisionStep}.
+ *
+ * By default all components are both installed and started (except client
components, but that exception is handled in
+ * HostComponentResourceProvider, not here). This can be customized at the
request-, service-, and component levels in
+ * the Add Service request. Actions are inherited at the lower levels, so the
request-level action applies to all
+ * services that have no custom action given, and the effective service-level
action applies to all components of the
+ * given service with similar restriction. The request and each service can
specify exactly one {@code ProvisionAction},
+ * but at the component level the same component may have different action for
groups of hosts.
+ *
+ * The predicates need to filter by service name (to avoid affecting existing
services), and apply any component-level
+ * overrides by further checking for component name and host name.
+ *
+ * Example:
+ * <pre>
+ * cluster_name=TEST
+ * AND
+ * (
+ * (
+ * service_name=AMBARI_METRICS
+ * AND
+ * (
+ * component_name=METRICS_MONITOR
+ * OR
+ * component_name=METRICS_COLLECTOR
+ * )
+ * )
+ * OR
+ * (
+ * service_name=KAFKA
+ * AND
+ * (
+ * component_name=KAFKA_BROKER
+ * AND
+ * host_name=c7402
+ * )
+ * )
+ * )
+ * </pre>
+ */
+public class ProvisionActionPredicateBuilder {
+
+ private final Map<ProvisionStep, Predicate> predicates = new
EnumMap<>(ProvisionStep.class);
+ private final AddServiceInfo request;
+ private final Map<String, ProvisionAction> customServiceActions;
+ private final Map<String, Map<String, Map<ProvisionAction, Set<String>>>>
customComponentActions;
+ private final Map<ProvisionStep, List<Predicate>> servicePredicatesByStep;
+
+ public ProvisionActionPredicateBuilder(AddServiceInfo request) {
+ this.request = request;
+
+ customServiceActions = findServicesWithCustomAction();
+ customComponentActions = findComponentsWithCustomAction();
+ servicePredicatesByStep = createServicePredicates();
+ createGlobalPredicates();
+ }
+
+ public Optional<Predicate> getPredicate(ProvisionStep action) {
+ return Optional.ofNullable(predicates.get(action));
+ }
+
+ /**
+ * Creates a "global" predicate for each {@link ProvisionStep} in the form
of:
+ * cluster_name=... AND (service1 predicate OR service2 predicate OR ...)
+ */
+ private void createGlobalPredicates() {
+ Preconditions.checkState(servicePredicatesByStep != null);
+
+ Function<Predicate, Predicate> andClusterNameMatches =
and(clusterNameIs(request.clusterName()));
+ for (Map.Entry<ProvisionStep, List<Predicate>> entry :
servicePredicatesByStep.entrySet()) {
+ ProvisionStep step = entry.getKey();
+ List<Predicate> servicePredicates = entry.getValue();
+ anyOf(servicePredicates).map(andClusterNameMatches).ifPresent(predicate
-> predicates.put(step, predicate));
+ }
+ }
+
+ /**
+ * Creates predicates for each service for each {@link ProvisionStep} as
necessary.
+ *
+ * @return step -> service predicates map
+ */
+ private Map<ProvisionStep, List<Predicate>> createServicePredicates() {
+ Preconditions.checkState(customServiceActions != null);
+ Preconditions.checkState(customComponentActions != null);
+
+ ProvisionAction requestAction = request.getRequest().getProvisionAction();
+ Map<ProvisionStep, List<Predicate>> servicePredicatesByStep = new
EnumMap<>(ProvisionStep.class);
+
+ for (Map.Entry<String, Map<String, Set<String>>> serviceEntry :
request.newServices().entrySet()) {
+ String serviceName = serviceEntry.getKey();
+ Map<String, Set<String>> hostsByComponent = serviceEntry.getValue();
+
+ ProvisionAction serviceAction =
customServiceActions.getOrDefault(serviceName, requestAction);
+ Predicate serviceNamePredicate = serviceNameIs(serviceName);
+
+ Map<String, Map<ProvisionAction, Set<String>>> customActionByComponent =
customComponentActions.get(serviceName);
+ if (customActionByComponent == null) {
+ classifyItem(serviceAction, serviceNamePredicate,
servicePredicatesByStep);
+ } else {
+ Map<ProvisionStep, List<Predicate>> componentPredicatesByStep =
+ createComponentPredicates(serviceAction, hostsByComponent,
customActionByComponent);
+
+ applyComponentOverrides(servicePredicatesByStep, serviceNamePredicate,
componentPredicatesByStep);
+ }
+ }
+ return servicePredicatesByStep;
+ }
+
+ /**
+ * Creates a service-level predicate for each step in the form of:
+ * <pre>service_name=... AND (component1 predicate OR component2 predicate
OR ...)</pre>
+ * The result is appended to the list of predicates corresponding to each
step in {@code servicePredicatesByStep}.
+ *
+ * @param servicePredicatesByStep step -> service predicates
+ * @param serviceNamePredicate predicate for service_name=...
+ * @param componentPredicatesByStep step -> component predicates
+ */
+ private static void applyComponentOverrides(
+ Map<ProvisionStep, List<Predicate>> servicePredicatesByStep,
+ Predicate serviceNamePredicate,
+ Map<ProvisionStep, List<Predicate>> componentPredicatesByStep
+ ) {
+ Function<Predicate, Predicate> andServiceNameMatches =
and(serviceNamePredicate);
+ for (Map.Entry<ProvisionStep, List<Predicate>> entry :
componentPredicatesByStep.entrySet()) {
+ ProvisionStep step = entry.getKey();
+ List<Predicate> componentPredicates = entry.getValue();
+
anyOf(componentPredicates).map(andServiceNameMatches).ifPresent(predicate ->
+ servicePredicatesByStep.computeIfAbsent(step, __ -> new
LinkedList<>()).add(predicate)
+ );
+ }
+ }
+
+ /**
+ * Creates predicates for each component with custom action (one that does
not match its parent service's action).
+ *
+ * @param serviceAction service-level action
+ * @param hostsByComponent component -> hosts map (all hosts, including ones
for which no custom action was specified)
+ * @param customActionByComponent component -> action -> hosts mapping;
+ * only contains components whose action does not match the upper-level
(service or request) action
+ * @return step -> component predicates map
+ */
+ private static Map<ProvisionStep, List<Predicate>> createComponentPredicates(
+ ProvisionAction serviceAction,
+ Map<String, Set<String>> hostsByComponent,
+ Map<String, Map<ProvisionAction, Set<String>>> customActionByComponent
+ ) {
+ Map<ProvisionStep, List<Predicate>> componentPredicatesByStep = new
EnumMap<>(ProvisionStep.class);
+
+ for (Map.Entry<String, Set<String>> componentEntry :
hostsByComponent.entrySet()) {
+ String componentName = componentEntry.getKey();
+ Set<String> allHosts = componentEntry.getValue();
+ Map<ProvisionAction, Set<String>> hostsByAction =
customActionByComponent.getOrDefault(componentName, ImmutableMap.of());
+
+ if (!hostsByAction.isEmpty()) {
+ Set<String> customActionHosts = new HashSet<>();
+ for (Map.Entry<ProvisionAction, Set<String>> e :
hostsByAction.entrySet()) {
+ ProvisionAction componentAction = e.getKey();
+ Set<String> hosts = e.getValue();
+
+ Predicate componentPredicate =
predicateForComponentHosts(componentName, hosts);
+ classifyItem(componentAction, componentPredicate,
componentPredicatesByStep);
+
+ customActionHosts.addAll(hosts);
+ }
+
+ // apply service-level action to any hosts for which no explicit
action was specified
+ Set<String> leftoverHosts =
ImmutableSet.copyOf(Sets.difference(allHosts, customActionHosts));
+ if (!leftoverHosts.isEmpty()) {
+ Predicate componentPredicate =
predicateForComponentHosts(componentName, leftoverHosts);
+ classifyItem(serviceAction, componentPredicate,
componentPredicatesByStep);
+ }
+ } else {
+ Predicate componentPredicate = componentNameIs(componentName);
+ classifyItem(serviceAction, componentPredicate,
componentPredicatesByStep);
+ }
+ }
+ return componentPredicatesByStep;
+ }
+
+ /**
+ * Maps services in the request by component.
+ *
+ * @return component -> service map
+ */
+ private Map<String, String> mapServicesByComponent() {
+ Map<String, String> serviceByComponent = new HashMap<>();
+ for (Map.Entry<String, Map<String, Set<String>>> e :
request.newServices().entrySet()) {
+ String service = e.getKey();
+ for (String component : e.getValue().keySet()) {
+ serviceByComponent.put(component, service);
+ }
+ }
+ return serviceByComponent;
+ }
+
+ /**
+ * Finds all services for which custom provision action was specified in the
request.
+ *
+ * @return service -> action map; only contains services whose action does
not match the request-level action
+ */
+ private Map<String, ProvisionAction> findServicesWithCustomAction() {
+ ProvisionAction requestAction = request.getRequest().getProvisionAction();
+ return request.getRequest().getServices().stream()
+ .filter(service -> service.getProvisionAction().isPresent())
+ .filter(service -> !Objects.equals(requestAction,
service.getProvisionAction().get()))
+ .collect(toMap(Service::getName, service ->
service.getProvisionAction().get()));
+ }
+
+ /**
+ * Finds all host components for which custom provision action was specified
in the request.
+ *
+ * @return service -> component -> action -> hosts mapping; only contains
components whose action does not match the upper-level (service or request)
action
+ */
+ private Map<String, Map<String, Map<ProvisionAction, Set<String>>>>
findComponentsWithCustomAction() {
+ Preconditions.checkState(customServiceActions != null);
+
+ Map<String, String> serviceByComponent = mapServicesByComponent();
+
+ Map<String, Map<String, Map<ProvisionAction, Set<String>>>> result = new
HashMap<>();
+ for (Component component : request.getRequest().getComponents()) {
+ component.getProvisionAction().ifPresent(componentAction -> {
+ String componentName = component.getName();
+ String serviceName = serviceByComponent.get(componentName);
+ ProvisionAction serviceAction =
customServiceActions.getOrDefault(serviceName,
request.getRequest().getProvisionAction());
+ if (!Objects.equals(serviceAction, componentAction)) {
+ result
+ .computeIfAbsent(serviceName, __ -> new HashMap<>())
+ .computeIfAbsent(componentName, __ -> new
EnumMap<>(ProvisionAction.class))
+ .computeIfAbsent(componentAction, __ -> new HashSet<>())
+
.addAll(component.getHosts().stream().map(Host::getFqdn).collect(toSet()));
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Adds {@code item} to the list(s) it belongs to depending on {@code
action}'s steps.
+ * For example if {@code action} is {@link
ProvisionAction#INSTALL_AND_START}, then the
+ * {@code item} is added to both {@link ProvisionStep#INSTALL} and {@link
ProvisionStep#START}
+ * lists, but not to the list for {@link ProvisionStep#SKIP_INSTALL}.
+ *
+ * @param action provision action
+ * @param item the item to add
+ * @param itemsByStep step -> list of items
+ */
+ private static <T> void classifyItem(ProvisionAction action, T item,
Map<ProvisionStep, List<T>> itemsByStep) {
+ for (ProvisionStep step : action.getSteps()) {
+ itemsByStep.computeIfAbsent(step, __ -> new LinkedList<>()).add(item);
+ }
+ }
+
+ /**
+ * Creates a predicate in the form of:
+ * <pre>component_name=... AND (host_name=... OR host_name=... OR ...)</pre>
+ *
+ * @param componentName component name
+ * @param hosts set of host names
+ */
+ private static Predicate predicateForComponentHosts(String componentName,
Set<String> hosts) {
+ Preconditions.checkNotNull(hosts);
+ Preconditions.checkArgument(!hosts.isEmpty());
+ Set<Predicate> hostPredicates =
hosts.stream().map(ProvisionActionPredicateBuilder::hostnameIs).collect(toSet());
+ return
anyOf(hostPredicates).map(and(componentNameIs(componentName))).get();
+ }
+
+ private static Predicate clusterNameIs(String clusterName) {
+ return new EqualsPredicate<>(CLUSTER_NAME, clusterName);
+ }
+
+ private static Predicate serviceNameIs(String serviceName) {
+ return new EqualsPredicate<>(SERVICE_NAME, serviceName);
+ }
+
+ private static Predicate componentNameIs(String componentName) {
+ return new EqualsPredicate<>(COMPONENT_NAME, componentName);
+ }
+
+ private static Predicate hostnameIs(String hostname) {
+ return new EqualsPredicate<>(HOST_NAME, hostname);
+ }
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidator.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidator.java
index 29ac8c8..59302d1 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidator.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidator.java
@@ -17,11 +17,14 @@
*/
package org.apache.ambari.server.topology.addservice;
+import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -33,7 +36,6 @@ import javax.inject.Inject;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.RequestFactory;
-import org.apache.ambari.server.controller.AddServiceRequest;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.controller.internal.Stack;
@@ -53,7 +55,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.Multisets;
import com.google.common.collect.Sets;
import com.google.inject.assistedinject.Assisted;
@@ -116,9 +121,10 @@ public class RequestValidator {
CHECK.checkState(!serviceInfoCreated.getAndSet(true), "Can create only one
instance for each validated add service request");
RequestStageContainer stages = new
RequestStageContainer(actionManager.getNextRequestId(), null, requestFactory,
actionManager);
- AddServiceInfo validatedRequest = new AddServiceInfo(request,
cluster.getClusterName(),
- state.getStack(), state.getConfig(), state.getKerberosDescriptor(),
- stages, state.getNewServices(), null);
+ AddServiceInfo validatedRequest = new AddServiceInfo(request,
cluster.getClusterName(), stages,
+ state.getStack(), state.getConfig(), state.getNewServices(),
state.getKerberosDescriptor(),
+ null
+ );
stages.setRequestContext(validatedRequest.describe());
return validatedRequest;
}
@@ -206,11 +212,12 @@ public class RequestValidator {
void validateServicesAndComponents() {
Stack stack = state.getStack();
Map<String, Map<String, Set<String>>> newServices = new LinkedHashMap<>();
+ Map<String, Map<String, Multiset<String>>> withAllHosts = new
LinkedHashMap<>();
Set<String> existingServices = cluster.getServices().keySet();
// process service declarations
- for (AddServiceRequest.Service service : request.getServices()) {
+ for (Service service : request.getServices()) {
String serviceName = service.getName();
CHECK.checkArgument(stack.getServices().contains(serviceName),
@@ -222,7 +229,7 @@ public class RequestValidator {
}
// process component declarations
- for (AddServiceRequest.Component requestedComponent :
request.getComponents()) {
+ for (Component requestedComponent : request.getComponents()) {
String componentName = requestedComponent.getName();
String serviceName = stack.getServiceForComponent(componentName);
@@ -231,12 +238,27 @@ public class RequestValidator {
CHECK.checkArgument(!existingServices.contains(serviceName),
"Service %s (for component %s) already exists in cluster %s",
serviceName, componentName, cluster.getClusterName());
+ List<String> hosts =
requestedComponent.getHosts().stream().map(Host::getFqdn).collect(toList());
newServices.computeIfAbsent(serviceName, __ -> new HashMap<>())
- .put(componentName,
requestedComponent.getHosts().stream().map(AddServiceRequest.Host::getFqdn).collect(toSet()));
+ .computeIfAbsent(componentName, __ -> new HashSet<>())
+ .addAll(hosts);
+ withAllHosts.computeIfAbsent(serviceName, __ -> new HashMap<>())
+ .computeIfAbsent(componentName, __ -> HashMultiset.create())
+ .addAll(hosts);
}
CHECK.checkArgument(!newServices.isEmpty(), "Request should have at least
one new service or component to be added");
+ newServices.forEach(
+ (service, components) -> components.forEach(
+ (component, hosts) -> {
+ Multiset<String> allHosts = withAllHosts.get(service).get(component);
+ Multisets.removeOccurrences(allHosts, hosts);
+ CHECK.checkArgument(allHosts.isEmpty(), "Some hosts appear multiple
times for the same component (%s) in the request: %s", component, allHosts);
+ }
+ )
+ );
+
state = state.withNewServices(newServices);
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidatorFactory.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidatorFactory.java
index f23a9f8..95a6cb8 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidatorFactory.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/RequestValidatorFactory.java
@@ -17,7 +17,6 @@
*/
package org.apache.ambari.server.topology.addservice;
-import org.apache.ambari.server.controller.AddServiceRequest;
import org.apache.ambari.server.state.Cluster;
/**
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ResourceProviderAdapter.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ResourceProviderAdapter.java
index a33d617..95fcc17 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ResourceProviderAdapter.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ResourceProviderAdapter.java
@@ -19,11 +19,7 @@ package org.apache.ambari.server.topology.addservice;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
-import static
org.apache.ambari.server.controller.AmbariManagementControllerImpl.CLUSTER_PHASE_PROPERTY;
-import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.DO_NOT_SKIP_INSTALL_FOR_ANY_COMPONENTS;
-import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.DO_NOT_SKIP_INSTALL_FOR_COMPONENTS;
-import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.SKIP_INSTALL_FOR_ALL_COMPONENTS;
-import static
org.apache.ambari.server.controller.internal.HostComponentResourceProvider.SKIP_INSTALL_FOR_COMPONENTS;
+import static
org.apache.ambari.server.controller.internal.RequestResourceProvider.CONTEXT;
import java.util.List;
import java.util.Map;
@@ -37,15 +33,12 @@ import javax.inject.Singleton;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
import org.apache.ambari.server.controller.ClusterRequest;
import org.apache.ambari.server.controller.ConfigurationRequest;
import org.apache.ambari.server.controller.internal.ArtifactResourceProvider;
-import org.apache.ambari.server.controller.internal.ClusterResourceProvider;
import org.apache.ambari.server.controller.internal.ComponentResourceProvider;
import org.apache.ambari.server.controller.internal.CredentialResourceProvider;
import
org.apache.ambari.server.controller.internal.HostComponentResourceProvider;
-import org.apache.ambari.server.controller.internal.ProvisionAction;
import org.apache.ambari.server.controller.internal.RequestImpl;
import org.apache.ambari.server.controller.internal.RequestOperationLevel;
import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
@@ -64,13 +57,13 @@ import
org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
import org.apache.ambari.server.controller.utilities.PredicateBuilder;
-import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
import org.apache.ambari.server.topology.Credential;
+import org.apache.ambari.server.topology.ProvisionStep;
import org.apache.ambari.server.utils.LoggingPreconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -197,26 +190,30 @@ public class ResourceProviderAdapter {
Set<Map<String, Object>> properties = ImmutableSet.of(ImmutableMap.of(
ServiceResourceProvider.SERVICE_SERVICE_STATE_PROPERTY_ID,
desiredState.name()
));
- Map<String, String> requestInfo = createRequestInfo(request.clusterName(),
Resource.Type.Service).build();
- Predicate predicate = predicateForNewServices(request, "ServiceInfo");
+ Map<String, String> requestInfo =
RequestOperationLevel.propertiesFor(Resource.Type.Service,
request.clusterName());
+ Predicate predicate = predicateForNewServices(request);
updateResources(request, properties, Resource.Type.Service, predicate,
requestInfo);
}
- public void updateHostComponentDesiredState(AddServiceInfo request, State
desiredState) {
- LOG.info("Updating host component desired state to {} for {}",
desiredState, request);
+ public void updateHostComponentDesiredState(AddServiceInfo request,
Predicate predicate, ProvisionStep step) {
+ State desiredState = step.getDesiredStateToSet();
+ LOG.info("Updating host component desired state to {} per {} for {}",
desiredState, step, request);
+ LOG.debug("Using predicate {}", predicate);
Set<Map<String, Object>> properties = ImmutableSet.of(ImmutableMap.of(
HostComponentResourceProvider.STATE, desiredState.name(),
- "context", String.format("Put new components to %s state", desiredState)
+ CONTEXT, String.format("Put new components to %s state", desiredState)
));
- ImmutableMap.Builder<String, String> requestInfo =
createRequestInfo(request.clusterName(), Resource.Type.HostComponent);
- addProvisionProperties(requestInfo, desiredState,
request.getRequest().getProvisionAction());
+ Map<String, String> requestInfo = new ImmutableMap.Builder<String,
String>()
+ .putAll(RequestOperationLevel.propertiesFor(Resource.Type.HostComponent,
request.clusterName()))
+ .putAll(step.getProvisionProperties())
+ .build();
HostComponentResourceProvider rp = (HostComponentResourceProvider)
getClusterController().ensureResourceProvider(Resource.Type.HostComponent);
- Request internalRequest = createRequest(properties, requestInfo.build(),
null);
+ Request internalRequest = createRequest(properties, requestInfo, null);
try {
- rp.doUpdateResources(request.getStages(), internalRequest,
predicateForNewServices(request, HostComponentResourceProvider.HOST_ROLES),
false, false, false);
+ rp.doUpdateResources(request.getStages(), internalRequest, predicate,
false, false, false);
} catch (UnsupportedPropertyException | SystemException |
NoSuchParentResourceException | NoSuchResourceException e) {
CHECK.wrapInUnchecked(e, RuntimeException::new, "Error updating host
component desired state for %s", request);
}
@@ -272,20 +269,6 @@ public class ResourceProviderAdapter {
return new RequestImpl(propertyIds, properties, requestInfoProperties,
null);
}
- private static ImmutableMap.Builder<String, String> createRequestInfo(String
clusterName, Resource.Type resourceType) {
- return new ImmutableMap.Builder<String, String>()
- .put(RequestOperationLevel.OPERATION_LEVEL_ID,
RequestOperationLevel.getExternalLevelName(resourceType.name()))
- .put(RequestOperationLevel.OPERATION_CLUSTER_ID, clusterName);
- }
-
- private static void addProvisionProperties(ImmutableMap.Builder<String,
String> requestInfo, State desiredState, ProvisionAction requestAction) {
- if (desiredState == State.INSTALLED && requestAction.skipInstall()) {
- requestInfo.put(SKIP_INSTALL_FOR_COMPONENTS,
SKIP_INSTALL_FOR_ALL_COMPONENTS);
- requestInfo.put(DO_NOT_SKIP_INSTALL_FOR_COMPONENTS,
DO_NOT_SKIP_INSTALL_FOR_ANY_COMPONENTS);
- requestInfo.put(CLUSTER_PHASE_PROPERTY,
AmbariManagementControllerImpl.CLUSTER_PHASE_INITIAL_INSTALL);
- }
- }
-
public static Map<String, String>
requestInfoForKerberosDescriptor(KerberosDescriptor descriptor) {
return ImmutableMap.of(Request.REQUEST_INFO_BODY_PROPERTY,
ArtifactResourceProvider.toArtifactDataJson(descriptor.toMap()));
}
@@ -440,13 +423,13 @@ public class ResourceProviderAdapter {
.end().toPredicate();
}
- private static Predicate predicateForNewServices(AddServiceInfo request,
String category) {
+ private static Predicate predicateForNewServices(AddServiceInfo request) {
return new AndPredicate(
- new EqualsPredicate<>(PropertyHelper.getPropertyId(category,
ClusterResourceProvider.CLUSTER_NAME), request.clusterName()),
- new OrPredicate(
+ new
EqualsPredicate<>(ServiceResourceProvider.SERVICE_CLUSTER_NAME_PROPERTY_ID,
request.clusterName()),
+ OrPredicate.of(
request.newServices().keySet().stream()
- .map(service -> new
EqualsPredicate<>(PropertyHelper.getPropertyId(category, "service_name"),
service))
- .toArray(Predicate[]::new)
+ .map(service -> new
EqualsPredicate<>(ServiceResourceProvider.SERVICE_SERVICE_NAME_PROPERTY_ID,
service))
+ .collect(toList())
)
);
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Service.java
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Service.java
new file mode 100644
index 0000000..e31b3d8
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/Service.java
@@ -0,0 +1,96 @@
+/*
+ * 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.ambari.server.topology.addservice;
+
+import static
org.apache.ambari.server.controller.internal.BaseClusterRequest.PROVISION_ACTION_PROPERTY;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.ambari.annotations.ApiIgnore;
+import org.apache.ambari.server.controller.internal.ProvisionAction;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel
+public final class Service {
+
+ private static final String NAME = "name";
+
+ private final String name;
+ private final ProvisionAction provisionAction;
+
+ @JsonCreator
+ public Service(
+ @JsonProperty(NAME) String name,
+ @JsonProperty(PROVISION_ACTION_PROPERTY) ProvisionAction provisionAction
+ ) {
+ this.name = name;
+ this.provisionAction = provisionAction;
+ }
+
+ public static Service of(String name) {
+ return of(name, null);
+ }
+
+ public static Service of(String name, ProvisionAction provisionAction) {
+ return new Service(name, provisionAction);
+ }
+
+ @JsonProperty(NAME)
+ @ApiModelProperty(name = NAME)
+ public String getName() {
+ return name;
+ }
+
+ @JsonProperty(PROVISION_ACTION_PROPERTY)
+ @ApiModelProperty(name = PROVISION_ACTION_PROPERTY)
+ public ProvisionAction _getProvisionAction() {
+ return provisionAction;
+ }
+
+ @ApiIgnore
+ @JsonIgnore
+ public Optional<ProvisionAction> getProvisionAction() {
+ return Optional.ofNullable(provisionAction);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Service service = (Service) o;
+ return Objects.equals(name, service.name) &&
+ Objects.equals(provisionAction, service.provisionAction);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, provisionAction);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/controller/AddServiceRequestTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/AddServiceRequestTest.java
similarity index 92%
rename from
ambari-server/src/test/java/org/apache/ambari/server/controller/AddServiceRequestTest.java
rename to
ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/AddServiceRequestTest.java
index 4b90374..9f0e331 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/controller/AddServiceRequestTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/AddServiceRequestTest.java
@@ -16,16 +16,15 @@
* limitations under the License.
*/
-package org.apache.ambari.server.controller;
+package org.apache.ambari.server.topology.addservice;
-import static org.apache.ambari.server.controller.AddServiceRequest.Component;
-import static
org.apache.ambari.server.controller.AddServiceRequest.OperationType.ADD_SERVICE;
-import static org.apache.ambari.server.controller.AddServiceRequest.Service;
-import static
org.apache.ambari.server.controller.AddServiceRequest.ValidationType.PERMISSIVE;
-import static
org.apache.ambari.server.controller.AddServiceRequest.ValidationType.STRICT;
import static
org.apache.ambari.server.controller.internal.ProvisionAction.INSTALL_AND_START;
import static
org.apache.ambari.server.controller.internal.ProvisionAction.INSTALL_ONLY;
+import static
org.apache.ambari.server.controller.internal.ProvisionAction.START_ONLY;
import static
org.apache.ambari.server.topology.ConfigRecommendationStrategy.ALWAYS_APPLY;
+import static
org.apache.ambari.server.topology.addservice.AddServiceRequest.OperationType.ADD_SERVICE;
+import static
org.apache.ambari.server.topology.addservice.AddServiceRequest.ValidationType.PERMISSIVE;
+import static
org.apache.ambari.server.topology.addservice.AddServiceRequest.ValidationType.STRICT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -101,11 +100,14 @@ public class AddServiceRequestTest {
configuration.getProperties());
assertEquals(
- ImmutableSet.of(Component.of("NIMBUS", "c7401.ambari.apache.org",
"c7402.ambari.apache.org"), Component.of("BEACON_SERVER",
"c7402.ambari.apache.org", "c7403.ambari.apache.org")),
+ ImmutableSet.of(
+ Component.of("NIMBUS", START_ONLY, "c7401.ambari.apache.org",
"c7402.ambari.apache.org"),
+ Component.of("BEACON_SERVER", "c7402.ambari.apache.org",
"c7403.ambari.apache.org")
+ ),
request.getComponents());
assertEquals(
- ImmutableSet.of(Service.of("STORM"), Service.of("BEACON")),
+ ImmutableSet.of(Service.of("STORM", INSTALL_AND_START),
Service.of("BEACON")),
request.getServices());
assertEquals(
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilderTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilderTest.java
new file mode 100644
index 0000000..9a3bab6
--- /dev/null
+++
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilderTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.ambari.server.topology.addservice;
+
+import static java.util.stream.Collectors.toSet;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import
org.apache.ambari.server.controller.internal.HostComponentResourceProvider;
+import org.apache.ambari.server.controller.internal.ProvisionAction;
+import org.apache.ambari.server.controller.internal.RequestStageContainer;
+import org.apache.ambari.server.controller.internal.ResourceImpl;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.topology.ProvisionStep;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class ProvisionActionPredicateBuilderTest {
+
+ private static final String CLUSTER_NAME = "TEST";
+ private static final Map<String, Map<String, Set<String>>> NEW_SERVICES =
ImmutableMap.of(
+ "AMBARI_METRICS", ImmutableMap.of(
+ "METRICS_COLLECTOR", ImmutableSet.of("c7401"),
+ "METRICS_GRAFANA", ImmutableSet.of("c7403"),
+ "METRICS_MONITOR", ImmutableSet.of("c7401", "c7402", "c7403", "c7404",
"c7405")
+ ),
+ "KAFKA", ImmutableMap.of(
+ "KAFKA_BROKER", ImmutableSet.of("c7402", "c7404")
+ ),
+ "ZOOKEEPER", ImmutableMap.of(
+ "ZOOKEEPER_SERVER", ImmutableSet.of("c7401", "c7402", "c7403"),
+ "ZOOKEEPER_CLIENT", ImmutableSet.of("c7404")
+ )
+ );
+ private static final RequestStageContainer STAGES = new
RequestStageContainer(42L, null, null, null, null);
+
+ @Test
+ public void noCustomProvisionAction() {
+ AddServiceRequest request = createRequest(null, null, null);
+ AddServiceInfo info = new AddServiceInfo(request, CLUSTER_NAME, STAGES,
null, null, NEW_SERVICES);
+ ProvisionActionPredicateBuilder builder = new
ProvisionActionPredicateBuilder(info);
+
+ assertTrue(builder.getPredicate(ProvisionStep.INSTALL).isPresent());
+ assertFalse(builder.getPredicate(ProvisionStep.SKIP_INSTALL).isPresent());
+ assertTrue(builder.getPredicate(ProvisionStep.START).isPresent());
+
+ Predicate installPredicate =
builder.getPredicate(ProvisionStep.INSTALL).get();
+ Predicate startPredicate = builder.getPredicate(ProvisionStep.START).get();
+
+ Set<Resource> allNewHostComponents = allHostComponents(NEW_SERVICES);
+ assertMatchesAll(installPredicate, allNewHostComponents);
+ assertMatchesAll(startPredicate, allNewHostComponents);
+
+ assertNoMatchForExistingComponents(installPredicate, startPredicate);
+ }
+
+ @Test
+ public void requestLevelStartOnly() {
+ AddServiceRequest request = createRequest(ProvisionAction.START_ONLY,
null, null);
+ AddServiceInfo info = new AddServiceInfo(request, CLUSTER_NAME, STAGES,
null, null, NEW_SERVICES);
+ ProvisionActionPredicateBuilder builder = new
ProvisionActionPredicateBuilder(info);
+
+ assertEquals(Optional.empty(),
builder.getPredicate(ProvisionStep.INSTALL));
+ assertTrue(builder.getPredicate(ProvisionStep.SKIP_INSTALL).isPresent());
+ assertTrue(builder.getPredicate(ProvisionStep.START).isPresent());
+
+ Predicate skipInstallPredicate =
builder.getPredicate(ProvisionStep.SKIP_INSTALL).get();
+ Predicate startPredicate = builder.getPredicate(ProvisionStep.START).get();
+
+ Set<Resource> allNewHostComponents = allHostComponents(NEW_SERVICES);
+ assertMatchesAll(skipInstallPredicate, allNewHostComponents);
+ assertMatchesAll(startPredicate, allNewHostComponents);
+ assertNoMatchForExistingComponents(skipInstallPredicate, startPredicate);
+ }
+
+ @Test
+ public void customAtAllLevels() {
+ AddServiceRequest request = createRequest(ProvisionAction.START_ONLY,
+ ImmutableSet.of(
+ Service.of("AMBARI_METRICS", ProvisionAction.INSTALL_AND_START),
+ Service.of("KAFKA"),
+ Service.of("ZOOKEEPER", ProvisionAction.INSTALL_ONLY)
+ ),
+ ImmutableSet.of(
+ Component.of("KAFKA_BROKER", ProvisionAction.INSTALL_AND_START,
"c7404"), // overrides request-level
+ // KAFKA_BROKER on c7402 added by layout recommendation inherits
request-level
+ Component.of("METRICS_GRAFANA", ProvisionAction.START_ONLY, "c7403"),
// overrides service-level
+ Component.of("METRICS_MONITOR", "c7401"), // inherit from service
+ Component.of("METRICS_MONITOR", ProvisionAction.INSTALL_AND_START,
"c7402"), // matches service-level
+ // METRICS_MONITOR on c7403 added by layout recommendation, inherits
service-level
+ Component.of("METRICS_MONITOR", ProvisionAction.INSTALL_ONLY, "c7404",
"c7405") // overrides service-level
+ )
+ );
+ AddServiceInfo info = new AddServiceInfo(request, CLUSTER_NAME, STAGES,
null, null, NEW_SERVICES);
+ ProvisionActionPredicateBuilder builder = new
ProvisionActionPredicateBuilder(info);
+
+ assertTrue(builder.getPredicate(ProvisionStep.INSTALL).isPresent());
+ assertTrue(builder.getPredicate(ProvisionStep.SKIP_INSTALL).isPresent());
+ assertTrue(builder.getPredicate(ProvisionStep.START).isPresent());
+
+ Predicate installPredicate =
builder.getPredicate(ProvisionStep.INSTALL).get();
+ Predicate skipInstallPredicate =
builder.getPredicate(ProvisionStep.SKIP_INSTALL).get();
+ Predicate startPredicate = builder.getPredicate(ProvisionStep.START).get();
+
+ Map<String, Map<String, Set<String>>> installComponents = ImmutableMap.of(
+ "AMBARI_METRICS", ImmutableMap.of(
+ "METRICS_COLLECTOR", ImmutableSet.of("c7401"),
+ "METRICS_MONITOR", ImmutableSet.of("c7401", "c7402", "c7404", "c7405")
+ ),
+ "KAFKA", ImmutableMap.of(
+ "KAFKA_BROKER", ImmutableSet.of("c7404")
+ ),
+ "ZOOKEEPER", ImmutableMap.of(
+ "ZOOKEEPER_SERVER", ImmutableSet.of("c7401", "c7402", "c7403"),
+ "ZOOKEEPER_CLIENT", ImmutableSet.of("c7404")
+ )
+ );
+ Map<String, Map<String, Set<String>>> skipInstallComponents =
ImmutableMap.of(
+ "AMBARI_METRICS", ImmutableMap.of(
+ "METRICS_GRAFANA", ImmutableSet.of("c7403")
+ ),
+ "KAFKA", ImmutableMap.of(
+ "KAFKA_BROKER", ImmutableSet.of("c7402")
+ )
+ );
+ Map<String, Map<String, Set<String>>> startComponents = ImmutableMap.of(
+ "AMBARI_METRICS", ImmutableMap.of(
+ "METRICS_COLLECTOR", ImmutableSet.of("c7401"),
+ "METRICS_GRAFANA", ImmutableSet.of("c7403"),
+ "METRICS_MONITOR", ImmutableSet.of("c7401", "c7402", "c7403")
+ ),
+ "KAFKA", ImmutableMap.of(
+ "KAFKA_BROKER", ImmutableSet.of("c7402", "c7404")
+ )
+ );
+ assertMatchesAll(installPredicate, allHostComponents(installComponents));
+ assertMatchesAll(skipInstallPredicate,
allHostComponents(skipInstallComponents));
+ assertMatchesAll(startPredicate, allHostComponents(startComponents));
+ assertNoMatchForExistingComponents(skipInstallPredicate, startPredicate);
+ }
+
+ private static void assertNoMatchForExistingComponents(Predicate...
predicates) {
+ Resource existingComponent = existingComponent();
+ for (Predicate predicate : predicates) {
+ assertFalse(predicate.evaluate(existingComponent));
+ }
+ }
+
+ private static Resource existingComponent() {
+ return hostComponent("HDFS", "NAMENODE", "c7401");
+ }
+
+ private static void assertMatchesAll(Predicate predicates, Collection<?
extends Resource> resources) {
+ assertEquals(ImmutableSet.of(), resources.stream().filter(each ->
!predicates.evaluate(each)).collect(toSet()));
+ }
+
+ private static AddServiceRequest createRequest(ProvisionAction
provisionAction, Set<Service> services, Set<Component> components) {
+ return new AddServiceRequest(AddServiceRequest.OperationType.ADD_SERVICE,
null, provisionAction, AddServiceRequest.ValidationType.DEFAULT, "HDP", "3.0",
services, components, null, null, null);
+ }
+
+ private static Set<Resource> allHostComponents(Map<String, Map<String,
Set<String>>> services) {
+ return services.entrySet().stream()
+ .flatMap(componentsOfService ->
componentsOfService.getValue().entrySet().stream()
+ .flatMap(hostsOfComponent -> hostsOfComponent.getValue().stream()
+ .map(host -> hostComponent(componentsOfService.getKey(),
hostsOfComponent.getKey(), host))))
+ .collect(toSet());
+ }
+
+ private static Resource hostComponent(String service, String component,
String hostname) {
+ Resource hostComponent = new ResourceImpl(Resource.Type.HostComponent);
+ hostComponent.setProperty(HostComponentResourceProvider.CLUSTER_NAME,
CLUSTER_NAME);
+ hostComponent.setProperty(HostComponentResourceProvider.SERVICE_NAME,
service);
+ hostComponent.setProperty(HostComponentResourceProvider.COMPONENT_NAME,
component);
+ hostComponent.setProperty(HostComponentResourceProvider.HOST_NAME,
hostname);
+ return hostComponent;
+ }
+
+}
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/RequestValidatorTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/RequestValidatorTest.java
index 13fc281..96a0afa 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/RequestValidatorTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/RequestValidatorTest.java
@@ -23,6 +23,7 @@ import static java.util.stream.Collectors.toSet;
import static org.apache.ambari.server.utils.Assertions.assertThrows;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
@@ -33,12 +34,13 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
+import java.util.stream.Stream;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.RequestFactory;
-import org.apache.ambari.server.controller.AddServiceRequest;
import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.internal.ProvisionAction;
import org.apache.ambari.server.controller.internal.Stack;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.ConfigHelper;
@@ -228,6 +230,43 @@ public class RequestValidatorTest extends EasyMockSupport {
}
@Test
+ public void handlesMultipleComponentInstances() {
+ expect(request.getComponents()).andReturn(
+ Stream.of("c7401", "c7402")
+ .map(hostname -> Component.of("KAFKA_BROKER", hostname))
+ .collect(toSet()));
+ validator.setState(RequestValidator.State.INITIAL.with(simpleMockStack()));
+ replayAll();
+
+ validator.validateServicesAndComponents();
+
+ Map<String, Map<String, Set<String>>> expectedNewServices =
ImmutableMap.of(
+ "KAFKA", ImmutableMap.of("KAFKA_BROKER", ImmutableSet.of("c7401",
"c7402"))
+ );
+ assertEquals(expectedNewServices, validator.getState().getNewServices());
+ }
+
+ @Test
+ public void rejectsMultipleOccurrencesOfSameHostForSameComponent() {
+ Set<String> duplicateHosts = ImmutableSet.of("c7402", "c7403");
+ Set<String> uniqueHosts = ImmutableSet.of("c7401", "c7404");
+ expect(request.getComponents()).andReturn(
+ ImmutableSet.of(
+ Component.of("KAFKA_BROKER", ProvisionAction.INSTALL_AND_START,
"c7401", "c7402", "c7403"),
+ Component.of("KAFKA_BROKER", ProvisionAction.INSTALL_ONLY, "c7402",
"c7403", "c7404")
+ )
+ );
+ validator.setState(RequestValidator.State.INITIAL.with(simpleMockStack()));
+ replayAll();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
validator::validateServicesAndComponents);
+ assertTrue(e.getMessage().contains("hosts appear multiple"));
+ duplicateHosts.forEach(host -> assertTrue(e.getMessage().contains(host)));
+ uniqueHosts.forEach(host -> assertFalse(e.getMessage().contains(host)));
+ assertNull(validator.getState().getNewServices());
+ }
+
+ @Test
public void rejectsUnknownService() {
String serviceName = "UNKNOWN_SERVICE";
requestServices(false, serviceName);
@@ -525,7 +564,7 @@ public class RequestValidatorTest extends EasyMockSupport {
Exception e = assertThrows(IllegalArgumentException.class, validation);
if (expectedMessage != null) {
assertTrue(e.getMessage().contains(expectedMessage));
- };
+ }
resetAll();
setUp();
@@ -585,7 +624,7 @@ public class RequestValidatorTest extends EasyMockSupport {
private void requestServices(boolean validated, String... services) {
expect(request.getServices()).andReturn(
Arrays.stream(services)
- .map(AddServiceRequest.Service::of)
+ .map(org.apache.ambari.server.topology.addservice.Service::of)
.collect(toSet())
).anyTimes();
if (validated) {
@@ -607,7 +646,7 @@ public class RequestValidatorTest extends EasyMockSupport {
private void requestComponents(String... components) {
expect(request.getComponents()).andReturn(
Arrays.stream(components)
- .map(componentName -> AddServiceRequest.Component.of(componentName,
"c7401.ambari.apache.org"))
+ .map(componentName -> Component.of(componentName,
"c7401.ambari.apache.org"))
.collect(toSet())
);
}
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/StackAdvisorAdapterTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/StackAdvisorAdapterTest.java
index 78f481e..5219acb 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/StackAdvisorAdapterTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/topology/addservice/StackAdvisorAdapterTest.java
@@ -42,7 +42,6 @@ import
org.apache.ambari.server.api.services.stackadvisor.StackAdvisorHelper;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
import
org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
import
org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
-import org.apache.ambari.server.controller.AddServiceRequest;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.internal.Stack;
import org.apache.ambari.server.state.Cluster;
@@ -178,8 +177,8 @@ public class StackAdvisorAdapterTest {
"OOZIE_SERVER", ImmutableSet.of("c7401"),
"OOZIE_CLIENT", ImmutableSet.of("c7403", "c7404")));
- AddServiceInfo info = new
AddServiceInfo(request(ConfigRecommendationStrategy.ALWAYS_APPLY), "c1", stack
, Configuration.newEmpty(),
- null, null, newServices, null); // No LayoutReommendationInfo -> needs
to be calculated
+ AddServiceRequest request =
request(ConfigRecommendationStrategy.ALWAYS_APPLY);
+ AddServiceInfo info = new AddServiceInfo(request, "c1", null, stack,
Configuration.newEmpty(), newServices); // No LayoutReommendationInfo -> needs
to be calculated
LayoutRecommendationInfo layoutRecommendationInfo =
adapter.getLayoutRecommendationInfo(info);
layoutRecommendationInfo.getAllServiceLayouts();
@@ -361,7 +360,7 @@ public class StackAdvisorAdapterTest {
"KAFKA",
ImmutableMap.of("KAFKA_BROKER", emptySet()));
- AddServiceInfo info = new AddServiceInfo(null, "c1", stack,
org.apache.ambari.server.topology.Configuration.newEmpty(), null, null,
newServices, null);
+ AddServiceInfo info = new AddServiceInfo(null, "c1", null, stack,
org.apache.ambari.server.topology.Configuration.newEmpty(), newServices);
AddServiceInfo infoWithRecommendations = adapter.recommendLayout(info);
Map<String, Map<String, Set<String>>> expectedNewLayout = ImmutableMap.of(
@@ -392,8 +391,8 @@ public class StackAdvisorAdapterTest {
userConfig.setParentConfiguration(clusterConfig);
clusterConfig.setParentConfiguration(stackConfig);
- AddServiceInfo info = new
AddServiceInfo(request(ConfigRecommendationStrategy.ALWAYS_APPLY), "c1", stack
, userConfig,
- null, null, newServices, null); // No LayoutRecommendationInfo
+ AddServiceRequest request =
request(ConfigRecommendationStrategy.ALWAYS_APPLY);
+ AddServiceInfo info = new AddServiceInfo(request, "c1", null, stack,
userConfig, newServices); // No LayoutRecommendationInfo
AddServiceInfo infoWithConfig = adapter.recommendConfigurations(info);
Configuration recommendedConfig = infoWithConfig.getConfig();
@@ -442,8 +441,9 @@ public class StackAdvisorAdapterTest {
clusterConfig.setParentConfiguration(stackConfig);
LayoutRecommendationInfo layoutRecommendationInfo = new
LayoutRecommendationInfo(new HashMap<>(), new HashMap<>()); // contents doesn't
matter for the test
- AddServiceInfo info = new
AddServiceInfo(request(ConfigRecommendationStrategy.ALWAYS_APPLY), "c1", stack
, userConfig,
- null, null, newServices, layoutRecommendationInfo);
+ AddServiceRequest request =
request(ConfigRecommendationStrategy.ALWAYS_APPLY);
+ AddServiceInfo info = new AddServiceInfo(request, "c1", null, stack,
userConfig, newServices)
+ .withLayoutRecommendation(newServices, layoutRecommendationInfo);
AddServiceInfo infoWithConfig = adapter.recommendConfigurations(info);
Configuration recommendedConfig = infoWithConfig.getConfig();
@@ -492,8 +492,9 @@ public class StackAdvisorAdapterTest {
clusterConfig.setParentConfiguration(stackConfig);
LayoutRecommendationInfo layoutRecommendationInfo = new
LayoutRecommendationInfo(new HashMap<>(), new HashMap<>()); // contents doesn't
matter for the test
- AddServiceInfo info = new
AddServiceInfo(request(ConfigRecommendationStrategy.ALWAYS_APPLY_DONT_OVERRIDE_CUSTOM_VALUES),
"c1", stack , userConfig,
- null, null, newServices, layoutRecommendationInfo);
+ AddServiceRequest request =
request(ConfigRecommendationStrategy.ALWAYS_APPLY_DONT_OVERRIDE_CUSTOM_VALUES);
+ AddServiceInfo info = new AddServiceInfo(request, "c1", null, stack,
userConfig, newServices)
+ .withLayoutRecommendation(newServices, layoutRecommendationInfo);
AddServiceInfo infoWithConfig = adapter.recommendConfigurations(info);
assertSame(userConfig, infoWithConfig.getConfig()); // user config stays
top priority
@@ -547,8 +548,9 @@ public class StackAdvisorAdapterTest {
clusterConfig.setParentConfiguration(stackConfig);
LayoutRecommendationInfo layoutRecommendationInfo = new
LayoutRecommendationInfo(new HashMap<>(), new HashMap<>()); // contents doesn't
matter for the test
- AddServiceInfo info = new
AddServiceInfo(request(ConfigRecommendationStrategy.NEVER_APPLY), "c1", stack ,
userConfig,
- null, null, newServices, layoutRecommendationInfo);
+ AddServiceRequest request =
request(ConfigRecommendationStrategy.NEVER_APPLY);
+ AddServiceInfo info = new AddServiceInfo(request, "c1", null, stack,
userConfig, newServices)
+ .withLayoutRecommendation(newServices, layoutRecommendationInfo);
AddServiceInfo infoWithConfig = adapter.recommendConfigurations(info);
// No recommended config, no stack config
@@ -588,8 +590,9 @@ public class StackAdvisorAdapterTest {
clusterConfig.setParentConfiguration(stackConfig);
LayoutRecommendationInfo layoutRecommendationInfo = new
LayoutRecommendationInfo(new HashMap<>(), new HashMap<>()); // contents doesn't
matter for the test
- AddServiceInfo info = new
AddServiceInfo(request(ConfigRecommendationStrategy.ONLY_STACK_DEFAULTS_APPLY),
"c1", stack , userConfig,
- null, null, newServices, layoutRecommendationInfo);
+ AddServiceRequest request =
request(ConfigRecommendationStrategy.ONLY_STACK_DEFAULTS_APPLY);
+ AddServiceInfo info = new AddServiceInfo(request, "c1", null, stack,
userConfig, newServices)
+ .withLayoutRecommendation(newServices, layoutRecommendationInfo);
AddServiceInfo infoWithConfig = adapter.recommendConfigurations(info);
Configuration recommendedConfig =
infoWithConfig.getConfig().getParentConfiguration();
@@ -656,7 +659,7 @@ public class StackAdvisorAdapterTest {
assertEquals(recommendedConfigsForStackDefaults, recommendedConfigs);
}
- private AddServiceRequest request(ConfigRecommendationStrategy strategy) {
+ private static AddServiceRequest request(ConfigRecommendationStrategy
strategy) {
return new AddServiceRequest(null, strategy, null, null, null, null, null,
null, null, null, null);
}
diff --git a/ambari-server/src/test/resources/add_service_api/request1.json
b/ambari-server/src/test/resources/add_service_api/request1.json
index 75fb12f..b4e56e2 100644
--- a/ambari-server/src/test/resources/add_service_api/request1.json
+++ b/ambari-server/src/test/resources/add_service_api/request1.json
@@ -7,13 +7,14 @@
"stack_version" : "3.0",
"services": [
- { "name" : "STORM" },
+ { "name" : "STORM", "provision_action": "INSTALL_AND_START" },
{ "name" : "BEACON" }
],
"components" : [
{
"name" : "NIMBUS",
+ "provision_action" : "START_ONLY",
"hosts": [
{ "fqdn" : "c7401.ambari.apache.org" },
{ "fqdn" : "c7402.ambari.apache.org" }