You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ha...@apache.org on 2018/05/07 15:48:16 UTC

[ambari] branch trunk updated: AMBARI-23769 Insert operation in upgrade pack extension (dgrinenko)

This is an automated email from the ASF dual-hosted git repository.

hapylestat 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 3593017  AMBARI-23769 Insert operation in upgrade pack extension (dgrinenko)
3593017 is described below

commit 3593017e1c34411bbf3971afa047012dd51ddaa3
Author: Dmitry Grinenko <ha...@gmail.com>
AuthorDate: Fri May 4 14:44:42 2018 +0300

    AMBARI-23769 Insert operation in upgrade pack extension (dgrinenko)
---
 .../serveraction/upgrades/ConfigureAction.java     |  98 +++++------
 .../upgrade/ConfigUpgradeChangeDefinition.java     |  54 +++++--
 .../server/orm/InMemoryDefaultTestModule.java      |   2 +-
 .../serveraction/upgrades/ConfigureActionTest.java | 180 +++++++++++++++++++++
 .../ambari/server/state/UpgradeHelperTest.java     |   4 +-
 5 files changed, 279 insertions(+), 59 deletions(-)

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 d3cc290..202fc91 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
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
@@ -48,7 +49,9 @@ 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.UpgradeContext;
+import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConditionalField;
 import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue;
+import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.IfValueMatchType;
 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;
@@ -89,6 +92,7 @@ import com.google.inject.Provider;
 public class ConfigureAction extends AbstractUpgradeServerAction {
 
   private static final Logger LOG = LoggerFactory.getLogger(ConfigureAction.class);
+  private static final String ALL_SYMBOL = "*";
 
   /**
    * Used to update the configuration properties.
@@ -218,8 +222,7 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     List<Transfer> transfers = Collections.emptyList();
     String transferJson = commandParameters.get(ConfigureTask.PARAMETER_TRANSFERS);
     if (null != transferJson) {
-      transfers = m_gson.fromJson(
-        transferJson, new TypeToken<List<Transfer>>(){}.getType());
+      transfers = m_gson.fromJson(transferJson, new TypeToken<List<Transfer>>(){}.getType());
       transfers = getAllowedTransfers(cluster, configType, transfers);
     }
 
@@ -227,8 +230,7 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     List<Replace> replacements = Collections.emptyList();
     String replaceJson = commandParameters.get(ConfigureTask.PARAMETER_REPLACEMENTS);
     if (null != replaceJson) {
-      replacements = m_gson.fromJson(
-          replaceJson, new TypeToken<List<Replace>>(){}.getType());
+      replacements = m_gson.fromJson(replaceJson, new TypeToken<List<Replace>>(){}.getType());
       replacements = getAllowedReplacements(cluster, configType, replacements);
     }
 
@@ -236,8 +238,8 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     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());
+      insertions = m_gson.fromJson(insertJson, new TypeToken<List<Insert>>(){}.getType());
+      insertions = getAllowedInsertions(cluster, configType, insertions);
     }
 
     // if there is nothing to do, then skip the task
@@ -366,7 +368,7 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
 
           break;
         case DELETE:
-          if ("*".equals(transfer.deleteKey)) {
+          if (ALL_SYMBOL.equals(transfer.deleteKey)) {
             newValues.clear();
 
             // append standard output
@@ -666,8 +668,7 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     List<Replace> allowedReplacements= new ArrayList<>();
 
     for(Replace replacement: replacements){
-      if(isOperationAllowed(cluster, configType, replacement.key,
-          replacement.ifKey, replacement.ifType, replacement.ifValue, replacement.ifKeyState)) {
+      if(isOperationAllowed(cluster, configType, replacement.key, replacement)) {
         allowedReplacements.add(replacement);
       }
     }
@@ -679,8 +680,7 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     List<ConfigurationKeyValue> allowedSets = new ArrayList<>();
 
     for(ConfigurationKeyValue configurationKeyValue: sets){
-      if(isOperationAllowed(cluster, configType, configurationKeyValue.key,
-          configurationKeyValue.ifKey, configurationKeyValue.ifType, configurationKeyValue.ifValue, configurationKeyValue.ifKeyState)) {
+      if(isOperationAllowed(cluster, configType, configurationKeyValue.key, configurationKeyValue)) {
         allowedSets.add(configurationKeyValue);
       }
     }
@@ -691,15 +691,14 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
   private List<Transfer> getAllowedTransfers(Cluster cluster, String configType, List<Transfer> transfers){
     List<Transfer> allowedTransfers = new ArrayList<>();
     for (Transfer transfer : transfers) {
-      String key = "";
+      String key;
       if(transfer.operation == TransferOperation.DELETE) {
         key = transfer.deleteKey;
       } else {
         key = transfer.fromKey;
       }
 
-      if(isOperationAllowed(cluster, configType, key,
-          transfer.ifKey, transfer.ifType, transfer.ifValue, transfer.ifKeyState)) {
+      if(isOperationAllowed(cluster, configType, key, transfer)) {
         allowedTransfers.add(transfer);
       }
     }
@@ -707,6 +706,14 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
     return allowedTransfers;
   }
 
+
+  private List<Insert> getAllowedInsertions(Cluster cluster, String configType, List<Insert> insertions){
+    return insertions.stream()
+      .filter(insertion -> isOperationAllowed(cluster, configType, insertion.key, insertion))
+      .collect(Collectors.toList());
+  }
+
+
   /**
    * Gets whether the {@code set} directive is valid based on the optional
    * attributes specified.
@@ -717,66 +724,63 @@ public class ConfigureAction extends AbstractUpgradeServerAction {
    *          the configuration type for the change (not {@code null}).
    * @param targetPropertyKey
    *          the property to set (not {@code null}).
-   * @param ifKey
-   *          the property name to check in order to satisfy a condition, or
-   *          {@code null} if there is no condition.
-   * @param ifType
-   *          the property type to check in order to satisfy a condition, or
-   *          {@code null} if there is no condition.
-   * @param ifValue
-   *          the property value to compare for equality in order to satisfy a
-   *          condition, or {@code null} if there is no condition.
-   * @param ifKeyState
-   *          the state of the if-property. If the property is
-   *          {@link PropertyKeyState#ABSENT}, then execute the set directory
-   *          only if the if-key is absent.
+   * @param operationItem
+   *           operation field compatible with {@link ConditionalField}
    * @return {@code true} if the set operation should be executed by the
    *         upgrade, {@code false} otherwise.
    */
-  private boolean isOperationAllowed(Cluster cluster, String configType, String targetPropertyKey,
-      String ifKey, String ifType, String ifValue, PropertyKeyState ifKeyState){
+  private boolean isOperationAllowed(Cluster cluster, String configType, String targetPropertyKey, ConditionalField operationItem)
+  {
     boolean isAllowed = true;
 
-    boolean ifKeyIsNotBlank = StringUtils.isNotBlank(ifKey);
-    boolean ifTypeIsNotBlank = StringUtils.isNotBlank(ifType);
-    boolean ifValueIsBlank = StringUtils.isBlank(ifValue);
+    boolean ifKeyIsNotBlank = StringUtils.isNotBlank(operationItem.ifKey);
+    boolean ifTypeIsNotBlank = StringUtils.isNotBlank(operationItem.ifType);
+    boolean ifValueIsBlank = StringUtils.isBlank(operationItem.ifValue);
 
     // if-key/if-type and no value - set only if absent
-    if (ifKeyIsNotBlank && ifTypeIsNotBlank && ifValueIsBlank && ifKeyState == PropertyKeyState.ABSENT) {
-      boolean keyPresent = getDesiredConfigurationKeyPresence(cluster, ifType, ifKey);
+    if (ifKeyIsNotBlank && ifTypeIsNotBlank && ifValueIsBlank && operationItem.ifKeyState == PropertyKeyState.ABSENT) {
+      boolean keyPresent = getDesiredConfigurationKeyPresence(cluster, operationItem.ifType, operationItem.ifKey);
       if (keyPresent) {
         LOG.info("Skipping property operation for {}/{} as the key {} for {} is present",
-          configType, targetPropertyKey, ifKey, ifType);
+          configType, targetPropertyKey, operationItem.ifKey, operationItem.ifType);
         isAllowed = false;
       }
       // if-key/if-type and no value - set only is present
-    } else if (ifKeyIsNotBlank && ifTypeIsNotBlank && ifValueIsBlank && ifKeyState == PropertyKeyState.PRESENT) {
-      boolean keyPresent = getDesiredConfigurationKeyPresence(cluster, ifType, ifKey);
+    } else if (ifKeyIsNotBlank && ifTypeIsNotBlank && ifValueIsBlank
+      && operationItem.ifKeyState == PropertyKeyState.PRESENT) {
+
+      boolean keyPresent = getDesiredConfigurationKeyPresence(cluster, operationItem.ifType, operationItem.ifKey);
       if (!keyPresent) {
         LOG.info("Skipping property operation for {}/{} as the key {} for {} is not present",
-          configType, targetPropertyKey, ifKey, ifType);
+          configType, targetPropertyKey, operationItem.ifKey, operationItem.ifType);
         isAllowed = false;
       }
       // if-key/if-type and a value to check - set only if values match
     } else if (ifKeyIsNotBlank && ifTypeIsNotBlank && !ifValueIsBlank) {
-      String ifConfigType = ifType;
-      String checkValue = getDesiredConfigurationValue(cluster, ifConfigType, ifKey);
+      String checkValue = getDesiredConfigurationValue(cluster, operationItem.ifType, operationItem.ifKey);
 
       // the check value is blank and there is an if-key-state of ABSENT - in
       // this case, it means set the value if it matches or if it's absent
-      if (ifKeyState == PropertyKeyState.ABSENT) {
-        boolean keyPresent = getDesiredConfigurationKeyPresence(cluster, ifType, ifKey);
+      if (operationItem.ifKeyState == PropertyKeyState.ABSENT) {
+        boolean keyPresent = getDesiredConfigurationKeyPresence(cluster, operationItem.ifType, operationItem.ifKey);
         if (!keyPresent) {
           return true;
         }
       }
 
       // the if-key was found, so we need to do a comparison
-      if (!StringUtils.equalsIgnoreCase(ifValue, checkValue)) {
-        // skip adding
-        LOG.info("Skipping property operation for {}/{} as the value {} for {}/{} is not equal to {}",
-                 configType, targetPropertyKey, checkValue, ifConfigType, ifKey, ifValue);
-        isAllowed = false;
+      if (operationItem.ifValueMatchType == IfValueMatchType.PARTIAL) {
+        if (!StringUtils.containsIgnoreCase(checkValue, operationItem.ifValue) ^ operationItem.ifValueNotMatched) {
+          LOG.info("Skipping property operation for {}/{} as the value {} for {}/{} is not found in {}",
+            configType, targetPropertyKey, operationItem.ifValue, operationItem.ifType, operationItem.ifKey, checkValue);
+          isAllowed = false;
+        }
+      } else {
+        if (!StringUtils.equalsIgnoreCase(operationItem.ifValue, checkValue) ^ operationItem.ifValueNotMatched) {
+          LOG.info("Skipping property operation for {}/{} as the value {} for {}/{} is not equal to {}",
+            configType, targetPropertyKey, checkValue, operationItem.ifType, operationItem.ifKey, operationItem.ifValue);
+          isAllowed = false;
+        }
       }
     }
 
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 ff9a123..92c74c2 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
@@ -287,15 +287,8 @@ public class ConfigUpgradeChangeDefinition {
     return inserts;
   }
 
-  /**
-   * Used for configuration updates that should mask their values from being
-   * printed in plain text.
-   */
   @XmlAccessorType(XmlAccessType.FIELD)
-  public static class Masked {
-    @XmlAttribute(name = "mask")
-    public boolean mask = false;
-
+  public static class ConditionalField{
     /**
      * The key to read for the if condition.
      */
@@ -315,12 +308,37 @@ public class ConfigUpgradeChangeDefinition {
     public String ifValue;
 
     /**
+     * Reverse search value result to opposite by allowing
+     * operation to be executed when value not found
+     */
+    @XmlAttribute(name = "if-value-not-matched")
+    public boolean ifValueNotMatched = false;
+
+    /**
+     * the way how to search the value:
+     * {@code IfValueMatchType.EXACT} - full comparison
+     * {@code IfValueMatchType.PARTIAL} - search for substring in string
+     */
+    @XmlAttribute(name = "if-value-match-type")
+    public IfValueMatchType ifValueMatchType = IfValueMatchType.EXACT;
+
+    /**
      * The property key state for the if condition
      */
     @XmlAttribute(name = "if-key-state")
     public PropertyKeyState ifKeyState;
   }
 
+  /**
+   * Used for configuration updates that should mask their values from being
+   * printed in plain text.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class Masked extends ConditionalField{
+    @XmlAttribute(name = "mask")
+    public boolean mask = false;
+  }
+
 
   /**
    * A key/value pair to set in the type specified by {@link ConfigUpgradeChangeDefinition#configType}
@@ -532,7 +550,7 @@ public class ConfigUpgradeChangeDefinition {
    */
   @XmlAccessorType(XmlAccessType.FIELD)
   @XmlType(name = "insert")
-  public static class Insert {
+  public static class Insert extends Masked{
     /**
      * The key name
      */
@@ -594,4 +612,22 @@ public class ConfigUpgradeChangeDefinition {
     APPEND
   }
 
+  /**
+   * The {@link IfValueMatchType} defines value search behaviour
+   */
+  @XmlEnum
+  public enum IfValueMatchType {
+    /**
+     * Exact value match
+     */
+    @XmlEnumValue("exact")
+    EXACT,
+
+    /**
+     * partial value match
+     */
+    @XmlEnumValue("partial")
+    PARTIAL
+  }
+
 }
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/InMemoryDefaultTestModule.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/InMemoryDefaultTestModule.java
index ebc2596..bb03327 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/InMemoryDefaultTestModule.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/InMemoryDefaultTestModule.java
@@ -94,7 +94,7 @@ public class InMemoryDefaultTestModule extends AbstractModule {
     String resourcesDir = "src/test/resources/";
     if (System.getProperty("os.name").contains("Windows")) {
       stacks = ClassLoader.getSystemClassLoader().getResource("stacks").getPath();
-      version = new File(new File(ClassLoader.getSystemClassLoader().getResource("").getPath()).getParent(), "version").getPath();
+      version = new File(new File(ClassLoader.getSystemClassLoader().getResource("").getPath()), "version").getPath();
       sharedResourcesDir = ClassLoader.getSystemClassLoader().getResource("").getPath();
     }
 
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 d74cb3f..e61da8f 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
@@ -64,6 +64,7 @@ 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.ConfigUpgradeChangeDefinition.IfValueMatchType;
 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;
@@ -1696,6 +1697,185 @@ public class ConfigureActionTest {
   }
 
   /**
+   * Tests using the {@code <insert/>} element in a configuration upgrade pack.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testInsertWithCondition() throws Exception {
+    Cluster c = clusters.getCluster("c1");
+    assertEquals(1, c.getConfigsByType("zoo.cfg").size());
+
+    final String lineSample = "This is before";
+    Map<String, String> properties = new HashMap<String, String>() {
+      {
+        put("item_not_inserted", lineSample);
+        put("item_inserted", lineSample);
+        put("item_partial_inserted", lineSample);
+        put("item_partial_not_inserted", lineSample);
+        put("item_value_not_inserted", lineSample);
+        put("item_partial_value_not_inserted", lineSample);
+        put("item_value_not_not_inserted", lineSample);
+        put("item_partial_value_not_not_inserted", lineSample);
+      }
+    };
+
+    Config config = createConfig(c, repoVersion2110, "zoo.cfg", "version2", properties);
+
+    c.addDesiredConfig("user", Collections.singleton(config));
+    assertEquals(2, c.getConfigsByType("zoo.cfg").size());
+
+    createUpgrade(c, repoVersion2111);
+
+    Map<String, String> commandParams = new HashMap<>();
+    commandParams.put("clusterName", "c1");
+    commandParams.put(ConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg");
+
+
+    final String appendValue = " this will be after...";
+
+    // insert tasks
+    List<Insert> insertions = new ArrayList<>();
+
+    Insert in1 = new Insert();
+    Insert in2 = new Insert();
+    Insert in3 = new Insert();
+    Insert in4 = new Insert();
+    Insert in5 = new Insert();
+    Insert in6 = new Insert();
+    Insert in7 = new Insert();
+    Insert in8 = new Insert();
+
+    //expect: no changes
+    in1.insertType = InsertType.APPEND;
+    in1.key = "item_not_inserted";
+    in1.value = appendValue;
+    in1.newlineBefore = false;
+    in1.newlineAfter = false;
+    in1.ifType = "zoo.cfg";
+    in1.ifKey = "item_not_inserted";
+    in1.ifValue = "multiline";
+    in1.ifValueMatchType = IfValueMatchType.EXACT;
+
+    //expect: value appended to the property
+    in2.insertType = InsertType.APPEND;
+    in2.key = "item_inserted";
+    in2.value = appendValue;
+    in2.newlineBefore = false;
+    in2.newlineAfter = false;
+    in2.ifType = "zoo.cfg";
+    in2.ifKey = "item_inserted";
+    in2.ifValue = lineSample;
+    in2.ifValueMatchType = IfValueMatchType.EXACT;
+
+    //expect: value appended to the property
+    in3.insertType = InsertType.APPEND;
+    in3.key = "item_partial_inserted";
+    in3.value = appendValue;
+    in3.newlineBefore = false;
+    in3.newlineAfter = false;
+    in3.ifType = "zoo.cfg";
+    in3.ifKey = "item_partial_inserted";
+    in3.ifValue = "before";
+    in3.ifValueMatchType = IfValueMatchType.PARTIAL;
+
+    //expect: no changes
+    in4.insertType = InsertType.APPEND;
+    in4.key = "item_partial_not_inserted";
+    in4.value = appendValue;
+    in4.newlineBefore = false;
+    in4.newlineAfter = false;
+    in4.ifType = "zoo.cfg";
+    in4.ifKey = "item_partial_not_inserted";
+    in4.ifValue = "wrong word";
+    in4.ifValueMatchType = IfValueMatchType.PARTIAL;
+
+    //expect: value appended to the property
+    in5.insertType = InsertType.APPEND;
+    in5.key = "item_value_not_inserted";
+    in5.value = appendValue;
+    in5.newlineBefore = false;
+    in5.newlineAfter = false;
+    in5.ifType = "zoo.cfg";
+    in5.ifKey = "item_value_not_inserted";
+    in5.ifValue = "wrong word";
+    in5.ifValueMatchType = IfValueMatchType.EXACT;
+    in5.ifValueNotMatched = true;
+
+    //expect: value appended to the property
+    in6.insertType = InsertType.APPEND;
+    in6.key = "item_partial_value_not_inserted";
+    in6.value = appendValue;
+    in6.newlineBefore = false;
+    in6.newlineAfter = false;
+    in6.ifType = "zoo.cfg";
+    in6.ifKey = "item_partial_value_not_inserted";
+    in6.ifValue = "wrong word";
+    in6.ifValueMatchType = IfValueMatchType.PARTIAL;
+    in6.ifValueNotMatched = true;
+
+    //expect: no changes
+    in7.insertType = InsertType.APPEND;
+    in7.key = "item_value_not_not_inserted";
+    in7.value = appendValue;
+    in7.newlineBefore = false;
+    in7.newlineAfter = false;
+    in7.ifType = "zoo.cfg";
+    in7.ifKey = "item_value_not_not_inserted";
+    in7.ifValue = lineSample;
+    in7.ifValueMatchType = IfValueMatchType.EXACT;
+    in7.ifValueNotMatched = true;
+
+    //expect: no changes
+    in8.insertType = InsertType.APPEND;
+    in8.key = "item_partial_value_not_not_inserted";
+    in8.value = appendValue;
+    in8.newlineBefore = false;
+    in8.newlineAfter = false;
+    in8.ifType = "zoo.cfg";
+    in8.ifKey = "item_partial_value_not_not_inserted";
+    in8.ifValue = "before";
+    in8.ifValueMatchType = IfValueMatchType.PARTIAL;
+    in8.ifValueNotMatched = true;
+
+    insertions.add(in1);
+    insertions.add(in2);
+    insertions.add(in3);
+    insertions.add(in4);
+    insertions.add(in5);
+    insertions.add(in6);
+    insertions.add(in7);
+    insertions.add(in8);
+
+    commandParams.put(ConfigureTask.PARAMETER_INSERTIONS, new Gson().toJson(insertions));
+
+    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);
+
+    config = c.getDesiredConfigByType("zoo.cfg");
+    assertNotNull(config);
+
+    // build the expected values
+    String expectedAppend = lineSample + appendValue;
+
+    assertEquals(expectedAppend, config.getProperties().get("item_inserted"));
+    assertEquals(expectedAppend, config.getProperties().get("item_partial_inserted"));
+    assertEquals(expectedAppend, config.getProperties().get("item_value_not_inserted"));
+    assertEquals(expectedAppend, config.getProperties().get("item_partial_value_not_inserted"));
+
+    assertTrue(lineSample.equalsIgnoreCase(config.getProperties().get("item_not_inserted")));
+    assertTrue(lineSample.equalsIgnoreCase(config.getProperties().get("item_partial_not_inserted")));
+    assertTrue(lineSample.equalsIgnoreCase(config.getProperties().get("item_value_not_not_inserted")));
+    assertTrue(lineSample.equalsIgnoreCase(config.getProperties().get("item_partial_value_not_not_inserted")));
+  }
+
+  /**
    * Creates a cluster using {@link #repoVersion2110} with ZooKeeper installed.
    *
    * @throws Exception
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
index 147bdd0..4f8e950 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
@@ -1092,9 +1092,9 @@ public class UpgradeHelperTest extends EasyMockSupport {
         configurationJson,
         new TypeToken<List<ConfigUpgradeChangeDefinition.Replace>>() {}.getType());
 
-    assertEquals("1-foo-2\n", replacements.get(0).find);
+    assertEquals("1-foo-2" + System.lineSeparator(), replacements.get(0).find);
     assertEquals("REPLACED", replacements.get(0).replaceWith);
-    assertEquals("3-foo-4\n", replacements.get(1).find);
+    assertEquals("3-foo-4" + System.lineSeparator(), replacements.get(1).find);
     assertEquals("REPLACED", replacements.get(1).replaceWith);
     assertEquals(2, replacements.size());
   }

-- 
To stop receiving notification emails like this one, please contact
hapylestat@apache.org.