You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/11/17 13:32:31 UTC
[07/11] ambari git commit: AMBARI-22431 Able to add config type if
EU/RU of the same stack (minor version upgrade) (dili)
AMBARI-22431 Able to add config type if EU/RU of the same stack (minor version upgrade) (dili)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/29512573
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/29512573
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/29512573
Branch: refs/heads/branch-feature-AMBARI-22457
Commit: 29512573090948e29d38bb0d259f72b0a5e42e99
Parents: 3279bef
Author: Di Li <di...@apache.org>
Authored: Thu Nov 16 12:22:35 2017 -0500
Committer: Di Li <di...@apache.org>
Committed: Thu Nov 16 12:22:35 2017 -0500
----------------------------------------------------------------------
.../internal/UpgradeResourceProvider.java | 36 ++
.../upgrades/CreateAndConfigureAction.java | 164 +++++++++
.../ambari/server/state/stack/UpgradePack.java | 3 +
.../state/stack/upgrade/ClusterGrouping.java | 2 +
.../stack/upgrade/CreateAndConfigureTask.java | 57 +++
.../ambari/server/state/stack/upgrade/Task.java | 6 +-
.../src/main/resources/upgrade-pack.xsd | 9 +-
.../upgrades/CreateAndConfigureActionTest.java | 357 +++++++++++++++++++
8 files changed, 632 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index 66f5bf9..b6846f7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -92,6 +92,7 @@ import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
import org.apache.ambari.server.state.stack.ConfigUpgradePack;
import org.apache.ambari.server.state.stack.UpgradePack;
import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
+import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask;
import org.apache.ambari.server.state.stack.upgrade.Direction;
import org.apache.ambari.server.state.stack.upgrade.ManualTask;
import org.apache.ambari.server.state.stack.upgrade.ServerSideActionTask;
@@ -1336,6 +1337,41 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
break;
}
+ case CREATE_AND_CONFIGURE: {
+ CreateAndConfigureTask ct = (CreateAndConfigureTask) task;
+
+ // !!! would prefer to do this in the sequence generator, but there's too many
+ // places to miss
+ if (context.getOrchestrationType().isRevertable() && !ct.supportsPatch) {
+ process = false;
+ }
+
+ Map<String, String> configurationChanges =
+ ct.getConfigurationChanges(cluster, configUpgradePack);
+
+ // add all configuration changes to the command params
+ commandParams.putAll(configurationChanges);
+
+ // extract the config type to build the summary
+ String configType = configurationChanges.get(CreateAndConfigureTask.PARAMETER_CONFIG_TYPE);
+ if (null != configType) {
+ itemDetail = String.format("Updating configuration %s", configType);
+ } else {
+ itemDetail = "Skipping Configuration Task "
+ + StringUtils.defaultString(ct.id, "(missing id)");
+ }
+
+ entity.setText(itemDetail);
+
+ String configureTaskSummary = ct.getSummary(configUpgradePack);
+ if (null != configureTaskSummary) {
+ stageText = configureTaskSummary;
+ } else {
+ stageText = itemDetail;
+ }
+
+ break;
+ }
default:
break;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java
new file mode 100644
index 0000000..e60938a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java
@@ -0,0 +1,164 @@
+/*
+ * 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.serveraction.upgrades;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ConfigurationRequest;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.UpgradeContext;
+import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+
+/**
+ * The {@link CreateAndConfigureAction} is used to alter a configuration property during
+ * an upgrade. It also creates the config type if it does not exist as a desired config for the cluster.
+ * It will only produce a new configuration if an actual change is
+ * occuring. For some configure tasks, the value is already at the desired
+ * property or the conditions of the task are not met. In these cases, a new
+ * configuration will not be created. This task can perform any of the following
+ * actions in a single declaration:
+ * <ul>
+ * <li>Copy a configuration to a new property key, optionally setting a default
+ * if the original property did not exist</li>
+ * <li>Copy a configuration to a new property key from one configuration type to
+ * another, optionally setting a default if the original property did not exist</li>
+ * <li>Rename a configuration, optionally setting a default if the original
+ * property did not exist</li>
+ * <li>Delete a configuration property</li>
+ * <li>Set a configuration property</li>
+ * <li>Conditionally set a configuration property based on another configuration
+ * property value</li>
+ * </ul>
+ */
+public class CreateAndConfigureAction extends ConfigureAction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CreateAndConfigureAction.class);
+
+ /**
+ * Used to lookup the cluster.
+ */
+ @Inject
+ private Clusters m_clusters;
+
+ /**
+ * Used to update the configuration properties.
+ */
+ @Inject
+ private AmbariManagementController m_controller;
+
+ /**
+ * Used to assist in the creation of a {@link ConfigurationRequest} to update
+ * configuration values.
+ */
+ @Inject
+ private ConfigHelper m_configHelper;
+
+
+ @Override
+ public CommandReport execute(
+ ConcurrentMap<String, Object> requestSharedDataContext)
+ throws AmbariException, InterruptedException {
+
+ LOG.info("Create and Configure...");
+
+ Map<String,String> commandParameters = getCommandParameters();
+ if( null == commandParameters || commandParameters.isEmpty() ){
+ return createCommandReport(0, HostRoleStatus.FAILED, "{}", "",
+ "Unable to change configuration values without command parameters");
+ }
+
+ String clusterName = commandParameters.get("clusterName");
+ Cluster cluster = m_clusters.getCluster(clusterName);
+ UpgradeContext upgradeContext = getUpgradeContext(cluster);
+
+ Direction direction = upgradeContext.getDirection();
+ if (direction == Direction.DOWNGRADE) {
+ return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", "", "Skip changing configuration values for downgrade");
+ }
+
+ String configType = commandParameters.get(CreateAndConfigureTask.PARAMETER_CONFIG_TYPE);
+ String serviceName = cluster.getServiceByConfigType(configType);
+
+ if (StringUtils.isBlank(serviceName)) {
+ serviceName = commandParameters.get(CreateAndConfigureTask.PARAMETER_ASSOCIATED_SERVICE);
+ }
+
+ RepositoryVersionEntity sourceRepoVersion = upgradeContext.getSourceRepositoryVersion(serviceName);
+ RepositoryVersionEntity targetRepoVersion = upgradeContext.getTargetRepositoryVersion(serviceName);
+ StackId sourceStackId = sourceRepoVersion.getStackId();
+ StackId targetStackId = targetRepoVersion.getStackId();
+
+ if (!sourceStackId.equals(targetStackId)){
+ return createCommandReport(0, HostRoleStatus.FAILED, "{}", "",
+ "Unable to change configuration values across stacks. Use regular config task type instead.");
+ }
+
+ Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs();
+ DesiredConfig desiredConfig = desiredConfigs.get(configType);
+ if (desiredConfig == null) {
+ LOG.info(String.format("Could not find desired config type with name %s. Create it with default values.", configType));
+
+ // populate a map with default configurations from the new stack
+ Map<String, Map<String, String>> newServiceDefaultConfigsByType = m_configHelper.getDefaultProperties(
+ targetStackId, serviceName);
+
+ if (!newServiceDefaultConfigsByType.containsKey(configType)){
+ String error = String.format("%s in %s does not contain configuration type %s", serviceName, targetStackId.getStackId(), configType);
+ LOG.error(error);
+ return createCommandReport(0, HostRoleStatus.FAILED, "{}", "", error);
+ }
+
+ Map<String, String> defaultConfigsForType = newServiceDefaultConfigsByType.get(configType);
+ // Remove any property for the new config type whose value is NULL
+ Iterator<Map.Entry<String, String>> iter = defaultConfigsForType.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<String, String> entry = iter.next();
+ if (entry.getValue() == null) {
+ iter.remove();
+ }
+ }
+
+ String serviceVersionNote = String.format("%s %s %s", direction.getText(true),
+ direction.getPreposition(), upgradeContext.getRepositoryVersion().getVersion());
+
+ m_configHelper.createConfigType(cluster, targetStackId,
+ m_controller,
+ configType, defaultConfigsForType,
+ m_controller.getAuthName(), serviceVersionNote);
+ }
+
+ return super.execute(requestSharedDataContext);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
index 56f13ab..43c7a55 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java
@@ -38,6 +38,7 @@ import javax.xml.bind.annotation.XmlValue;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.state.stack.upgrade.ClusterGrouping;
import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
+import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask;
import org.apache.ambari.server.state.stack.upgrade.Direction;
import org.apache.ambari.server.state.stack.upgrade.Grouping;
import org.apache.ambari.server.state.stack.upgrade.ServiceCheckGrouping;
@@ -594,6 +595,8 @@ public class UpgradePack {
for (Task task : tasks) {
if (Task.Type.CONFIGURE == task.getType()) {
((ConfigureTask) task).associatedService = service;
+ } else if (Task.Type.CREATE_AND_CONFIGURE == task.getType()) {
+ ((CreateAndConfigureTask) task).associatedService = service;
}
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
index 63d0993..c1a05c0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java
@@ -135,6 +135,8 @@ public class ClusterGrouping extends Grouping {
void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
if (task.getType().equals(Task.Type.CONFIGURE) && StringUtils.isNotEmpty(service)) {
((ConfigureTask) task).associatedService = service;
+ } else if (task.getType().equals(Task.Type.CREATE_AND_CONFIGURE) && StringUtils.isNotEmpty(service)) {
+ ((CreateAndConfigureTask) task).associatedService = service;
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/CreateAndConfigureTask.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/CreateAndConfigureTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/CreateAndConfigureTask.java
new file mode 100644
index 0000000..d89840f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/CreateAndConfigureTask.java
@@ -0,0 +1,57 @@
+/**
+ * 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.state.stack.upgrade;
+
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.ambari.server.serveraction.upgrades.CreateAndConfigureAction;
+
+/**
+ * The {@link CreateAndConfigureTask} represents a two step change where the create is for creating a config type if it does not exist
+ * followed by the configuration change.
+ * This task contains id of change. Change definitions are located in a separate file (config
+ * upgrade pack). IDs of change definitions share the same namespace within all stacks.
+ *
+ *
+ * <p/>
+ *
+ * <pre>
+ * {@code
+ * <task xsi:type="create_and_configure" id="hdp_2_3_0_0-UpdateHiveConfig"/>
+ * }
+ * </pre>
+ *
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name="create_and_configure")
+public class CreateAndConfigureTask extends ConfigureTask {
+
+ public static final String actionVerb = "CreateAndConfiguring";
+
+ /**
+ * Constructor.
+ */
+ public CreateAndConfigureTask() {
+ implClass = CreateAndConfigureAction.class.getName();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
index 6ab2fd2..2167b7b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/Task.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlSeeAlso;
/**
* Base class to identify the items that could possibly occur during an upgrade
*/
-@XmlSeeAlso(value={ExecuteTask.class, ConfigureTask.class, ManualTask.class, RestartTask.class, StartTask.class, StopTask.class, ServerActionTask.class, ConfigureFunction.class})
+@XmlSeeAlso(value={ExecuteTask.class, CreateAndConfigureTask.class, ConfigureTask.class, ManualTask.class, RestartTask.class, StartTask.class, StopTask.class, ServerActionTask.class, ConfigureFunction.class})
public abstract class Task {
/**
@@ -96,6 +96,10 @@ public abstract class Task {
*/
CONFIGURE,
/**
+ * Task that create a config type if it does not, and alters a configuration.
+ */
+ CREATE_AND_CONFIGURE,
+ /**
* Task that sets up the configuration for subsequent task
*/
CONFIGURE_FUNCTION,
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/main/resources/upgrade-pack.xsd
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/upgrade-pack.xsd b/ambari-server/src/main/resources/upgrade-pack.xsd
index 21606bd..249725e 100644
--- a/ambari-server/src/main/resources/upgrade-pack.xsd
+++ b/ambari-server/src/main/resources/upgrade-pack.xsd
@@ -87,7 +87,7 @@
</xs:extension>
</xs:complexContent>
</xs:complexType>
-
+
<xs:complexType name="security">
<xs:complexContent>
<xs:extension base="abstract-condition-type">
@@ -336,6 +336,13 @@
</xs:complexContent>
</xs:complexType>
+ <xs:complexType name="create_and_configure">
+ <xs:complexContent>
+ <xs:extension base="configure">
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
<xs:complexType name="configure_function">
<xs:complexContent>
<xs:extension base="abstract-task-type">
http://git-wip-us.apache.org/repos/asf/ambari/blob/29512573/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java
new file mode 100644
index 0000000..43b5bd0
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureActionTest.java
@@ -0,0 +1,357 @@
+/*
+ * 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.serveraction.upgrades;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.H2DatabaseCleaner;
+import org.apache.ambari.server.ServiceComponentNotFoundException;
+import org.apache.ambari.server.ServiceNotFoundException;
+import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
+import org.apache.ambari.server.actionmanager.HostRoleCommand;
+import org.apache.ambari.server.actionmanager.HostRoleCommandFactory;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.OrmTestHelper;
+import org.apache.ambari.server.orm.dao.RequestDAO;
+import org.apache.ambari.server.orm.dao.UpgradeDAO;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.RequestEntity;
+import org.apache.ambari.server.orm.entities.UpgradeEntity;
+import org.apache.ambari.server.orm.entities.UpgradeHistoryEntity;
+import org.apache.ambari.server.serveraction.ServerAction;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigFactory;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentFactory;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceComponentHostFactory;
+import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue;
+import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * Tests upgrade-related server side actions
+ */
+public class CreateAndConfigureActionTest {
+
+ @Inject
+ private Injector m_injector;
+
+ @Inject
+ private OrmTestHelper m_helper;
+
+ @Inject
+ private HostRoleCommandFactory hostRoleCommandFactory;
+
+ @Inject
+ private ServiceFactory serviceFactory;
+
+ @Inject
+ private ConfigHelper m_configHelper;
+
+ @Inject
+ private Clusters clusters;
+
+ @Inject
+ private ConfigFactory configFactory;
+
+ @Inject
+ private CreateAndConfigureAction action;
+
+ @Inject
+ private RequestDAO requestDAO;
+
+ @Inject
+ private UpgradeDAO upgradeDAO;
+
+ @Inject
+ private ServiceComponentFactory serviceComponentFactory;
+
+ @Inject
+ private ServiceComponentHostFactory serviceComponentHostFactory;
+
+ private RepositoryVersionEntity repoVersion2110;
+ private RepositoryVersionEntity repoVersion2111;
+ private RepositoryVersionEntity repoVersion2200;
+
+ private final Map<String, Map<String, String>> NO_ATTRIBUTES = new HashMap<>();
+
+ @Before
+ public void setup() throws Exception {
+ m_injector = Guice.createInjector(new InMemoryDefaultTestModule());
+ m_injector.getInstance(GuiceJpaInitializer.class);
+ m_injector.injectMembers(this);
+
+ repoVersion2110 = m_helper.getOrCreateRepositoryVersion(new StackId("HDP-2.1.1"), "2.1.1.0-1234");
+ repoVersion2111 = m_helper.getOrCreateRepositoryVersion(new StackId("HDP-2.1.1"), "2.1.1.1-5678");
+ repoVersion2200 = m_helper.getOrCreateRepositoryVersion(new StackId("HDP-2.2.0"), "2.2.0.0-1234");
+
+ makeUpgradeCluster();
+ }
+
+ @After
+ public void teardown() throws Exception {
+ H2DatabaseCleaner.clearDatabase(m_injector.getProvider(EntityManager.class).get());
+ }
+
+
+ /**
+ * Tests that a new configuration is created when upgrading across stack when
+ * there is no existing configuration with the correct target stack.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testNewConfigCreatedWhenUpgradingWithoutChaningStack() throws Exception {
+ Cluster c = clusters.getCluster("c1");
+ assertEquals(1, c.getConfigsByType("zoo.cfg").size());
+
+ Map<String, String> properties = new HashMap<String, String>() {
+ {
+ put("initLimit", "10");
+ }
+ };
+
+ Config config = createConfig(c, "zoo.cfg", "version2", properties);
+
+ c.addDesiredConfig("user", Collections.singleton(config));
+ assertEquals(2, c.getConfigsByType("zoo.cfg").size());
+
+ List<ConfigurationKeyValue> configurations = new ArrayList<>();
+ ConfigurationKeyValue keyValue = new ConfigurationKeyValue();
+ configurations.add(keyValue);
+ keyValue.key = "initLimit";
+ keyValue.value = "11";
+ c.setCurrentStackVersion(repoVersion2110.getStackId());
+ c.setDesiredStackVersion(repoVersion2111.getStackId());
+
+ createUpgrade(c, repoVersion2111);
+
+ Map<String, String> commandParams = new HashMap<>();
+ commandParams.put("clusterName", "c1");
+ commandParams.put(CreateAndConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg");
+ commandParams.put(CreateAndConfigureTask.PARAMETER_KEY_VALUE_PAIRS, new Gson().toJson(configurations));
+
+ ExecutionCommand executionCommand = getExecutionCommand(commandParams);
+ HostRoleCommand hostRoleCommand = hostRoleCommandFactory.create(null, null,
+ null, null);
+
+ hostRoleCommand.setExecutionCommandWrapper(new ExecutionCommandWrapper(
+ executionCommand));
+
+ action.setExecutionCommand(executionCommand);
+ action.setHostRoleCommand(hostRoleCommand);
+
+ CommandReport report = action.execute(null);
+ assertNotNull(report);
+
+ assertEquals(3, c.getConfigsByType("zoo.cfg").size());
+
+ config = c.getDesiredConfigByType("zoo.cfg");
+ assertNotNull(config);
+ assertFalse(StringUtils.equals("version2", config.getTag()));
+ assertEquals("11", config.getProperties().get("initLimit"));
+ }
+
+ /**
+ * Creates a cluster using {@link #repoVersion2110} with ZooKeeper installed.
+ *
+ * @throws Exception
+ */
+ private void makeUpgradeCluster() throws Exception {
+ String clusterName = "c1";
+ String hostName = "h1";
+
+ clusters.addCluster(clusterName, repoVersion2110.getStackId());
+
+ Cluster c = clusters.getCluster(clusterName);
+
+ // add a host component
+ clusters.addHost(hostName);
+ Host host = clusters.getHost(hostName);
+ Map<String, String> hostAttributes = new HashMap<>();
+ hostAttributes.put("os_family", "redhat");
+ hostAttributes.put("os_release_version", "6");
+ host.setHostAttributes(hostAttributes);
+
+ clusters.mapHostToCluster(hostName, clusterName);
+
+ // !!! very important, otherwise the loops that walk the list of installed
+ // service properties will not run!
+ Service zk = installService(c, "ZOOKEEPER", repoVersion2110);
+ addServiceComponent(c, zk, "ZOOKEEPER_SERVER");
+ addServiceComponent(c, zk, "ZOOKEEPER_CLIENT");
+ createNewServiceComponentHost(c, "ZOOKEEPER", "ZOOKEEPER_SERVER", hostName);
+ createNewServiceComponentHost(c, "ZOOKEEPER", "ZOOKEEPER_CLIENT", hostName);
+
+ Map<String, String> properties = new HashMap<String, String>() {
+ {
+ put("initLimit", "10");
+ }
+ };
+
+ Config config = createConfig(c, "zoo.cfg", "version1", properties);
+
+ c.addDesiredConfig("user", Collections.singleton(config));
+
+ // verify that our configs are there
+ String tickTime = m_configHelper.getPropertyValueFromStackDefinitions(c, "zoo.cfg", "tickTime");
+ assertNotNull(tickTime);
+ }
+
+ /**
+ * Installs a service in the cluster.
+ *
+ * @param cluster
+ * @param serviceName
+ * @return
+ * @throws AmbariException
+ */
+ private Service installService(Cluster cluster, String serviceName,
+ RepositoryVersionEntity repositoryVersion) throws AmbariException {
+ Service service = null;
+
+ try {
+ service = cluster.getService(serviceName);
+ } catch (ServiceNotFoundException e) {
+ service = serviceFactory.createNew(cluster, serviceName, repositoryVersion);
+ cluster.addService(service);
+ }
+
+ return service;
+ }
+
+ private ServiceComponent addServiceComponent(Cluster cluster, Service service,
+ String componentName) throws AmbariException {
+ ServiceComponent serviceComponent = null;
+ try {
+ serviceComponent = service.getServiceComponent(componentName);
+ } catch (ServiceComponentNotFoundException e) {
+ serviceComponent = serviceComponentFactory.createNew(service, componentName);
+ service.addServiceComponent(serviceComponent);
+ serviceComponent.setDesiredState(State.INSTALLED);
+ }
+
+ return serviceComponent;
+ }
+
+ private ServiceComponentHost createNewServiceComponentHost(Cluster cluster, String serviceName,
+ String svcComponent, String hostName) throws AmbariException {
+ Assert.assertNotNull(cluster.getConfigGroups());
+ Service s = cluster.getService(serviceName);
+ ServiceComponent sc = addServiceComponent(cluster, s, svcComponent);
+
+ ServiceComponentHost sch = serviceComponentHostFactory.createNew(sc, hostName);
+
+ sc.addServiceComponentHost(sch);
+ sch.setDesiredState(State.INSTALLED);
+ sch.setState(State.INSTALLED);
+ return sch;
+ }
+
+ /**
+ * Creates an upgrade and associates it with the cluster.
+ */
+ private UpgradeEntity createUpgrade(Cluster cluster, RepositoryVersionEntity repositoryVersion)
+ throws Exception {
+
+ // create some entities for the finalize action to work with for patch
+ // history
+ RequestEntity requestEntity = new RequestEntity();
+ requestEntity.setClusterId(cluster.getClusterId());
+ requestEntity.setRequestId(1L);
+ requestEntity.setStartTime(System.currentTimeMillis());
+ requestEntity.setCreateTime(System.currentTimeMillis());
+ requestDAO.create(requestEntity);
+
+ UpgradeEntity upgradeEntity = new UpgradeEntity();
+ upgradeEntity.setId(1L);
+ upgradeEntity.setClusterId(cluster.getClusterId());
+ upgradeEntity.setRequestEntity(requestEntity);
+ upgradeEntity.setUpgradePackage("");
+ upgradeEntity.setRepositoryVersion(repositoryVersion);
+ upgradeEntity.setUpgradeType(UpgradeType.NON_ROLLING);
+
+ Map<String, Service> services = cluster.getServices();
+ for (String serviceName : services.keySet()) {
+ Service service = services.get(serviceName);
+ Map<String, ServiceComponent> components = service.getServiceComponents();
+ for (String componentName : components.keySet()) {
+ UpgradeHistoryEntity history = new UpgradeHistoryEntity();
+ history.setUpgrade(upgradeEntity);
+ history.setServiceName(serviceName);
+ history.setComponentName(componentName);
+ history.setFromRepositoryVersion(service.getDesiredRepositoryVersion());
+ history.setTargetRepositoryVersion(repositoryVersion);
+ upgradeEntity.addHistory(history);
+ }
+ }
+
+ upgradeDAO.create(upgradeEntity);
+ cluster.setUpgradeEntity(upgradeEntity);
+ return upgradeEntity;
+ }
+
+ private ExecutionCommand getExecutionCommand(Map<String, String> commandParams) {
+ ExecutionCommand executionCommand = new ExecutionCommand();
+ executionCommand.setClusterName("c1");
+ executionCommand.setCommandParams(commandParams);
+ executionCommand.setRoleParams(new HashMap<String, String>());
+ executionCommand.getRoleParams().put(ServerAction.ACTION_USER_NAME, "username");
+
+ return executionCommand;
+ }
+
+ private Config createConfig(Cluster cluster, String type, String tag,
+ Map<String, String> properties) {
+ return configFactory.createNew(cluster, type, tag, properties,
+ NO_ATTRIBUTES);
+ }
+}
\ No newline at end of file