This is an automated email from the ASF dual-hosted git repository. jonathanhurley 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 4c70e1a [AMBARI-24994] Updates to the SPI for Upgrade Action Operations (#2687) 4c70e1a is described below commit 4c70e1a7ec5609992fa06fca9618f5b112f941a5 Author: Jonathan Hurley <jonathanhur...@apache.org> AuthorDate: Tue Dec 4 16:11:58 2018 -0500 [AMBARI-24994] Updates to the SPI for Upgrade Action Operations (#2687) --- .../org/apache/ambari/spi/ClusterInformation.java | 25 +-- .../apache/ambari/spi/upgrade/UpgradeAction.java | 7 +- .../spi/upgrade/UpgradeActionOperations.java | 168 +++++++++++++++++++-- .../ambari/spi/upgrade/UpgradeInformation.java | 131 ++++++++++++++++ .../orm/entities/RepositoryVersionEntity.java | 17 ++- .../upgrades/AbstractUpgradeServerAction.java | 18 +++ .../upgrades/PluginUpgradeServerAction.java | 63 +++++++- .../stack/upgrade/orchestrate/UpgradeContext.java | 42 ++++++ .../ambari/server/state/cluster/ClusterImpl.java | 7 +- .../upgrades/PluginUpgradeServerActionTest.java | 105 ++++++++++--- 10 files changed, 519 insertions(+), 64 deletions(-) diff --git a/ambari-server-spi/src/main/java/org/apache/ambari/spi/ClusterInformation.java b/ambari-server-spi/src/main/java/org/apache/ambari/spi/ClusterInformation.java index eb9974e..774fe65 100644 --- a/ambari-server-spi/src/main/java/org/apache/ambari/spi/ClusterInformation.java +++ b/ambari-server-spi/src/main/java/org/apache/ambari/spi/ClusterInformation.java @@ -21,8 +21,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import com.google.common.collect.Maps; - /** * The {@link ClusterInformation} class is used to pass the state of the cluster * as simple primitive values and collections. It contains the following types of information: @@ -124,13 +122,17 @@ public class ClusterInformation { return hosts; } + /** + * Gets the configuration properties for the specified type. If the type does + * not exist, this will return {@code null}. + * + * @param configurationType + * the configuration type to retrieve. + * @return the property name and value pairs for the configuration type, or + * {@code null} if no configuration type exists. + */ public Map<String, String> getConfigurationProperties(String configurationType) { - Map<String, String> properties = m_configurations.get(configurationType); - if (null == properties) { - return Maps.newHashMap(); - } - - return properties; + return m_configurations.get(configurationType); } /** @@ -143,7 +145,12 @@ public class ClusterInformation { * @return the property value, or {@code null} if it does not exist. */ public String getConfigurationProperty(String configurationType, String propertyName) { - return getConfigurationProperties(configurationType).get(propertyName); + Map<String, String> configType = getConfigurationProperties(configurationType); + if (null == configType) { + return null; + } + + return configType.get(propertyName); } /** diff --git a/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeAction.java b/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeAction.java index 1e25c34..a34cee6 100644 --- a/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeAction.java +++ b/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeAction.java @@ -35,13 +35,14 @@ public interface UpgradeAction { * * @param clusterInformation * the cluster information, such as topology, configurations, etc. - * + * @param upgradeInformation + * the upgrade type, direction, services, repository versions, etc. * @return the changes to perform during the upgrade, such as updating * configurations. * @throws UpgradeActionException * if the class is unable to create the operations for the Ambari * Server to execute. */ - UpgradeActionOperations getOperations(ClusterInformation clusterInformation) - throws UpgradeActionException; + UpgradeActionOperations getOperations(ClusterInformation clusterInformation, + UpgradeInformation upgradeInformation) throws UpgradeActionException; } diff --git a/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeActionOperations.java b/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeActionOperations.java index ddba98c..8a17538 100644 --- a/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeActionOperations.java +++ b/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeActionOperations.java @@ -18,12 +18,16 @@ package org.apache.ambari.spi.upgrade; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; /** * The {@link UpgradeActionOperations} is used to instruct Ambari Server to * perform actions during an upgrade. It is returned by - * {@link UpgradeAction#getOperations()}. + * {@link UpgradeAction#getOperations(org.apache.ambari.spi.ClusterInformation, UpgradeInformation)} */ public class UpgradeActionOperations { @@ -33,13 +37,36 @@ public class UpgradeActionOperations { private List<ConfigurationChanges> m_configurationChanges; /** + * Any configuration types which should be completely removed. + */ + private Set<String> m_configurationTypeRemovals; + + /** * A buffer that the {@link UpgradeAction} can use to pass messages back to * Ambari to display to the user. */ - private StringBuilder m_standardOutput; + private String m_standardOutput; + + /** + * Sets configuration changes which are a part of the actions to be performed + * during the upgrade for a single configuration type only. If multiple + * configuration types are being updated, then + * {@link #setConfigurationChanges(List)} should be used. + * + * @param configurationChanges + * the configuration changes to make. + * @return an instance of the {@link UpgradeActionOperations} with the value + * set. + * @see #setConfigurationChanges(List) + */ + public UpgradeActionOperations setConfigurationChanges( + ConfigurationChanges configurationChanges) { + setConfigurationChanges(Collections.singletonList(configurationChanges)); + return this; + } /** - * Sets configuration changes which are a part of the actions to be perfomred + * Sets configuration changes which are a part of the actions to be performed * during the upgrade. * * @param configurationChanges @@ -54,14 +81,48 @@ public class UpgradeActionOperations { } /** - * Sets a {@link StringBuilder} which is used by the server to display - * messages about what the action did. + * Adds a single configuration change to the operations which should be + * performed. This might be more useful thank the bulk methods, such as + * {@link #setConfigurationChanges(List)}. + * + * @param configurationChanges + * the configuration changes to make. + * @return an instance of the {@link UpgradeActionOperations} with the value + * set. + */ + public UpgradeActionOperations addConfigurationChange(ConfigurationChanges configurationChanges) { + if (null == m_configurationChanges) { + m_configurationChanges = new ArrayList<>(); + } + + m_configurationChanges.add(configurationChanges); + return this; + } + + /** + * Sets any configuration types which should be completely removed. + * + * @param configurationTypeRemovals + * the configuration types to be removed, if any. + * @return an instance of the {@link UpgradeActionOperations} with the value + * set. + */ + public UpgradeActionOperations setConfigurationTypeRemoval( + Set<String> configurationTypeRemovals) { + m_configurationTypeRemovals = configurationTypeRemovals; + return this; + } + + /** + * Sets the standard output which will be used by the server to display + * information about what actions are being performed. * * @param standardOutput + * the output which will be displayed by the upgrade process. * @return an instance of the {@link UpgradeActionOperations} with the value * set. */ - public UpgradeActionOperations setStandardOutput(StringBuilder standardOutput) { + public UpgradeActionOperations setStandardOutput(String standardOutput) { m_standardOutput = standardOutput; return this; } @@ -76,13 +137,22 @@ public class UpgradeActionOperations { } /** + * Gets the configuration types which should be removed, if any. + * + * @return the configuration types which should be completely removed, if any. + */ + public Set<String> getConfigurationTypeRemovals() { + return m_configurationTypeRemovals; + } + + /** * Gets the standard output, if any, for the server to display as part of the * action being run. * * @return any messages that should be display along with the command's * status. */ - public StringBuilder getStandardOutput() { + public String getStandardOutput() { return m_standardOutput; } @@ -117,20 +187,34 @@ public class UpgradeActionOperations { private final List<PropertyChange> m_changes = new ArrayList<>(); /** + * {@code true} if the only changes included are removals (or there are no + * changes at all), {@code false} if there are additions and/or + * modifications as well. + */ + private boolean m_onlyRemovals = true; + + /** * Constructor. * * @param configType + * the name of the configuration type, such as {@code foo-site}. */ public ConfigurationChanges(String configType) { m_configType = configType; } /** + * Sets either a new or an update to an existing configuration property. + * * @param propertyName + * the name of the property. * @param propertyValue - * @return + * the value for the property. + * @return an instance of this class with the value set. */ public ConfigurationChanges set(String propertyName, String propertyValue) { + m_onlyRemovals = false; + PropertyChange propertyChange = new PropertyChange(ChangeType.SET, propertyName, propertyValue); @@ -139,8 +223,11 @@ public class UpgradeActionOperations { } /** + * Marks a configuration property for removal. + * * @param propertyName - * @return + * the name of the property to remove. + * @return an instance of this class with the property marked for removal. */ public ConfigurationChanges remove(String propertyName) { PropertyChange propertyChange = new PropertyChange(ChangeType.REMOVE, propertyName, null); @@ -161,11 +248,67 @@ public class UpgradeActionOperations { * Gets all of the additions, updates, and removals for this configuration * type. * - * @return + * @return all of the various property changes, including additions and + * removals. */ public List<PropertyChange> getPropertyChanges() { return m_changes; } + + /** + * Gets whether the only changes included for this configuration type are + * removals (or there are no changes at all of any kind). If there are any + * additions or modifications, this will be {@code false}. + * + * @return whether there are only removals in this change request, or if + * there are also additions or modifications to properties. + */ + public boolean isOnlyRemovals() { + return m_onlyRemovals; + } + + /** + * Gets whether there are no changes yet for this configuration change type. + * + * @return {@code true} if there are no changes yet, otherwise + * {@code false}. + */ + public boolean isEmpty() { + return null == m_changes || m_changes.isEmpty(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + if(m_changes.isEmpty()) { + return "There are no configuration changes"; + } + + StringBuilder buffer = new StringBuilder(m_configType); + buffer.append(System.lineSeparator()); + + for( PropertyChange propertyChange : m_changes ) { + switch(propertyChange.getChangeType()) { + case REMOVE: + buffer.append(" Removed " ).append(propertyChange.getPropertyName()); + break; + case SET: + buffer + .append(" Set " ) + .append(propertyChange.getPropertyName()) + .append(" to " ) + .append(StringUtils.abbreviateMiddle(propertyChange.getPropertyValue(), "\u2026", 30)); + break; + default: + break; + + } + } + + return buffer.toString(); + } } /** @@ -196,8 +339,7 @@ public class UpgradeActionOperations { * @param propertyName * the name of the property being added, updated, or removed. * @param propertyValue - * the value to add/update if the type is - * {@link ConfigurationChangeType#SET}. + * the value to add/update if the type is {@link ChangeType#SET}. */ public PropertyChange(ChangeType changeType, String propertyName, String propertyValue) { @@ -226,7 +368,7 @@ public class UpgradeActionOperations { /** * Gets the name of the property value to set if the configuration type is - * {@link ConfigurationChangeType#SET}. + * {@link ChangeType#SET} * * @return the property value. */ diff --git a/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeInformation.java b/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeInformation.java new file mode 100644 index 0000000..19de747 --- /dev/null +++ b/ambari-server-spi/src/main/java/org/apache/ambari/spi/upgrade/UpgradeInformation.java @@ -0,0 +1,131 @@ +/** + * 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.spi.upgrade; + +import java.util.Map; + +import org.apache.ambari.spi.RepositoryVersion; + +/** + * The {@link UpgradeInformation} class contains information about a running + * upgrade or downgrade. + */ +public class UpgradeInformation { + + /** + * {@code true} if the direction is upgrade, {@code false} if it is a + * downgrade. + */ + private final boolean m_isUpgrade; + + /** + * The orchestration type of the upgrade. + */ + private final UpgradeType m_upgradeType; + + /** + * The target version of the upgrade or downgrade. + */ + private final RepositoryVersion m_targetVersion; + + /** + * The source version of every service in the upgrade. + */ + private final Map<String, RepositoryVersion> m_sourceVersions; + + /** + * The target version of every service in the upgrade. + */ + private final Map<String, RepositoryVersion> m_targetVersions; + + /** + * Constructor. + * + * @param isUpgrade + * {@code true} if this is an upgrade, {@code false} otherwise. + * @param upgradeType + * the orchestration type of the upgrade. + * @param targetVersion + * the target version for all services and components in the upgrade + * or downgrade. If this is an upgrade, then this is the version tha + * all services are moving to. If this is a downgrade, then this is + * the version that all services are coming back from. + * @param sourceVersions + * the versions that all services and components are coming from. + * @param targetVersions + * the versions that all services and components in the upgrade are + * moving to. + */ + public UpgradeInformation(boolean isUpgrade, UpgradeType upgradeType, + RepositoryVersion targetVersion, Map<String, RepositoryVersion> sourceVersions, + Map<String, RepositoryVersion> targetVersions) { + m_isUpgrade = isUpgrade; + m_upgradeType = upgradeType; + m_targetVersion = targetVersion; + m_sourceVersions = sourceVersions; + m_targetVersions = targetVersions; + } + + /** + * {@code true} if this is an upgrade, {@code false} otherwise. + * + * @return the upgrade direction. + */ + public boolean isUpgrade() { + return m_isUpgrade; + } + + /** + * The orchestration type of the upgrade. + * + * @return the orchestration type. + */ + public UpgradeType getUpgradeType() { + return m_upgradeType; + } + + /** + * The target version for all services and components in the upgrade or + * downgrade. If this is an upgrade, then this is the version tha all services + * are moving to. If this is a downgrade, then this is the version that all + * services are coming back from. + * + * @return the target versions for all services. + */ + public RepositoryVersion getRepositoryVersion() { + return m_targetVersion; + } + + /** + * The versions that all services and components are coming from. + * + * @return the source versions of all services. + */ + public Map<String, RepositoryVersion> getSourceVersions() { + return m_sourceVersions; + } + + /** + * The versions that all services and components in the upgrade are moving to. + * + * @return the target versions for all services. + */ + public Map<String, RepositoryVersion> getTargetVersions() { + return m_targetVersions; + } +} diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java index 358de55..ef63538 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java @@ -47,16 +47,14 @@ import javax.persistence.UniqueConstraint; import org.apache.ambari.annotations.Experimental; import org.apache.ambari.annotations.ExperimentalFeature; import org.apache.ambari.server.StaticallyInject; -import org.apache.ambari.server.stack.upgrade.RepositoryVersionHelper; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.repository.VersionDefinitionXml; import org.apache.ambari.spi.RepositoryType; +import org.apache.ambari.spi.RepositoryVersion; import org.apache.commons.lang.StringUtils; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; -import com.google.inject.Inject; -import com.google.inject.Provider; @Entity @Table(name = "repo_version", uniqueConstraints = { @@ -93,9 +91,6 @@ import com.google.inject.Provider; query = "SELECT repositoryVersion FROM RepositoryVersionEntity repositoryVersion WHERE repositoryVersion IN (SELECT DISTINCT sd1.desiredRepositoryVersion FROM ServiceDesiredStateEntity sd1 WHERE sd1.desiredRepositoryVersion IN ?1)") }) @StaticallyInject public class RepositoryVersionEntity { - @Inject - private static Provider<RepositoryVersionHelper> repositoryVersionHelperProvider; - @Id @Column(name = "repo_version_id") @GeneratedValue(strategy = GenerationType.TABLE, generator = "repository_version_id_generator") @@ -504,4 +499,14 @@ public class RepositoryVersionEntity { repoOsEntity.setRepositoryVersionEntity(this); } } + + /** + * Builds a {@link RepositoryVersion} instance type from this entity. + * + * @return a single POJO to represent this entity. + */ + public RepositoryVersion getRepositoryVersion() { + return new RepositoryVersion(getId(), getStackName(), getStackVersion(), + getStackId().getStackId(), getVersion(), getType()); + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java index ea4d007..52c85e1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/AbstractUpgradeServerAction.java @@ -19,6 +19,7 @@ package org.apache.ambari.server.serveraction.upgrades; import org.apache.ambari.server.agent.stomp.AgentConfigsHolder; import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.orm.dao.UpgradeDAO; import org.apache.ambari.server.orm.entities.UpgradeEntity; import org.apache.ambari.server.serveraction.AbstractServerAction; @@ -27,6 +28,7 @@ import org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeContextFactory; import org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeHelper; 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.StackInfo; import com.google.gson.Gson; @@ -64,6 +66,9 @@ public abstract class AbstractUpgradeServerAction extends AbstractServerAction { @Inject private UpgradeContextFactory m_upgradeContextFactory; + /** + * Used for updating push data to the agents. + */ @Inject protected AgentConfigsHolder agentConfigsHolder; @@ -74,6 +79,19 @@ public abstract class AbstractUpgradeServerAction extends AbstractServerAction { protected Provider<AmbariMetaInfo> m_metainfoProvider; /** + * Used for manipulting configurations, such as removing entire types and + * creating new ones. + */ + @Inject + protected ConfigHelper m_configHelper; + + /** + * Who knows what this is used for or why it even exists. + */ + @Inject + protected AmbariManagementController m_amc; + + /** * Gets the injected instance of the {@link Gson} serializer/deserializer. * * @return the injected {@link Gson} instance. diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerAction.java index 839cd94..154352e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerAction.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; @@ -28,6 +29,7 @@ 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.serveraction.ServerAction; +import org.apache.ambari.server.stack.upgrade.Direction; import org.apache.ambari.server.stack.upgrade.UpgradePack; import org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeContext; import org.apache.ambari.server.state.Cluster; @@ -98,14 +100,15 @@ public class PluginUpgradeServerAction extends AbstractUpgradeServerAction { try { ClusterInformation clusterInformation = cluster.buildClusterInformation(); UpgradeActionOperations upgradeActionOperations = upgradeAction.getOperations( - clusterInformation); + clusterInformation, upgradeContext.buildUpgradeInformation()); // update configurations - changeConfigurations(cluster, upgradeActionOperations.getConfigurationChanges()); + changeConfigurations(cluster, upgradeActionOperations.getConfigurationChanges(), upgradeContext); + removeConfigurationTypes(cluster, upgradeActionOperations.getConfigurationTypeRemovals()); standardOutput = "Successfully executed " + pluginClassName; if(null != upgradeActionOperations.getStandardOutput()) { - standardOutput = upgradeActionOperations.getStandardOutput().toString(); + standardOutput = upgradeActionOperations.getStandardOutput(); } } catch (UpgradeActionException exception) { LOG.error("Unable to run the upgrade action {}", pluginClassName, exception); @@ -124,22 +127,51 @@ public class PluginUpgradeServerAction extends AbstractUpgradeServerAction { } /** - * Updates configurations in the cluster. + * Updates configurations in the cluster. This will create new configuration + * types if changes are required for one which does not exist. * * @param cluster * the cluster used to retrieve the configurations. * @param configurationChanges * the changes to make. + * @param upgradeContext + * upgrade information for the current upgrade or downgrade. * @throws AmbariException * if there was a problem determining what change to make or while * making changes. */ private void changeConfigurations(Cluster cluster, - List<ConfigurationChanges> configurationChanges) + List<ConfigurationChanges> configurationChanges, UpgradeContext upgradeContext) throws AmbariException { + if (null == configurationChanges) { + return; + } + for (ConfigurationChanges configTypeChanges : configurationChanges) { String configType = configTypeChanges.getConfigType(); + + // the configuration could be null, so try to figure out if we're creating + // it by checking all of the changes being made Config config = cluster.getDesiredConfigByType(configType); + if (null == config) { + // no additions/updates, so just skip it entirely + if (configTypeChanges.isOnlyRemovals()) { + continue; + } + + Direction direction = upgradeContext.getDirection(); + String serviceVersionNote = String.format("%s %s %s", direction.getText(true), + direction.getPreposition(), upgradeContext.getRepositoryVersion().getVersion()); + + m_configHelper.createConfigType(cluster, upgradeContext.getRepositoryVersion().getStackId(), + m_amc, configType, new HashMap<>(), m_amc.getAuthName(), serviceVersionNote); + + config = cluster.getDesiredConfigByType(configType); + if (null == config) { + throw new AmbariException( + String.format("Unable to create the % configuration type", configType)); + } + } List<PropertyChange> propertyChanges = configTypeChanges.getPropertyChanges(); for (PropertyChange propertyChange : propertyChanges) { @@ -165,6 +197,27 @@ public class PluginUpgradeServerAction extends AbstractUpgradeServerAction { } /** + * Remove the specified configuration types from the cluster. + * + * @param cluster + * the cluster to remove the configurations from. + * @param configurationTypeRemovals + * the types to remove. + * @throws AmbariException + * if there were problems removing the configuration types. + */ + private void removeConfigurationTypes(Cluster cluster, Set<String> configurationTypeRemovals) + throws AmbariException { + if (null == configurationTypeRemovals) { + return; + } + + for (String configType : configurationTypeRemovals) { + m_configHelper.removeConfigsByType(cluster, configType); + } + } + + /** * Gets the fully qualified classname of the {@link UpgradeAction} class which * will be executed. This will look in the command parameters of the execution * command for {@link ServerAction#WRAPPED_CLASS_NAME}. diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/orchestrate/UpgradeContext.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/orchestrate/UpgradeContext.java index d2e68bb..dc1cf8e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/orchestrate/UpgradeContext.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/orchestrate/UpgradeContext.java @@ -86,7 +86,9 @@ import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.repository.ClusterVersionSummary; import org.apache.ambari.server.state.repository.VersionDefinitionXml; import org.apache.ambari.spi.RepositoryType; +import org.apache.ambari.spi.RepositoryVersion; import org.apache.ambari.spi.upgrade.UpgradeCheckStatus; +import org.apache.ambari.spi.upgrade.UpgradeInformation; import org.apache.ambari.spi.upgrade.UpgradeType; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; @@ -1457,4 +1459,44 @@ public class UpgradeContext { return packs.get(upgrade.getUpgradePackage()); } + + /** + * Builds a {@link UpgradeInformation} instance from a {@link Cluster} where + * there is an upgrade in progress. + * + * @return the {@link UpgradeInformation} instance comprised of simple POJOs + * and SPI classes. + */ + public UpgradeInformation buildUpgradeInformation() { + RepositoryVersionEntity targetRepositoryVersionEntity = m_repositoryVersion; + + Map<String, Service> clusterServices = m_cluster.getServices(); + Map<String, RepositoryVersion> clusterServiceVersions = new HashMap<>(); + if (null != clusterServices) { + for (Map.Entry<String, Service> serviceEntry : clusterServices.entrySet()) { + Service service = serviceEntry.getValue(); + RepositoryVersionEntity desiredRepositoryEntity = service.getDesiredRepositoryVersion(); + RepositoryVersion desiredRepositoryVersion = desiredRepositoryEntity.getRepositoryVersion(); + + clusterServiceVersions.put(serviceEntry.getKey(), desiredRepositoryVersion); + } + } + + Map<String, RepositoryVersionEntity> sourceVersionEntites = getSourceVersions(); + Map<String, RepositoryVersionEntity> targetVersionEntites = getTargetVersions(); + Map<String, RepositoryVersion> sourceVersions = new HashMap<>(); + Map<String, RepositoryVersion> targetVersions = new HashMap<>(); + + sourceVersionEntites.forEach( + (service, repositoryVersion) -> sourceVersions.put(service, repositoryVersion.getRepositoryVersion())); + + targetVersionEntites.forEach( + (service, repositoryVersion) -> targetVersions.put(service, repositoryVersion.getRepositoryVersion())); + + UpgradeInformation upgradeInformation = new UpgradeInformation( + getDirection().isUpgrade(), getType(), + targetRepositoryVersionEntity.getRepositoryVersion(), sourceVersions, targetVersions); + + return upgradeInformation; + } } \ No newline at end of file diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java index 897a433..e23c571 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java @@ -2950,12 +2950,7 @@ public class ClusterImpl implements Cluster { for (Map.Entry<String, Service> serviceEntry : clusterServices.entrySet()) { Service service = serviceEntry.getValue(); RepositoryVersionEntity desiredRepositoryEntity = service.getDesiredRepositoryVersion(); - StackId stackId = desiredRepositoryEntity.getStackId(); - - RepositoryVersion desiredRepositoryVersion = new RepositoryVersion( - desiredRepositoryEntity.getId(), stackId.getStackName(), stackId.getStackVersion(), - stackId.getStackId(), desiredRepositoryEntity.getVersion(), - desiredRepositoryEntity.getType()); + RepositoryVersion desiredRepositoryVersion = desiredRepositoryEntity.getRepositoryVersion(); clusterServiceVersions.put(serviceEntry.getKey(), desiredRepositoryVersion); } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerActionTest.java index 49b31af..cd88ff9 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerActionTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/PluginUpgradeServerActionTest.java @@ -17,6 +17,7 @@ */ package org.apache.ambari.server.serveraction.upgrades; +import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; @@ -28,19 +29,26 @@ import java.util.Map; import org.apache.ambari.server.agent.ExecutionCommand; import org.apache.ambari.server.agent.stomp.AgentConfigsHolder; import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.controller.AmbariManagementController; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.serveraction.ServerAction; +import org.apache.ambari.server.stack.upgrade.Direction; import org.apache.ambari.server.stack.upgrade.UpgradePack; import org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeContext; 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.ConfigHelper; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.spi.ClusterInformation; +import org.apache.ambari.spi.RepositoryType; +import org.apache.ambari.spi.RepositoryVersion; import org.apache.ambari.spi.exceptions.UpgradeActionException; import org.apache.ambari.spi.upgrade.UpgradeAction; import org.apache.ambari.spi.upgrade.UpgradeActionOperations; import org.apache.ambari.spi.upgrade.UpgradeActionOperations.ConfigurationChanges; +import org.apache.ambari.spi.upgrade.UpgradeInformation; import org.easymock.EasyMockSupport; import org.junit.After; import org.junit.Before; @@ -59,11 +67,12 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { private static final String CLUSTER_NAME = "c1"; private static final String FOO_SITE = "foo-site"; + private static final String AUTH_USERNAME = "admin"; private static final String CLASS_NAME = MockUpgradeAction.class.getName(); private final Map<String, String> m_commandParams = new HashMap<>(); - private final StackId m_mockStackId = createNiceMock(StackId.class); + private final StackId m_stackId = new StackId("FOO-STACK-1.0"); private final StackInfo m_mockStackInfo = createNiceMock(StackInfo.class); private final Clusters m_mockClusters = createNiceMock(Clusters.class); @@ -74,9 +83,14 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { private final UpgradePack m_mockUpgradePack = createNiceMock(UpgradePack.class); private final ClassLoader m_mockClassLoader = createNiceMock(ClassLoader.class); private final AmbariMetaInfo m_mockMetaInfo = createNiceMock(AmbariMetaInfo.class); + private final AmbariManagementController m_mockController = createNiceMock(AmbariManagementController.class); - private final AgentConfigsHolder m_mockAgentConfigsHolder = createNiceMock( - AgentConfigsHolder.class); + private final RepositoryVersion m_repositoryVersion = new RepositoryVersion(1L, "FOO-STACK", + "1.0", "FOO-STACK-1.0", "1.0.0.0-b1", RepositoryType.STANDARD); + + private final RepositoryVersionEntity m_mocRepoEntity = createNiceMock(RepositoryVersionEntity.class); + private final AgentConfigsHolder m_mockAgentConfigsHolder = createNiceMock(AgentConfigsHolder.class); + private final ConfigHelper m_mockConfigHelper = createNiceMock(ConfigHelper.class); private PluginUpgradeServerAction m_action; @@ -84,7 +98,7 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { * @throws Exception */ @Before - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) public void before() throws Exception { m_action = PowerMock.createNicePartialMock(PluginUpgradeServerAction.class, "getUpgradeContext", "createCommandReport", "getClusters"); @@ -98,10 +112,21 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { m_action.m_clusters = m_mockClusters; m_action.m_metainfoProvider = () -> m_mockMetaInfo; + m_action.m_amc = m_mockController; + m_action.m_configHelper = m_mockConfigHelper; + + expect(m_mockController.getAuthName()).andReturn(AUTH_USERNAME).anyTimes(); + + expect(m_mocRepoEntity.getStackId()).andReturn(m_stackId).anyTimes(); + expect(m_mocRepoEntity.getVersion()).andReturn("1.0.0.0-b1").anyTimes(); + expect(m_mocRepoEntity.getRepositoryVersion()).andReturn(m_repositoryVersion).anyTimes(); expect(m_mockUpgradeContext.getUpgradePack()).andReturn(m_mockUpgradePack).atLeastOnce(); - expect(m_mockUpgradePack.getOwnerStackId()).andReturn(m_mockStackId).atLeastOnce(); - expect(m_mockMetaInfo.getStack(m_mockStackId)).andReturn(m_mockStackInfo).atLeastOnce(); + expect(m_mockUpgradeContext.getDirection()).andReturn(Direction.UPGRADE).anyTimes(); + expect(m_mockUpgradeContext.getRepositoryVersion()).andReturn(m_mocRepoEntity).anyTimes(); + + expect(m_mockUpgradePack.getOwnerStackId()).andReturn(m_stackId).atLeastOnce(); + expect(m_mockMetaInfo.getStack(m_stackId)).andReturn(m_mockStackInfo).atLeastOnce(); expect(m_mockStackInfo.getLibraryClassLoader()).andReturn(m_mockClassLoader).atLeastOnce(); expect(m_action.getClusters()).andReturn(m_mockClusters).anyTimes(); @@ -110,17 +135,6 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { Class clazz = MockUpgradeAction.class; expect(m_mockClassLoader.loadClass(CLASS_NAME)).andReturn(clazz).atLeastOnce(); - expect(m_mockCluster.getDesiredConfigByType(FOO_SITE)).andReturn(m_mockConfig).once(); - - Map<String, String> configUpdates = new HashMap<>(); - configUpdates.put("property-name", "property-value"); - - m_mockConfig.updateProperties(configUpdates); - expectLastCall().once(); - - m_mockConfig.save(); - expectLastCall().once(); - m_action.agentConfigsHolder = m_mockAgentConfigsHolder; m_commandParams.put("clusterName", CLUSTER_NAME); @@ -144,6 +158,53 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { */ @Test public void testExecute() throws Exception { + // mock out the config stuff + expect(m_mockCluster.getDesiredConfigByType(FOO_SITE)).andReturn(m_mockConfig).once(); + + Map<String, String> configUpdates = new HashMap<>(); + configUpdates.put("property-name", "property-value"); + + m_mockConfig.updateProperties(configUpdates); + expectLastCall().once(); + + m_mockConfig.save(); + expectLastCall().once(); + + PowerMock.replay(m_action); + replayAll(); + + m_action.execute(null); + + // easymock verify + verifyAll(); + } + + /** + * Tests that when a new configuration type is specified in the list of + * configurattion changes, that the new type is created first. + * + * @throws Exception + */ + @Test + public void testExecuteAddNewConfiguration() throws Exception { + // mock two different answers + expect(m_mockCluster.getDesiredConfigByType(FOO_SITE)).andReturn(null).once(); + expect(m_mockCluster.getDesiredConfigByType(FOO_SITE)).andReturn(m_mockConfig).once(); + + m_mockConfigHelper.createConfigType(eq(m_mockCluster), eq(m_stackId), eq(m_mockController), + eq(FOO_SITE), eq(new HashMap<>()), eq(AUTH_USERNAME), eq("Upgrade to 1.0.0.0-b1")); + + expectLastCall(); + + Map<String, String> configUpdates = new HashMap<>(); + configUpdates.put("property-name", "property-value"); + + m_mockConfig.updateProperties(configUpdates); + expectLastCall().once(); + + m_mockConfig.save(); + expectLastCall().once(); + PowerMock.replay(m_action); replayAll(); @@ -162,18 +223,18 @@ public class PluginUpgradeServerActionTest extends EasyMockSupport { * {@inheritDoc} */ @Override - public UpgradeActionOperations getOperations(ClusterInformation clusterInformation) - throws UpgradeActionException { + public UpgradeActionOperations getOperations(ClusterInformation clusterInformation, + UpgradeInformation upgradeInformation) throws UpgradeActionException { List<ConfigurationChanges> allChanges = new ArrayList<>(); ConfigurationChanges configurationTypeChanges = new ConfigurationChanges(FOO_SITE); configurationTypeChanges.set( "property-name", "property-value"); allChanges.add(configurationTypeChanges); - StringBuilder standardOutput = new StringBuilder("Standard Output"); - UpgradeActionOperations upgradeActionOperations = new UpgradeActionOperations(); - upgradeActionOperations.setConfigurationChanges(allChanges).setStandardOutput(standardOutput); + upgradeActionOperations + .setConfigurationChanges(allChanges) + .setStandardOutput("Standard Output"); return upgradeActionOperations; }