AMBARI-19574 - Add upgrade logic for the heap dump control option added in HDP 2.6 stack (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/410f2943 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/410f2943 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/410f2943 Branch: refs/heads/branch-dev-patch-upgrade Commit: 410f2943d5babf6b9bd3e2f225fbbe9ac5761ee2 Parents: 4dac278 Author: Jonathan Hurley <jhur...@hortonworks.com> Authored: Mon Jan 16 20:26:24 2017 -0500 Committer: Jonathan Hurley <jhur...@hortonworks.com> Committed: Tue Jan 17 18:51:50 2017 -0500 ---------------------------------------------------------------------- .../serveraction/upgrades/ConfigureAction.java | 142 +++++++++++--- .../upgrade/ConfigUpgradeChangeDefinition.java | 194 +++++++++++++------ .../state/stack/upgrade/ConfigureTask.java | 45 ++--- .../stacks/HDP/2.5/upgrades/config-upgrade.xml | 27 +++ .../HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml | 19 +- .../stacks/HDP/2.5/upgrades/upgrade-2.6.xml | 14 ++ .../src/main/resources/upgrade-config.xsd | 16 ++ .../upgrades/ConfigureActionTest.java | 147 +++++++++++--- 8 files changed, 455 insertions(+), 149 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java index 97280ee..a42e667 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java @@ -46,6 +46,7 @@ import org.apache.ambari.server.state.DesiredConfig; import org.apache.ambari.server.state.PropertyInfo; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Insert; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Masked; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Replace; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Transfer; @@ -185,7 +186,7 @@ public class ConfigureAction extends AbstractServerAction { // such as hdfs-site or hbase-env String configType = commandParameters.get(ConfigureTask.PARAMETER_CONFIG_TYPE); - // extract transfers + // extract setters List<ConfigurationKeyValue> keyValuePairs = Collections.emptyList(); String keyValuePairJson = commandParameters.get(ConfigureTask.PARAMETER_KEY_VALUE_PAIRS); if (null != keyValuePairJson) { @@ -212,14 +213,22 @@ public class ConfigureAction extends AbstractServerAction { replacements = getAllowedReplacements(cluster, configType, replacements); } + // extract insertions + List<Insert> insertions = Collections.emptyList(); + String insertJson = commandParameters.get(ConfigureTask.PARAMETER_INSERTIONS); + if (null != insertJson) { + insertions = m_gson.fromJson( + insertJson, new TypeToken<List<Insert>>(){}.getType()); + } + // if there is nothing to do, then skip the task - if (keyValuePairs.isEmpty() && transfers.isEmpty() && replacements.isEmpty()) { - String message = "cluster={0}, type={1}, transfers={2}, replacements={3}, configurations={4}"; + if (keyValuePairs.isEmpty() && transfers.isEmpty() && replacements.isEmpty() && insertions.isEmpty()) { + String message = "cluster={0}, type={1}, transfers={2}, replacements={3}, insertions={4}, configurations={5}"; message = MessageFormat.format(message, clusterName, configType, transfers, replacements, - keyValuePairs); + insertions, keyValuePairs); StringBuilder buffer = new StringBuilder( - "Skipping this configuration task since none of the conditions were met and there are no transfers or replacements").append("\n"); + "Skipping this configuration task since none of the conditions were met and there are no transfers, replacements, or insertions.").append("\n"); buffer.append(message); @@ -229,9 +238,12 @@ public class ConfigureAction extends AbstractServerAction { // if only 1 of the required properties was null and no transfer properties, // then something went wrong if (null == clusterName || null == configType - || (keyValuePairs.isEmpty() && transfers.isEmpty() && replacements.isEmpty())) { - String message = "cluster={0}, type={1}, transfers={2}, replacements={3}, configurations={4}"; - message = MessageFormat.format(message, clusterName, configType, transfers, replacements, keyValuePairs); + || (keyValuePairs.isEmpty() && transfers.isEmpty() && replacements.isEmpty() && insertions.isEmpty())) { + String message = "cluster={0}, type={1}, transfers={2}, replacements={3}, insertions={4}, configurations={5}"; + + message = MessageFormat.format(message, clusterName, configType, transfers, replacements, + insertions, keyValuePairs); + return createCommandReport(0, HostRoleStatus.FAILED, "{}", "", message); } @@ -251,7 +263,7 @@ public class ConfigureAction extends AbstractServerAction { // !!! initial reference values Map<String, String> base = config.getProperties(); - Map<String, String> newValues = new HashMap<String, String>(base); + Map<String, String> newValues = new HashMap<>(base); boolean changedValues = false; @@ -287,7 +299,7 @@ public class ConfigureAction extends AbstractServerAction { case YAML_ARRAY: { // turn c6401,c6402 into ['c6401',c6402'] String[] splitValues = StringUtils.split(valueToCopy, ','); - List<String> quotedValues = new ArrayList<String>(splitValues.length); + List<String> quotedValues = new ArrayList<>(splitValues.length); for (String splitValue : splitValues) { quotedValues.add("'" + StringUtils.trim(splitValue) + "'"); } @@ -306,7 +318,8 @@ public class ConfigureAction extends AbstractServerAction { newValues.put(transfer.toKey, valueToCopy); // append standard output - outputBuffer.append(MessageFormat.format("Created {0}/{1} = \"{2}\"\n", configType, + updateBufferWithMessage(outputBuffer, MessageFormat.format("Created {0}/{1} = \"{2}\"", + configType, transfer.toKey, mask(transfer, valueToCopy))); } break; @@ -319,15 +332,17 @@ public class ConfigureAction extends AbstractServerAction { changedValues = true; // append standard output - outputBuffer.append(MessageFormat.format("Renamed {0}/{1} to {2}/{3}\n", configType, + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Renamed {0}/{1} to {2}/{3}", configType, transfer.fromKey, configType, transfer.toKey)); + } else if (StringUtils.isNotBlank(transfer.defaultValue)) { newValues.put(transfer.toKey, transfer.defaultValue); changedValues = true; // append standard output - outputBuffer.append(MessageFormat.format( - "Created {0}/{1} with default value \"{2}\"\n", + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Created {0}/{1} with default value \"{2}\"", configType, transfer.toKey, mask(transfer, transfer.defaultValue))); } @@ -337,15 +352,16 @@ public class ConfigureAction extends AbstractServerAction { newValues.clear(); // append standard output - outputBuffer.append(MessageFormat.format("Deleted all keys from {0}\n", configType)); + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Deleted all keys from {0}", configType)); for (String keeper : transfer.keepKeys) { if (base.containsKey(keeper) && base.get(keeper) != null) { newValues.put(keeper, base.get(keeper)); // append standard output - outputBuffer.append(MessageFormat.format("Preserved {0}/{1} after delete\n", - configType, keeper)); + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Preserved {0}/{1} after delete", configType, keeper)); } } @@ -358,7 +374,8 @@ public class ConfigureAction extends AbstractServerAction { newValues.put(changed, base.get(changed)); // append standard output - outputBuffer.append(MessageFormat.format("Preserved {0}/{1} after delete\n", + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Preserved {0}/{1} after delete", configType, changed)); } } @@ -369,7 +386,8 @@ public class ConfigureAction extends AbstractServerAction { changedValues = true; // append standard output - outputBuffer.append(MessageFormat.format("Deleted {0}/{1}\n", configType, + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Deleted {0}/{1}", configType, transfer.deleteKey)); } @@ -389,7 +407,8 @@ public class ConfigureAction extends AbstractServerAction { // !!! values are not changing, so make this a no-op if (null != oldValue && value.equals(oldValue)) { if (currentStack.equals(targetStack) && !changedValues) { - outputBuffer.append(MessageFormat.format( + updateBufferWithMessage(outputBuffer, + MessageFormat.format( "{0}/{1} for cluster {2} would not change, skipping setting", configType, key, clusterName)); @@ -409,40 +428,91 @@ public class ConfigureAction extends AbstractServerAction { if (StringUtils.isEmpty(value)) { message = MessageFormat.format("{0}/{1} changed to an empty value", configType, key); } else { - message = MessageFormat.format("{0}/{1} changed to \"{2}\"\n", configType, key, + message = MessageFormat.format("{0}/{1} changed to \"{2}\"", configType, key, mask(keyValuePair, value)); } - outputBuffer.append(message); + updateBufferWithMessage(outputBuffer, message); } } } - // !!! string replacements happen only on the new values. + // replacements happen only on the new values (as they are initialized from + // the existing pre-upgrade values) for (Replace replacement : replacements) { // the key might exist but might be null, so we need to check this // condition when replacing a part of the value String toReplace = newValues.get(replacement.key); if (StringUtils.isNotBlank(toReplace)) { if (!toReplace.contains(replacement.find)) { - outputBuffer.append(MessageFormat.format("String \"{0}\" was not found in {1}/{2}\n", + updateBufferWithMessage(outputBuffer, + MessageFormat.format("String \"{0}\" was not found in {1}/{2}", replacement.find, configType, replacement.key)); } else { String replaced = StringUtils.replace(toReplace, replacement.find, replacement.replaceWith); newValues.put(replacement.key, replaced); - outputBuffer.append( + updateBufferWithMessage(outputBuffer, MessageFormat.format("Replaced {0}/{1} containing \"{2}\" with \"{3}\"", configType, replacement.key, replacement.find, replacement.replaceWith)); - - outputBuffer.append(System.lineSeparator()); } } else { - outputBuffer.append(MessageFormat.format( + updateBufferWithMessage(outputBuffer, MessageFormat.format( "Skipping replacement for {0}/{1} because it does not exist or is empty.", configType, replacement.key)); - outputBuffer.append(System.lineSeparator()); + } + } + + // insertions happen only on the new values (as they are initialized from + // the existing pre-upgrade values) + for (Insert insert : insertions) { + String valueToInsertInto = newValues.get(insert.key); + + // if the key doesn't exist, then do no work + if (StringUtils.isNotBlank(valueToInsertInto)) { + // make this insertion idempotent - don't do it if the value already + // contains the content + if (StringUtils.contains(valueToInsertInto, insert.value)) { + updateBufferWithMessage(outputBuffer, + MessageFormat.format("Skipping insertion for {0}/{1} because it already contains {2}", + configType, insert.key, insert.value)); + + continue; + } + + // new line work + String valueToInsert = insert.value; + if (insert.newlineBefore) { + valueToInsert = System.lineSeparator() + valueToInsert; + } + + // new line work + if (insert.newlineAfter) { + valueToInsert = valueToInsert + System.lineSeparator(); + } + + switch (insert.insertType) { + case APPEND: + valueToInsertInto = valueToInsertInto + valueToInsert; + break; + case PREPEND: + valueToInsertInto = valueToInsert + valueToInsertInto; + break; + default: + LOG.error("Unable to insert {0}/{1} with unknown insertion type of {2}", configType, + insert.key, insert.insertType); + break; + } + + newValues.put(insert.key, valueToInsertInto); + + updateBufferWithMessage(outputBuffer, MessageFormat.format( + "Updated {0}/{1} by inserting {2}", configType, insert.key, insert.value)); + } else { + updateBufferWithMessage(outputBuffer, MessageFormat.format( + "Skipping insertion for {0}/{1} because it does not exist or is empty.", configType, + insert.key)); } } @@ -492,7 +562,7 @@ public class ConfigureAction extends AbstractServerAction { */ private List<String> findValuesToPreserve(String clusterName, Config config) throws AmbariException { - List<String> result = new ArrayList<String>(); + List<String> result = new ArrayList<>(); Map<String, Map<String, ThreeWayValue>> conflicts = m_mergeHelper.getConflicts(clusterName, config.getStackId()); @@ -519,7 +589,7 @@ public class ConfigureAction extends AbstractServerAction { // iterate over all properties for every cluster service; if the property // has the correct config type (ie oozie-site or hdfs-site) then add it to // the list of original stack propertiess - Set<String> stackPropertiesForType = new HashSet<String>(50); + Set<String> stackPropertiesForType = new HashSet<>(50); for (String serviceName : cluster.getServices().keySet()) { Set<PropertyInfo> serviceProperties = m_ambariMetaInfo.get().getServiceProperties( oldStack.getStackName(), oldStack.getStackVersion(), serviceName); @@ -700,4 +770,14 @@ public class ConfigureAction extends AbstractServerAction { return config.getProperties().get(propertyKey); } + + /** + * Appends the buffer with the message as well as a newline. + * + * @param buffer + * @param message + */ + private void updateBufferWithMessage(StringBuilder buffer, String message) { + buffer.append(message).append(System.lineSeparator()); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java index 31df790..5c0fba7 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigUpgradeChangeDefinition.java @@ -28,6 +28,8 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlEnumValue; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @@ -36,7 +38,7 @@ import org.apache.ambari.server.state.Config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.Gson; +import com.google.common.base.Objects; /** * The {@link ConfigUpgradeChangeDefinition} represents a configuration change. This change can be @@ -109,10 +111,6 @@ public class ConfigUpgradeChangeDefinition { public static final Float DEFAULT_PRIORITY = 1.0f; - /** - * Gson - */ - private Gson m_gson = new Gson(); /** * An optional brief description of config changes. @@ -137,6 +135,17 @@ public class ConfigUpgradeChangeDefinition { @XmlElement(name="regex-replace") private List<RegexReplace> regexReplacements; + /** + * Insert new content into an existing value by either prepending or + * appending. Each {@link Insert} will only run if: + * <ul> + * <li>The key specified by {@link Insert#key} exists. + * <li>The content specified by {@link Insert#value} is not found in the key's + * existing content. + * </ul> + */ + @XmlElement(name = "insert") + private List<Insert> inserts; /** * @return the config type @@ -250,6 +259,19 @@ public class ConfigUpgradeChangeDefinition { /** + * Gets the insertion directives. + * + * @return the inserts, or an empty list (never {@code null}). + */ + public List<Insert> getInsertions() { + if (null == inserts) { + return Collections.emptyList(); + } + + return inserts; + } + + /** * Used for configuration updates that should mask their values from being * printed in plain text. */ @@ -298,14 +320,12 @@ public class ConfigUpgradeChangeDefinition { @Override public String toString() { - return "Set{" + - ", key='" + key + '\'' + - ", value='" + value + '\'' + - ", ifKey='" + ifKey + '\'' + - ", ifType='" + ifType + '\'' + - ", ifValue='" + ifValue + '\'' + - ", ifKeyState='" + ifKeyState + '\'' + - '}'; + return Objects.toStringHelper("Set").add("key", key) + .add("value", value) + .add("ifKey", ifKey) + .add("ifType", ifType) + .add("ifValue",ifValue) + .add("ifKeyState", ifKeyState).omitNullValues().toString(); } } @@ -370,26 +390,24 @@ public class ConfigUpgradeChangeDefinition { * The keys to keep when the action is {@link TransferOperation#DELETE}. */ @XmlElement(name = "keep-key") - public List<String> keepKeys = new ArrayList<String>(); + public List<String> keepKeys = new ArrayList<>(); @Override public String toString() { - return "Transfer{" + - "operation=" + operation + - ", fromType='" + fromType + '\'' + - ", fromKey='" + fromKey + '\'' + - ", toKey='" + toKey + '\'' + - ", deleteKey='" + deleteKey + '\'' + - ", preserveEdits=" + preserveEdits + - ", defaultValue='" + defaultValue + '\'' + - ", coerceTo=" + coerceTo + - ", ifKey='" + ifKey + '\'' + - ", ifType='" + ifType + '\'' + - ", ifValue='" + ifValue + '\'' + - ", ifKeyState='" + ifKeyState + '\'' + - ", keepKeys=" + keepKeys + - '}'; + return Objects.toStringHelper(this).add("operation", operation) + .add("fromType", fromType) + .add("fromKey", fromKey) + .add("toKey", toKey) + .add("deleteKey", deleteKey) + .add("preserveEdits",preserveEdits) + .add("defaultValue", defaultValue) + .add("coerceTo", coerceTo) + .add("ifKey", ifKey) + .add("ifType", ifType) + .add("ifValue", ifValue) + .add("ifKeyState", ifKeyState) + .add("keepKeys", keepKeys).omitNullValues().toString(); } } @@ -420,15 +438,13 @@ public class ConfigUpgradeChangeDefinition { @Override public String toString() { - return "Replace{" + - "key='" + key + '\'' + - ", find='" + find + '\'' + - ", replaceWith='" + replaceWith + '\'' + - ", ifKey='" + ifKey + '\'' + - ", ifType='" + ifType + '\'' + - ", ifValue='" + ifValue + '\'' + - ", ifKeyState='" + ifKeyState + '\'' + - '}'; + return Objects.toStringHelper(this).add("key", key) + .add("find", find) + .add("replaceWith", replaceWith) + .add("ifKey", ifKey) + .add("ifType", ifType) + .add("ifValue", ifValue) + .add("ifKeyState", ifKeyState).omitNullValues().toString(); } } @@ -459,15 +475,13 @@ public class ConfigUpgradeChangeDefinition { @Override public String toString() { - return "RegexReplace{" + - "key='" + key + '\'' + - ", find='" + find + '\'' + - ", replaceWith='" + replaceWith + '\'' + - ", ifKey='" + ifKey + '\'' + - ", ifType='" + ifType + '\'' + - ", ifValue='" + ifValue + '\'' + - ", ifKeyState='" + ifKeyState + '\'' + - '}'; + return Objects.toStringHelper(this).add("key", key) + .add("find", find) + .add("replaceWith",replaceWith) + .add("ifKey", ifKey) + .add("ifType", ifType) + .add("ifValue", ifValue) + .add("ifKeyState", ifKeyState).omitNullValues().toString(); } /*** @@ -476,15 +490,85 @@ public class ConfigUpgradeChangeDefinition { */ public Replace copyToReplaceObject(){ Replace rep = new Replace(); - rep.find = this.find; - rep.key = this.key; - rep.replaceWith = this.replaceWith; - rep.ifKey = this.ifKey; - rep.ifType = this.ifType; - rep.ifValue = this.ifValue; - rep.ifKeyState = this.ifKeyState; + rep.find = find; + rep.key = key; + rep.replaceWith = replaceWith; + rep.ifKey = ifKey; + rep.ifType = ifType; + rep.ifValue = ifValue; + rep.ifKeyState = ifKeyState; return rep; } } -} + + /** + * Used to replace strings in a key with other strings. More complex scenarios + * will be possible with regex (when needed). If the value specified in + * {@link Insert#value} already exists, then it is not inserted again. + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "insert") + public static class Insert { + /** + * The key name + */ + @XmlAttribute(name = "key", required = true) + public String key; + + /** + * The value to insert. + */ + @XmlAttribute(name = "value", required = true) + public String value; + + /** + * The value to insert. + */ + @XmlAttribute(name = "insert-type", required = true) + public InsertType insertType = InsertType.APPEND; + + /** + * {@code true} to insert a new line before inserting the {@link #value}. + */ + @XmlAttribute(name = "newline-before") + public boolean newlineBefore = false; + + /** + * {@code true} to insert a new line after inserting the {@link #value}. + */ + @XmlAttribute(name = "newline-after") + public boolean newlineAfter = false; + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this).add("insertType", insertType) + .add("key", key) + .add("value",value) + .add("newlineBefore", newlineBefore) + .add("newlineAfter", newlineAfter).omitNullValues().toString(); + } + } + + /** + * The {@link InsertType} defines how to use the {@link Insert} directive. + */ + @XmlEnum + public enum InsertType { + /** + * Prepend the content. + */ + @XmlEnumValue("prepend") + PREPEND, + + /** + * Append the content. + */ + @XmlEnumValue("append") + APPEND + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java index f256eb0..b7be2ec 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ConfigureTask.java @@ -30,10 +30,9 @@ import javax.xml.bind.annotation.XmlType; import org.apache.ambari.server.serveraction.upgrades.ConfigureAction; import org.apache.ambari.server.state.Cluster; -import org.apache.ambari.server.state.Config; -import org.apache.ambari.server.state.DesiredConfig; import org.apache.ambari.server.state.stack.ConfigUpgradePack; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Insert; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Replace; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Transfer; import org.apache.commons.lang.StringUtils; @@ -86,6 +85,12 @@ public class ConfigureTask extends ServerSideActionTask { */ public static final String PARAMETER_REPLACEMENTS = "configure-task-replacements"; + /** + * Insertions can be several per task, so they're passed in as a json-ified + * list of objects. + */ + public static final String PARAMETER_INSERTIONS = "configure-task-insertions"; + public static final String actionVerb = "Configuring"; /** @@ -222,6 +227,12 @@ public class ConfigureTask extends ServerSideActionTask { configParameters.put(ConfigureTask.PARAMETER_REPLACEMENTS, m_gson.toJson(allowedReplacements)); } + // inserts + List<Insert> insertions = definition.getInsertions(); + if (!insertions.isEmpty()) { + configParameters.put(ConfigureTask.PARAMETER_INSERTIONS, m_gson.toJson(insertions)); + } + return configParameters; } @@ -296,32 +307,4 @@ public class ConfigureTask extends ServerSideActionTask { return isValid; } - - /** - * Gets the value of the specified cluster property. - * - * @param cluster - * the cluster (not {@code null}). - * @param configType - * the configuration type (ie hdfs-site) (not {@code null}). - * @param propertyKey - * the key to retrieve (not {@code null}). - * @return the value or {@code null} if it does not exist. - */ - private String getDesiredConfigurationValue(Cluster cluster, - String configType, String propertyKey) { - - Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs(); - DesiredConfig desiredConfig = desiredConfigs.get(configType); - if (null == desiredConfig) { - return null; - } - - Config config = cluster.getConfig(configType, desiredConfig.getTag()); - if (null == config) { - return null; - } - - return config.getProperties().get(propertyKey); - } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml index d5dec43..73e3c38 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml @@ -256,5 +256,32 @@ </component> </service> + <service name="HIVE"> + <component name="HIVE_SERVER"> + <changes> + <definition xsi:type="configure" id="hdp_2_6_0_0_hive_append_heap_dump_options" summary="Appending optional Java heap dump parameters" > + <type>hive-env</type> + <insert key="content" value="export HADOOP_CLIENT_OPTS="$HADOOP_CLIENT_OPTS{{heap_dump_opts}}"" insert-type="append" newline-before="true" newline-after="true" /> + </definition> + <definition xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options"> + <type>tez-site</type> + <insert key="tez.task.launch.cmd-opts" value="{{heap_dump_opts}}" insert-type="append" newline-before="false" newline-after="false" /> + </definition> + </changes> + </component> + <component name="HIVE_SERVER_INTERACTIVE"> + <changes> + <definition xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_heap_dump_options" summary="Appending optional Java heap dump parameters" > + <type>hive-interactive-env</type> + <insert key="content" value="export HADOOP_CLIENT_OPTS="$HADOOP_CLIENT_OPTS{{heap_dump_opts}}"" insert-type="append" newline-before="true" newline-after="true" /> + </definition> + <definition xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_java_heap_dump_options"> + <type>hive-interactive-env</type> + <insert key="llap_java_opts" value="{{heap_dump_opts}}" insert-type="append" newline-before="false" newline-after="false" /> + </definition> + </changes> + </component> + </service> + </services> </upgrade-config-changes> http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml index 5ef959b..6c4da04 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml @@ -269,8 +269,7 @@ <!-- After processing this group, will change the effective Stack of the UpgradeContext object. --> <group xsi:type="update-stack" name="UPDATE_DESIRED_STACK_ID" title="Update Target Stack"> <execute-stage title="Update Target Stack"> - <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.UpdateDesiredStackAction"> - </task> + <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.UpdateDesiredStackAction"/> </execute-stage> </group> @@ -402,6 +401,22 @@ <execute-stage service="STORM" component="NIMBUS" title="Apply config changes for Nimbus"> <task xsi:type="configure" id="increase_storm_zookeeper_timeouts"/> </execute-stage> + + <execute-stage service="HIVE" component="HIVE_SERVER" title="Appending heap dump options for Hive"> + <task xsi:type="configure" id="hdp_2_6_0_0_hive_append_heap_dump_options"/> + </execute-stage> + + <execute-stage service="HIVE" component="HIVE_SERVER" title="Appending heap dump options for Tez"> + <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options"/> + </execute-stage> + + <execute-stage service="HIVE" component="HIVE_SERVER_INTERACTIVE" title="Appending heap dump options for HiveSever2 Interactive"> + <task xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_heap_dump_options"/> + </execute-stage> + + <execute-stage service="HIVE" component="HIVE_SERVER_INTERACTIVE" title="Appending Java heap dump options for HiveSever2 Interactive"> + <task xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_java_heap_dump_options"/> + </execute-stage> </group> <!-- http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml index b13a6f0..7f9e986 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml @@ -764,12 +764,26 @@ </component> <component name="HIVE_SERVER"> + <pre-upgrade> + <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options"/> + <task xsi:type="configure" id="hdp_2_6_0_0_hive_append_heap_dump_options"/> + </pre-upgrade> + + <pre-downgrade /> + <upgrade> <task xsi:type="restart-task" /> </upgrade> </component> <component name="HIVE_SERVER_INTERACTIVE"> + <pre-upgrade> + <task xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_java_heap_dump_options"/> + <task xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_heap_dump_options"/> + </pre-upgrade> + + <pre-downgrade /> + <upgrade> <task xsi:type="restart-task" /> </upgrade> http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/main/resources/upgrade-config.xsd ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/upgrade-config.xsd b/ambari-server/src/main/resources/upgrade-config.xsd index 805b472..cee7c85 100644 --- a/ambari-server/src/main/resources/upgrade-config.xsd +++ b/ambari-server/src/main/resources/upgrade-config.xsd @@ -43,6 +43,13 @@ <xs:enumeration value="yaml-array"/> </xs:restriction> </xs:simpleType> + + <xs:simpleType name="insertion-type"> + <xs:restriction base="xs:string"> + <xs:enumeration value="prepend"/> + <xs:enumeration value="append"/> + </xs:restriction> + </xs:simpleType> <xs:complexType name="configure"> <xs:sequence> @@ -103,6 +110,15 @@ <xs:attribute name="mask" use="optional" type="xs:boolean"/> </xs:complexType> </xs:element> + <xs:element name="insert" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="key" use="required" type="xs:string"/> + <xs:attribute name="value" use="required" type="xs:string"/> + <xs:attribute name="insert-type" use="required" type="insertion-type"/> + <xs:attribute name="newline-before" use="optional" type="xs:boolean"/> + <xs:attribute name="newline-after" use="optional" type="xs:boolean"/> + </xs:complexType> + </xs:element> </xs:choice> </xs:sequence> <xs:attribute name="id" use="required" type="xs:string"/> http://git-wip-us.apache.org/repos/asf/ambari/blob/410f2943/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java index 92fa084..cd8327b 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java @@ -38,7 +38,6 @@ 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.ClusterVersionDAO; import org.apache.ambari.server.orm.dao.HostDAO; import org.apache.ambari.server.orm.dao.HostVersionDAO; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; @@ -57,6 +56,8 @@ import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceFactory; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Insert; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.InsertType; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Replace; import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Transfer; import org.apache.ambari.server.state.stack.upgrade.ConfigureTask; @@ -100,8 +101,6 @@ public class ConfigureActionTest { @Inject private Clusters clusters; @Inject - private ClusterVersionDAO clusterVersionDAO; - @Inject private ConfigFactory cf; @Inject private ConfigureAction action; @@ -139,13 +138,13 @@ public class ConfigureActionTest { c.addDesiredConfig("user", Collections.singleton(config)); assertEquals(2, c.getConfigsByType("zoo.cfg").size()); - List<ConfigurationKeyValue> configurations = new ArrayList<ConfigurationKeyValue>(); + List<ConfigurationKeyValue> configurations = new ArrayList<>(); ConfigurationKeyValue keyValue = new ConfigurationKeyValue(); configurations.add(keyValue); keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -203,7 +202,7 @@ public class ConfigureActionTest { c.addDesiredConfig("user", Collections.singleton(config)); assertEquals(2, c.getConfigsByType("zoo.cfg").size()); - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -272,7 +271,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -402,14 +401,14 @@ public class ConfigureActionTest { c.addDesiredConfig("user", Collections.singleton(config)); assertEquals(2, c.getConfigsByType("zoo.cfg").size()); - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); commandParams.put(ConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg"); // copy with coerce - List<Transfer> transfers = new ArrayList<Transfer>(); + List<Transfer> transfers = new ArrayList<>(); Transfer transfer = new Transfer(); transfer.operation = TransferOperation.COPY; transfer.coerceTo = TransferCoercionType.YAML_ARRAY; @@ -466,14 +465,14 @@ public class ConfigureActionTest { c.addDesiredConfig("user", Collections.singleton(config)); assertEquals(2, c.getConfigsByType("zoo.cfg").size()); - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); commandParams.put(ConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg"); // Replacement task - List<Replace> replacements = new ArrayList<Replace>(); + List<Replace> replacements = new ArrayList<>(); Replace replace = new Replace(); replace.key = "key_to_replace"; replace.find = "New Cat"; @@ -538,14 +537,14 @@ public class ConfigureActionTest { c.addDesiredConfig("user", Collections.singleton(config)); assertEquals(2, c.getConfigsByType("zoo.cfg").size()); - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); commandParams.put(ConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg"); // Replacement task - List<Replace> replacements = new ArrayList<Replace>(); + List<Replace> replacements = new ArrayList<>(); Replace replace = new Replace(); replace.key = "missing"; replace.find = "foo"; @@ -596,7 +595,7 @@ public class ConfigureActionTest { assertEquals(2, c.getConfigsByType("zoo.cfg").size()); // create several configurations - List<ConfigurationKeyValue> configurations = new ArrayList<ConfigurationKeyValue>(); + List<ConfigurationKeyValue> configurations = new ArrayList<>(); ConfigurationKeyValue fooKey2 = new ConfigurationKeyValue(); configurations.add(fooKey2); fooKey2.key = "fooKey2"; @@ -608,7 +607,7 @@ public class ConfigureActionTest { fooKey3.value = "barValue3"; fooKey3.mask = true; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -662,7 +661,7 @@ public class ConfigureActionTest { assertEquals(2, c.getConfigsByType("zoo.cfg").size()); // create several configurations - List<ConfigurationKeyValue> configurations = new ArrayList<ConfigurationKeyValue>(); + List<ConfigurationKeyValue> configurations = new ArrayList<>(); ConfigurationKeyValue fooKey1 = new ConfigurationKeyValue(); configurations.add(fooKey1); fooKey1.key = "fooKey1"; @@ -698,7 +697,7 @@ public class ConfigureActionTest { fooKey5.ifKeyState= PropertyKeyState.ABSENT; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -756,7 +755,7 @@ public class ConfigureActionTest { assertEquals(2, c.getConfigsByType("zoo.cfg").size()); // create several configurations - List<ConfigurationKeyValue> configurations = new ArrayList<ConfigurationKeyValue>(); + List<ConfigurationKeyValue> configurations = new ArrayList<>(); ConfigurationKeyValue fooKey3 = new ConfigurationKeyValue(); configurations.add(fooKey3); fooKey3.key = "fooKey3"; @@ -782,7 +781,7 @@ public class ConfigureActionTest { fooKey5.ifKeyState= PropertyKeyState.PRESENT; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -839,7 +838,7 @@ public class ConfigureActionTest { assertEquals(2, c.getConfigsByType("zoo.cfg").size()); // create several configurations - List<Replace> replacements = new ArrayList<Replace>(); + List<Replace> replacements = new ArrayList<>(); Replace replace = new Replace(); replace.key = "replace.key.3"; replace.find = "a"; @@ -876,7 +875,7 @@ public class ConfigureActionTest { replace4.ifKeyState = PropertyKeyState.ABSENT; replacements.add(replace4); - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -931,7 +930,7 @@ public class ConfigureActionTest { assertEquals(2, c.getConfigsByType("zoo.cfg").size()); // create several configurations - List<Replace> replacements = new ArrayList<Replace>(); + List<Replace> replacements = new ArrayList<>(); Replace replace2 = new Replace(); replacements.add(replace2); @@ -963,7 +962,7 @@ public class ConfigureActionTest { replace4.ifKeyState = PropertyKeyState.PRESENT; replacements.add(replace4); - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1018,7 +1017,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1131,7 +1130,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1226,7 +1225,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1333,7 +1332,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1434,7 +1433,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1532,7 +1531,7 @@ public class ConfigureActionTest { keyValue.key = "initLimit"; keyValue.value = "11"; - Map<String, String> commandParams = new HashMap<String, String>(); + Map<String, String> commandParams = new HashMap<>(); commandParams.put("upgrade_direction", "upgrade"); commandParams.put("version", HDP_2_2_0_1); commandParams.put("clusterName", "c1"); @@ -1600,6 +1599,94 @@ public class ConfigureActionTest { } } + /** + * Tests using the {@code <insert/>} element in a configuration upgrade pack. + * + * @throws Exception + */ + @Test + public void testInsert() throws Exception { + makeUpgradeCluster(); + + Cluster c = clusters.getCluster("c1"); + assertEquals(1, c.getConfigsByType("zoo.cfg").size()); + + c.setDesiredStackVersion(HDP_220_STACK); + Config config = cf.createNew(c, "zoo.cfg", "version2", new HashMap<String, String>() { + { + put("key_to_append", "append"); + put("key_to_prepend", "prepend"); + } + }, new HashMap<String, Map<String, String>>()); + + c.addDesiredConfig("user", Collections.singleton(config)); + assertEquals(2, c.getConfigsByType("zoo.cfg").size()); + + Map<String, String> commandParams = new HashMap<>(); + commandParams.put("upgrade_direction", "upgrade"); + commandParams.put("version", HDP_2_2_0_1); + commandParams.put("clusterName", "c1"); + commandParams.put(ConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg"); + + // define the changes + final String prependValue = "This should be on a newline"; + final String appendValue = " this will be after..."; + + // insert tasks + List<Insert> insertions = new ArrayList<>(); + + Insert prepend = new Insert(); + prepend.insertType = InsertType.PREPEND; + prepend.key = "key_to_prepend"; + prepend.value = prependValue; + prepend.newlineBefore = false; + prepend.newlineAfter = true; + + Insert append = new Insert(); + append.insertType = InsertType.APPEND; + append.key = "key_to_append"; + append.value = appendValue; + append.newlineBefore = false; + append.newlineAfter = false; + + // add them to the list + insertions.add(prepend); + insertions.add(append); + + // just for fun, add them again - this will test their idempotence + insertions.add(prepend); + insertions.add(append); + + commandParams.put(ConfigureTask.PARAMETER_INSERTIONS, new Gson().toJson(insertions)); + + ExecutionCommand executionCommand = new ExecutionCommand(); + executionCommand.setCommandParams(commandParams); + executionCommand.setClusterName("c1"); + executionCommand.setRoleParams(new HashMap<String, String>()); + executionCommand.getRoleParams().put(ServerAction.ACTION_USER_NAME, "username"); + + 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("version2".equals(config.getTag())); + + // build the expected values + String expectedPrepend = prependValue + System.lineSeparator() + "prepend"; + String expectedAppend = "append" + appendValue; + + assertEquals(expectedPrepend, config.getProperties().get("key_to_prepend")); + assertEquals(expectedAppend, config.getProperties().get("key_to_append")); + } + private void makeUpgradeCluster() throws Exception { String clusterName = "c1"; String hostName = "h1"; @@ -1632,7 +1719,7 @@ public class ConfigureActionTest { Host host = clusters.getHost(hostName); - Map<String, String> hostAttributes = new HashMap<String, String>(); + Map<String, String> hostAttributes = new HashMap<>(); hostAttributes.put("os_family", "redhat"); hostAttributes.put("os_release_version", "6"); host.setHostAttributes(hostAttributes);