http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptor.java
new file mode 100644
index 0000000..59e6104
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptor.java
@@ -0,0 +1,445 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * KerberosKeytabDescriptor is an implementation of an 
AbstractKerberosDescriptor that
+ * encapsulates data related to a Kerberos keytab file.  This class is 
typically associated with a
+ * KerberosPrincipalDescriptor via a KerberosIdentityDescriptor.
+ * <p/>
+ * A KerberosKeytabDescriptor has the following properties:
+ * <ul>
+ * <li>file</li>
+ * <li>owner {name, access}</li>
+ * <li>group {name, access}</li>
+ * <li>configuration</li>
+ * </ul>
+ * <p/>
+ * The following JSON Schema will yield a valid KerberosPrincipalDescriptor
+ * <pre>
+ *   {
+ *      "$schema": "http://json-schema.org/draft-04/schema#";,
+ *      "title": "KerberosKeytabDescriptor",
+ *      "description": "Describes a Kerberos keytab file and associated 
details",
+ *      "type": "object",
+ *      "properties": {
+ *        "file": {
+ *          "description": "The absolute path for the keytab file",
+ *          "type": "string"
+ *        },
+ *        "owner": {
+ *          "description": "Details about the file's user ownership",
+ *          "type": "object",
+ *          "properties": {
+ *            "name": {
+ *              "description": "The local username that should be set as the 
owner of this file",
+ *              "type": "string"
+ *            },
+ *            "access": {
+ *              "description": "The relevant access permissions that should be 
set for the owner of
+ *                              this file. Expected values are 'rw', 'r', ''"
+ *              "type": "string"
+ *            }
+ *          }
+ *        }
+ *        "group": {
+ *          "description": "Details about the file's group ownership",
+ *          "type": "object",
+ *          "properties": {
+ *            "name": {
+ *              "description": "The local group name that should be set as the 
group owner of this file",
+ *              "type": "string"
+ *            },
+ *            "access": {
+ *              "description": "The relevant access permissions that should be 
set for the group
+ *                              owner of this file. Expected values are 'rw', 
'r', ''"
+ *              "type": "string"
+ *            }
+ *          }
+ *        }
+ *        "configuration": {
+ *          "description": "The configuration type and property name 
indicating the property to be
+ *                          updated with the generated absolute path to the 
keytab file
+ *                          - format: config-type/property.name",
+ *          "type": "string"
+ *        }
+ *      }
+ *   }
+ * </pre>
+ * <p/>
+ * In this implementation,
+ * {@link 
org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptor#name} will 
hold the
+ * KerberosKeytabDescriptor#file value
+ */
+public class KerberosKeytabDescriptor extends AbstractKerberosDescriptor {
+
+  /**
+   * A String declaring the local username that should be set as the owner of 
the keytab file
+   */
+  private String ownerName = null;
+
+  /**
+   * A String declaring the access permissions that should be set on the 
keytab file related to the
+   * owner.
+   * <p/>
+   * Expected values are:
+   * <ul>
+   * <li>"rw" - read/write</li>
+   * <li>"r" - read-only</li>
+   * <li>"" - no access</li>
+   * </ul>
+   */
+  private String ownerAccess = null;
+
+  /**
+   * A String declaring the local groip name that should be set as the group 
owner of the keytab file
+   */
+  private String groupName = null;
+
+  /**
+   * A String declaring the access permissions that should be set on the 
keytab file related to the
+   * group.
+   * <p/>
+   * Expected values are:
+   * <ul>
+   * <li>"rw" - read/write</li>
+   * <li>"r" - read-only</li>
+   * <li>"" - no access</li>
+   * </ul>
+   */
+  private String groupAccess = null;
+
+  /**
+   * A string declaring configuration type and property name indicating the 
property to be updated
+   * with the absolute path to the keytab file
+   * <p/>
+   * This String is expected to be in the following format: 
configuration-type/property.name, where
+   * <ul>
+   * <li>configuration-type is the configuration file type where the property 
exists</li>
+   * <li>property.value is the name of the relevant property within the 
configuration</li>
+   * </ul>
+   * <p/>
+   * Example: hdfs-site/dfs.namenode.keytab.file
+   */
+  private String configuration = null;
+
+
+  /**
+   * Creates a new KerberosKeytabDescriptor
+   * <p/>
+   * See {@link 
org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor} for the JSON
+   * Schema that may be used to generate this map.
+   *
+   * @param data a Map of values use to populate the data for the new instance
+   * @see org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor
+   */
+  public KerberosKeytabDescriptor(Map<?, ?> data) {
+    // The name for this KerberosKeytabDescriptor is stored in the "file" 
entry in the map
+    // This is not automatically set by the super classes.
+    setName(getStringValue(data, "file"));
+
+    if (data != null) {
+      Object object;
+
+      object = data.get("owner");
+      if (object instanceof Map) {
+        Map<?, ?> map = (Map<?, ?>) object;
+        setOwnerName(getStringValue(map, "name"));
+        setOwnerAccess(getStringValue(map, "access"));
+      }
+
+      object = data.get("group");
+      if (object instanceof Map) {
+        Map<?, ?> map = (Map<?, ?>) object;
+        setGroupName(getStringValue(map, "name"));
+        setGroupAccess(getStringValue(map, "access"));
+      }
+
+      setConfiguration(getStringValue(data, "configuration"));
+    }
+  }
+
+  /**
+   * Gets the path to the keytab file
+   * <p/>
+   * The value may include variable placeholders to be replaced as needed
+   * <ul>
+   * <li>
+   * ${variable} placeholders are replaced on the server - see
+   * {@link 
org.apache.ambari.server.state.kerberos.KerberosDescriptor#replaceVariables(String,
 java.util.Map)}
+   * </li>
+   * </ul>
+   *
+   * @return a String declaring the keytab file's absolute path
+   * @see 
org.apache.ambari.server.state.kerberos.KerberosDescriptor#replaceVariables(String,
 java.util.Map)
+   */
+  public String getFile() {
+    return getName();
+  }
+
+  /**
+   * Sets the path to the keytab file
+   *
+   * @param file a String declaring this keytab's file path
+   * @see #getFile()
+   */
+  public void setFile(String file) {
+    setName(file);
+  }
+
+  /**
+   * Gets the local username to set as the owner of the keytab file
+   *
+   * @return a String declaring the name of the user to own the keytab file
+   */
+  public String getOwnerName() {
+    return ownerName;
+  }
+
+  /**
+   * Sets the local username to set as the owner of the keytab file
+   *
+   * @param name a String declaring the name of the user to own the keytab file
+   */
+  public void setOwnerName(String name) {
+    this.ownerName = name;
+  }
+
+  /**
+   * Gets the access permissions that should be set on the keytab file related 
to the file's owner
+   *
+   * @return a String declaring the access permissions that should be set on 
the keytab file related
+   * to the file's owner
+   * @see #ownerAccess
+   */
+  public String getOwnerAccess() {
+    return ownerAccess;
+  }
+
+  /**
+   * Sets the access permissions that should be set on the keytab file related 
to the file's owner
+   *
+   * @param access a String declaring the access permissions that should be 
set on the keytab file
+   *               related to the file's owner
+   * @see #ownerAccess
+   */
+  public void setOwnerAccess(String access) {
+    this.ownerAccess = access;
+  }
+
+  /**
+   * Gets the local group name to set as the group owner of the keytab file
+   *
+   * @return a String declaring the name of the group to own the keytab file
+   */
+  public String getGroupName() {
+    return groupName;
+  }
+
+  /**
+   * Sets the local group name to set as the group owner of the keytab file
+   *
+   * @param name a String declaring the name of the group to own the keytab 
file
+   */
+  public void setGroupName(String name) {
+    this.groupName = name;
+  }
+
+  /**
+   * Gets the access permissions that should be set on the keytab file related 
to the file's group
+   *
+   * @return a String declaring the access permissions that should be set on 
the keytab file related
+   * to the file's group
+   * @see #groupAccess
+   */
+  public String getGroupAccess() {
+    return groupAccess;
+  }
+
+  /**
+   * Sets the access permissions that should be set on the keytab file related 
to the file's group
+   *
+   * @param access a String declaring the access permissions that should be 
set on the keytab file
+   *               related to the file's group
+   * @see #groupAccess
+   */
+  public void setGroupAccess(String access) {
+    this.groupAccess = access;
+  }
+
+  /**
+   * Gets the configuration type and property name indicating the property to 
be updated with the
+   * keytab's file path
+   *
+   * @return a String declaring the configuration type and property name 
indicating the property to
+   * be updated with the keytab's file path
+   * #see #configuration
+   */
+  public String getConfiguration() {
+    return configuration;
+  }
+
+  /**
+   * Sets the configuration type and property name indicating the property to 
be updated with the
+   * keytab's file path
+   *
+   * @param configuration a String declaring the configuration type and 
property name indicating the
+   *                      property to be updated with the keytab's file path
+   * @see #configuration
+   */
+  public void setConfiguration(String configuration) {
+    this.configuration = configuration;
+  }
+
+  /**
+   * Updates this KerberosKeytabDescriptor with data from another 
KerberosKeytabDescriptor
+   * <p/>
+   * Properties will be updated if the relevant updated values are not null.
+   *
+   * @param updates the KerberosKeytabDescriptor containing the updated values
+   */
+  public void update(KerberosKeytabDescriptor updates) {
+    if (updates != null) {
+      String updatedValue;
+
+      updatedValue = updates.getFile();
+      if (updatedValue != null) {
+        setFile(updatedValue);
+      }
+
+      updatedValue = updates.getConfiguration();
+      if (updatedValue != null) {
+        setConfiguration(updatedValue);
+      }
+
+      updatedValue = updates.getOwnerName();
+      if (updatedValue != null) {
+        setOwnerName(updatedValue);
+      }
+
+      updatedValue = updates.getOwnerAccess();
+      if (updatedValue != null) {
+        setOwnerAccess(updatedValue);
+      }
+
+      updatedValue = updates.getGroupName();
+      if (updatedValue != null) {
+        setGroupName(updatedValue);
+      }
+
+      updatedValue = updates.getGroupAccess();
+      if (updatedValue != null) {
+        setGroupAccess(updatedValue);
+      }
+    }
+  }
+
+  /**
+   * Creates a Map of values that can be used to create a copy of this 
KerberosKeytabDescriptor
+   * or generate the JSON structure described in
+   * {@link org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor}
+   *
+   * @return a Map of values for this KerberosKeytabDescriptor
+   * @see org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor
+   */
+  @Override
+  public Map<String, Object> toMap() {
+    Map<String, Object> map = new HashMap<String, Object>();
+
+    map.put("file", getFile());
+
+    map.put("owner", new HashMap<String, Object>() {{
+      put("name", getOwnerName());
+      put("access", getOwnerAccess());
+    }});
+
+    map.put("group", new HashMap<String, Object>() {{
+      put("name", getGroupName());
+      put("access", getGroupAccess());
+    }});
+
+    map.put("configuration", getConfiguration());
+
+    return map;
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode() +
+        ((getConfiguration() == null)
+            ? 0
+            : getConfiguration().hashCode()) +
+        ((getOwnerName() == null)
+            ? 0
+            : getOwnerName().hashCode()) +
+        ((getOwnerAccess() == null)
+            ? 0
+            : getOwnerAccess().hashCode()) +
+        ((getGroupName() == null)
+            ? 0
+            : getGroupName().hashCode()) +
+        ((getGroupAccess() == null)
+            ? 0
+            : getGroupAccess().hashCode()) +
+        ((getConfiguration() == null)
+            ? 0
+            : getConfiguration().hashCode());
+  }
+
+  @Override
+  public boolean equals(Object object) {
+    if (object == null) {
+      return false;
+    } else if (object == this) {
+      return true;
+    } else if (object.getClass() == KerberosKeytabDescriptor.class) {
+      KerberosKeytabDescriptor descriptor = (KerberosKeytabDescriptor) object;
+      return super.equals(object) &&
+          (
+              (getConfiguration() == null)
+                  ? (descriptor.getConfiguration() == null)
+                  : getConfiguration().equals(descriptor.getConfiguration())
+          ) &&
+          (
+              (getOwnerName() == null)
+                  ? (descriptor.getOwnerName() == null)
+                  : getOwnerName().equals(descriptor.getOwnerName())
+          ) &&
+          (
+              (getOwnerAccess() == null)
+                  ? (descriptor.getOwnerAccess() == null)
+                  : getOwnerAccess().equals(descriptor.getOwnerAccess())
+          ) &&
+          (
+              (getGroupName() == null)
+                  ? (descriptor.getGroupName() == null)
+                  : getGroupName().equals(descriptor.getGroupName())
+          ) &&
+          (
+              (getGroupAccess() == null)
+                  ? (descriptor.getGroupAccess() == null)
+                  : getGroupAccess().equals(descriptor.getGroupAccess())
+          );
+    } else {
+      return false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptor.java
new file mode 100644
index 0000000..70bd396
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptor.java
@@ -0,0 +1,212 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * KerberosPrincipalDescriptor is an implementation of an 
AbstractKerberosDescriptor that
+ * encapsulates data related to a Kerberos principal.  This class is typically 
associated with the
+ * KerberosKeytabDescriptor via a KerberosIdentityDescriptor.
+ * <p/>
+ * A KerberosPrincipalDescriptor has the following properties:
+ * <ul>
+ * <li>value</li>
+ * <li>configuration</li>
+ * </ul>
+ * <p/>
+ * The following JSON Schema will yield a valid KerberosPrincipalDescriptor
+ * <pre>
+ *   {
+ *      "$schema": "http://json-schema.org/draft-04/schema#";,
+ *      "title": "KerberosIdentityDescriptor",
+ *      "description": "Describes a Kerberos principal and associated details",
+ *      "type": "object",
+ *      "properties": {
+ *        "value": {
+ *          "description": "The pattern to use to generate the principal",
+ *          "type": "string"
+ *        },
+ *        "configuration": {
+ *          "description": "The configuration type and property name 
indicating the property to be
+ *                          updated with the generated principal - format: 
config-type/property.name",
+ *          "type": "string"
+ *        }
+ *      }
+ *   }
+ * </pre>
+ * <p/>
+ * In this implementation,
+ * {@link 
org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptor#name} will 
hold the
+ * KerberosPrincipalDescriptor#value value
+ */
+public class KerberosPrincipalDescriptor extends AbstractKerberosDescriptor {
+
+  /**
+   * A string declaring configuration type and property name indicating the 
property to be updated
+   * with the generated principal
+   * <p/>
+   * This String is expected to be in the following format: 
configuration-type/property.name, where
+   * <ul>
+   * <li>configuration-type is the configuration file type where the property 
exists</li>
+   * <li>property.value is the name of the relevant property within the 
configuration</li>
+   * </ul>
+   * <p/>
+   * Example: hdfs-site/dfs.namenode.kerberos.principal
+   */
+  private String configuration;
+
+  /**
+   * Creates a new KerberosPrincipalDescriptor
+   * <p/>
+   * See {@link 
org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor} for the 
JSON
+   * Schema that may be used to generate this map.
+   *
+   * @param data a Map of values use to populate the data for the new instance
+   * @see org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor
+   */
+  public KerberosPrincipalDescriptor(Map<?, ?> data) {
+    // The name for this KerberosPrincipalDescriptor is stored in the "value" 
entry in the map
+    // This is not automatically set by the super classes.
+    setName(getStringValue(data, "value"));
+
+    setConfiguration(getStringValue(data, "configuration"));
+  }
+
+  /**
+   * Gets the value (or principal name pattern) for this 
KerberosPrincipalDescriptor
+   * <p/>
+   * The value may include variable placeholders to be replaced as needed
+   * <ul>
+   * <li>
+   * ${variable} placeholders are replaced on the server - see
+   * {@link 
org.apache.ambari.server.state.kerberos.KerberosDescriptor#replaceVariables(String,
 java.util.Map)}
+   * </li>
+   * <li>the _HOST placeholder is replaced on the hosts to dynamically 
populate the relevant hostname</li>
+   * </ul>
+   *
+   * @return a String declaring this principal's value
+   * @see 
org.apache.ambari.server.state.kerberos.KerberosDescriptor#replaceVariables(String,
 java.util.Map)
+   */
+  public String getValue() {
+    return getName();
+  }
+
+  /**
+   * Sets the value (or principal name pattern) for this 
KerberosPrincipalDescriptor
+   *
+   * @param value a String declaring this principal's value
+   * @see #getValue()
+   */
+  public void setValue(String value) {
+    setName(value);
+  }
+
+  /**
+   * Gets the configuration type and property name indicating the property to 
be updated with the
+   * generated principal
+   *
+   * @return a String declaring the configuration type and property name 
indicating the property to
+   * be updated with the generated principal
+   * #see #configuration
+   */
+  public String getConfiguration() {
+    return configuration;
+  }
+
+  /**
+   * Sets the configuration type and property name indicating the property to 
be updated with the
+   * generated principal
+   *
+   * @param configuration a String declaring the configuration type and 
property name indicating the
+   *                      property to be updated with the generated principal
+   * @see #configuration
+   */
+  public void setConfiguration(String configuration) {
+    this.configuration = configuration;
+  }
+
+  /**
+   * Updates this KerberosPrincipalDescriptor with data from another 
KerberosPrincipalDescriptor
+   * <p/>
+   * Properties will be updated if the relevant updated values are not null.
+   *
+   * @param updates the KerberosPrincipalDescriptor containing the updated 
values
+   */
+  public void update(KerberosPrincipalDescriptor updates) {
+    if (updates != null) {
+      String updatedValue;
+
+      updatedValue = updates.getValue();
+      if (updatedValue != null) {
+        setValue(updatedValue);
+      }
+
+      updatedValue = updates.getConfiguration();
+      if (updatedValue != null) {
+        setConfiguration(updatedValue);
+      }
+    }
+  }
+
+  /**
+   * Creates a Map of values that can be used to create a copy of this 
KerberosPrincipalDescriptor
+   * or generate the JSON structure described in
+   * {@link 
org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor}
+   *
+   * @return a Map of values for this KerberosPrincipalDescriptor
+   * @see org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor
+   */
+  @Override
+  public Map<String, Object> toMap() {
+    Map<String, Object> map = new HashMap<String, Object>();
+
+    map.put("value", getValue());
+    map.put("configuration", getConfiguration());
+
+    return map;
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode() +
+        ((getConfiguration() == null)
+            ? 0
+            : getConfiguration().hashCode());
+  }
+
+  @Override
+  public boolean equals(Object object) {
+    if (object == null) {
+      return false;
+    } else if (object == this) {
+      return true;
+    } else if (object.getClass() == KerberosPrincipalDescriptor.class) {
+      KerberosPrincipalDescriptor descriptor = (KerberosPrincipalDescriptor) 
object;
+      return super.equals(object) &&
+          (
+              (getConfiguration() == null)
+                  ? (descriptor.getConfiguration() == null)
+                  : getConfiguration().equals(descriptor.getConfiguration())
+          );
+    } else {
+      return false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
new file mode 100644
index 0000000..12b588c
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
@@ -0,0 +1,318 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents information required to configure Kerberos for a particular 
service.
+ * <p/>
+ * The data map is expected to have the following properties:
+ * <ul>
+ * <li>name</li>
+ * <li>components</li>
+ * <li>identities</li>
+ * <li>configurations</li>
+ * </ul>
+ * Example:
+ * <pre>
+ *  "name" => "SERVICE",
+ *  "identities" => Collection&lt;Map&lt;String, Object&gt;&gt;
+ *  "components" => Collection&lt;Map&lt;String, Object&gt;&gt;
+ *  "configurations" => Collection&lt;Map&lt;String, Object&gt;&gt;
+ * </pre>
+ */
+
+/**
+ * KerberosServiceDescriptor is an implementation of an 
AbstractKerberosDescriptorContainer that
+ * encapsulates an Ambari service and it components.
+ * <p/>
+ * A KerberosServiceDescriptor has the following properties:
+ * <ul>
+ * <li>name</li>
+ * <li>components</li>
+ * <li>identities ({@link 
org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptorContainer})</li>
+ * <li>configurations ({@link 
org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptorContainer})</li>
+ * </ul>
+ * <p/>
+ * The following (pseudo) JSON Schema will yield a valid 
KerberosServiceDescriptor
+ * <pre>
+ *   {
+ *      "$schema": "http://json-schema.org/draft-04/schema#";,
+ *      "title": "KerberosServiceDescriptor",
+ *      "description": "Describes an Ambari service",
+ *      "type": "object",
+ *      "properties": {
+ *        "name": {
+ *          "description": "An identifying name for this service descriptor.",
+ *          "type": "string"
+ *        },
+ *        "components": {
+ *          "description": "A list of Ambari component descriptors",
+ *          "type": "array",
+ *          "items": {
+ *            "title": "KerberosComponentDescriptor"
+ *            "type": "{@link 
org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor}"
+ *          }
+ *        },
+ *        "identities": {
+ *          "description": "A list of Kerberos identity descriptors",
+ *          "type": "array",
+ *          "items": {
+ *            "title": "KerberosIdentityDescriptor"
+ *            "type": "{@link 
org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor}"
+ *          }
+ *        },
+ *        "configurations": {
+ *          "description": "A list of relevant configuration blocks",
+ *          "type": "array",
+ *          "items": {
+ *            "title": "KerberosConfigurationDescriptor"
+ *            "type": "{@link 
org.apache.ambari.server.state.kerberos.KerberosConfigurationDescriptor}"
+ *          }
+ *        }
+ *      }
+ *   }
+ * </pre>
+ * <p/>
+ * In this implementation,
+ * {@link 
org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptor#name} will 
hold the
+ * KerberosServiceDescriptor#name value.
+ */
+public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContainer {
+
+  /**
+   * A Map of the components contained within this KerberosServiceDescriptor
+   */
+  private Map<String, KerberosComponentDescriptor> components;
+
+  /**
+   * Creates a new KerberosServiceDescriptor
+   *
+   * @param name a String declaring this service's name
+   * @param file a JSON-formatted file containing this service's descriptor 
data
+   * @throws FileNotFoundException if the descriptor file is not found
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public static KerberosServiceDescriptor fromFile(String name, File file) 
throws IOException {
+    return new KerberosServiceDescriptor(name, parseFile(file));
+  }
+
+  /**
+   * Creates a new KerberosServiceDescriptor
+   *
+   * @param name a String declaring this service's name
+   * @param json a JSON-formatted String containing this service's descriptor 
data
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public static KerberosServiceDescriptor fromJSON(String name, String json) {
+    return new KerberosServiceDescriptor(name, parseJSON(json));
+  }
+
+  /**
+   * Creates a new KerberosServiceDescriptor
+   * <p/>
+   * See {@link 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor} for the JSON
+   * Schema that may be used to generate this map.
+   *
+   * @param data a Map of values use to populate the data for the new instance
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor(Map<?, ?> data) {
+    // The name for this KerberosServiceDescriptor is stored in the "name" 
entry in the map
+    // This is not automatically set by the super classes.
+    this(getStringValue(data, "name"), data);
+  }
+
+  /**
+   * Creates a new KerberosServiceDescriptor
+   * <p/>
+   * See {@link 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor} for the JSON
+   * Schema that may be used to generate this map.
+   *
+   * @param name a String declaring this service's name
+   * @param data a Map of values use to populate the data for the new instance
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor(String name, Map<?, ?> data) {
+    super(data);
+
+    // This is not automatically set by the super classes.
+    setName(name);
+
+    if (data != null) {
+      Object list = 
data.get(KerberosDescriptorType.COMPONENT.getDescriptorPluralName());
+      if (list instanceof Collection) {
+        // Assume list is Collection<Map<String, Object>>
+        for (Object item : (Collection) list) {
+          if (item instanceof Map) {
+            putComponent(new KerberosComponentDescriptor((Map<?, ?>) item));
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Returns a Map of the KerberosComponentDescriptors related to this 
KerberosServiceDescriptor
+   *
+   * @return a Map of String to KerberosComponentDescriptor
+   */
+  public Map<String, KerberosComponentDescriptor> getComponents() {
+    return components;
+  }
+
+  /**
+   * Returns the KerberosComponentDescriptors with the specified name
+   *
+   * @param name the name of the component for which to retrieve a descriptor
+   * @return the KerberosComponentDescriptor for the requested component or 
null if not found
+   */
+  public KerberosComponentDescriptor getComponent(String name) {
+    return ((name == null) || (components == null)) ? null : 
components.get(name);
+  }
+
+  /**
+   * Adds or replaces a KerberosComponentDescriptor
+   * <p/>
+   * If a KerberosComponentDescriptor with the same name already exists in the 
components Map, it
+   * will be replaced; else a new entry will be made.
+   *
+   * @param component the KerberosComponentDescriptor to put
+   */
+  public void putComponent(KerberosComponentDescriptor component) {
+    if (component != null) {
+      String name = component.getName();
+
+      if (name == null) {
+        throw new IllegalArgumentException("The component name must not be 
null");
+      }
+
+      if (components == null) {
+        components = new HashMap<String, KerberosComponentDescriptor>();
+      }
+
+      components.put(name, component);
+      component.setParent(this);
+    }
+  }
+
+  /**
+   * Updates this KerberosServiceDescriptor with data from another 
KerberosServiceDescriptor
+   * <p/>
+   * Properties will be updated if the relevant updated values are not null.
+   *
+   * @param updates the KerberosServiceDescriptor containing the updated values
+   */
+  public void update(KerberosServiceDescriptor updates) {
+    if (updates != null) {
+      Map<String, KerberosComponentDescriptor> updatedComponents = 
updates.getComponents();
+      if (updatedComponents != null) {
+        for (Map.Entry<String, KerberosComponentDescriptor> entry : 
updatedComponents.entrySet()) {
+          KerberosComponentDescriptor existing = getComponent(entry.getKey());
+          if (existing == null) {
+            putComponent(entry.getValue());
+          } else {
+            existing.update(entry.getValue());
+          }
+        }
+      }
+    }
+
+    super.update(updates);
+  }
+
+  /**
+   * Gets the requested AbstractKerberosDescriptor implementation using a type 
name and a relevant
+   * descriptor name.
+   * <p/>
+   * This implementation handles component descriptors and relies on the
+   * AbstractKerberosDescriptorContainer implementation to handle other types.
+   *
+   * @param type a String indicating the type of the requested descriptor
+   * @param name a String indicating the name of the requested descriptor
+   * @return a AbstractKerberosDescriptor representing the requested 
descriptor or null if not found
+   */
+  @Override
+  protected AbstractKerberosDescriptor getDescriptor(KerberosDescriptorType 
type, String name) {
+    if (KerberosDescriptorType.COMPONENT == type) {
+      return getComponent(name);
+    } else {
+      return super.getDescriptor(type, name);
+    }
+  }
+
+  /**
+   * Creates a Map of values that can be used to create a copy of this 
KerberosServiceDescriptor
+   * or generate the JSON structure described in
+   * {@link org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor}
+   *
+   * @return a Map of values for this KerberosServiceDescriptor
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  @Override
+  public Map<String, Object> toMap() {
+    Map<String, Object> map = super.toMap();
+
+    if (components != null) {
+      List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
+      for (KerberosComponentDescriptor component : components.values()) {
+        list.add(component.toMap());
+      }
+      map.put(KerberosDescriptorType.COMPONENT.getDescriptorPluralName(), 
list);
+    }
+
+    return map;
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode() +
+        ((getComponents() == null)
+            ? 0
+            : getComponents().hashCode());
+  }
+
+  @Override
+  public boolean equals(Object object) {
+    if (object == null) {
+      return false;
+    } else if (object == this) {
+      return true;
+    } else if (object.getClass() == KerberosServiceDescriptor.class) {
+      KerberosServiceDescriptor descriptor = (KerberosServiceDescriptor) 
object;
+      return super.equals(object) &&
+          (
+              (getComponents() == null)
+                  ? (descriptor.getComponents() == null)
+                  : getComponents().equals(descriptor.getComponents())
+          );
+    } else {
+      return false;
+    }
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptorTest.java
new file mode 100644
index 0000000..e657f38
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptorTest.java
@@ -0,0 +1,206 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class KerberosComponentDescriptorTest {
+  public static final String JSON_VALUE =
+      " {" +
+          "  \"name\": \"COMPONENT_NAME\"," +
+          "  \"identities\": [" +
+          KerberosIdentityDescriptorTest.JSON_VALUE +
+          "]," +
+          "  \"configurations\": [" +
+          "    {" +
+          "      \"service-site\": {" +
+          "        \"service.component.property1\": \"value1\"," +
+          "        \"service.component.property2\": \"value2\"" +
+          "      }" +
+          "    }" +
+          "  ]" +
+          "}";
+
+  public static final Map<String, Object> MAP_VALUE =
+      new HashMap<String, Object>() {
+        {
+          put("name", "A_DIFFERENT_COMPONENT_NAME");
+          put(KerberosDescriptorType.IDENTITY.getDescriptorPluralName(), new 
ArrayList<Object>() {{
+            add(KerberosIdentityDescriptorTest.MAP_VALUE);
+            add(KerberosIdentityDescriptorTest.MAP_VALUE_ALT);
+            add(KerberosIdentityDescriptorTest.MAP_VALUE_REFERENCE);
+          }});
+          put(KerberosDescriptorType.CONFIGURATION.getDescriptorPluralName(), 
new ArrayList<Map<String, Object>>() {{
+            add(new HashMap<String, Object>() {
+              {
+                put("service-site", new HashMap<String, String>() {
+                  {
+                    put("service.component.property1", "red");
+                    put("service.component.property", "green");
+                  }
+                });
+              }
+            });
+          }});
+        }
+      };
+
+  public static void validateFromJSON(KerberosComponentDescriptor 
componentDescriptor) {
+    Assert.assertNotNull(componentDescriptor);
+    Assert.assertTrue(componentDescriptor.isContainer());
+
+    Assert.assertEquals("COMPONENT_NAME", componentDescriptor.getName());
+
+    List<KerberosIdentityDescriptor> identities = 
componentDescriptor.getIdentities();
+
+    Assert.assertNotNull(identities);
+    Assert.assertEquals(1, identities.size());
+
+    Map<String, KerberosConfigurationDescriptor> configurations = 
componentDescriptor.getConfigurations();
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(1, configurations.size());
+
+    KerberosConfigurationDescriptor configuration = 
configurations.get("service-site");
+
+    Assert.assertNotNull(configuration);
+
+    Map<String, String> properties = configuration.getProperties();
+
+    Assert.assertEquals("service-site", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("value1", 
properties.get("service.component.property1"));
+    Assert.assertEquals("value2", 
properties.get("service.component.property2"));
+  }
+
+  public static void validateFromMap(KerberosComponentDescriptor 
componentDescriptor) {
+    Assert.assertNotNull(componentDescriptor);
+    Assert.assertTrue(componentDescriptor.isContainer());
+
+    Assert.assertEquals("A_DIFFERENT_COMPONENT_NAME", 
componentDescriptor.getName());
+
+    List<KerberosIdentityDescriptor> identities = 
componentDescriptor.getIdentities();
+
+    Assert.assertNotNull(identities);
+    Assert.assertEquals(3, identities.size());
+
+    Map<String, KerberosConfigurationDescriptor> configurations = 
componentDescriptor.getConfigurations();
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(1, configurations.size());
+
+    KerberosConfigurationDescriptor configuration = 
configurations.get("service-site");
+
+    Assert.assertNotNull(configuration);
+
+    Map<String, String> properties = configuration.getProperties();
+
+    Assert.assertEquals("service-site", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("red", properties.get("service.component.property1"));
+    Assert.assertEquals("green", properties.get("service.component.property"));
+  }
+
+  public static void validateUpdatedData(KerberosComponentDescriptor 
componentDescriptor) {
+    Assert.assertNotNull(componentDescriptor);
+
+    Assert.assertEquals("A_DIFFERENT_COMPONENT_NAME", 
componentDescriptor.getName());
+
+    List<KerberosIdentityDescriptor> identities = 
componentDescriptor.getIdentities();
+
+    Assert.assertNotNull(identities);
+    Assert.assertEquals(3, identities.size());
+
+    Map<String, KerberosConfigurationDescriptor> configurations = 
componentDescriptor.getConfigurations();
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(1, configurations.size());
+
+    KerberosConfigurationDescriptor configuration = 
configurations.get("service-site");
+
+    Assert.assertNotNull(configuration);
+
+    Map<String, String> properties = configuration.getProperties();
+
+    Assert.assertEquals("service-site", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(3, properties.size());
+    Assert.assertEquals("red", properties.get("service.component.property1"));
+    Assert.assertEquals("value2", 
properties.get("service.component.property2"));
+    Assert.assertEquals("green", properties.get("service.component.property"));
+  }
+
+  private static KerberosComponentDescriptor createFromJSON() {
+    Map<Object, Object> map = new Gson()
+        .fromJson(JSON_VALUE, new TypeToken<Map<Object, Object>>() {
+        }.getType());
+    return new KerberosComponentDescriptor(map);
+  }
+
+  private static KerberosComponentDescriptor createFromMap() throws 
AmbariException {
+    return new KerberosComponentDescriptor(MAP_VALUE);
+  }
+
+  @Test
+  public void testJSONDeserialize() {
+    validateFromJSON(createFromJSON());
+  }
+
+  @Test
+  public void testMapDeserialize() throws AmbariException {
+    validateFromMap(createFromMap());
+  }
+
+  @Test
+  public void testEquals() throws AmbariException {
+    Assert.assertTrue(createFromJSON().equals(createFromJSON()));
+    Assert.assertFalse(createFromJSON().equals(createFromMap()));
+  }
+
+  @Test
+  public void testToMap() throws AmbariException {
+    KerberosComponentDescriptor descriptor = createFromMap();
+    Assert.assertNotNull(descriptor);
+    Assert.assertEquals(MAP_VALUE, descriptor.toMap());
+  }
+
+
+  @Test
+  public void testUpdate() throws AmbariException {
+    KerberosComponentDescriptor componentDescriptor = createFromJSON();
+    KerberosComponentDescriptor updatedComponentDescriptor = createFromMap();
+
+    Assert.assertNotNull(componentDescriptor);
+    Assert.assertNotNull(updatedComponentDescriptor);
+
+    componentDescriptor.update(updatedComponentDescriptor);
+
+    validateUpdatedData(componentDescriptor);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosConfigurationDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosConfigurationDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosConfigurationDescriptorTest.java
new file mode 100644
index 0000000..6017fae
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosConfigurationDescriptorTest.java
@@ -0,0 +1,242 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.junit.Test;
+
+import java.util.*;
+
+public class KerberosConfigurationDescriptorTest {
+  private static final String JSON_SINGLE_VALUE =
+      "{ \"configuration-type\": {" +
+          "     \"property1\": \"${property-value1}\"," +
+          "     \"property2\": \"${property.value2}\"" +
+          "}}";
+
+  private static final String JSON_MULTIPLE_VALUE =
+      "[" +
+          "{ \"configuration-type\": {" +
+          "     \"property1\": \"value1\"," +
+          "     \"property2\": \"value2\"" +
+          "}}," +
+          "{ \"configuration-type2\": {" +
+          "     \"property1\": \"value1\"," +
+          "     \"property3\": \"value3\"," +
+          "     \"property2\": \"value2\"" +
+          "}}" +
+          "]";
+
+  private static final Map<String, Map<String, Object>> MAP_SINGLE_VALUE =
+      new HashMap<String, Map<String, Object>>() {
+        {
+          put("configuration-type", new HashMap<String, Object>() {
+            {
+              put("property1", "black");
+              put("property2", "white");
+            }
+          });
+        }
+      };
+
+  private static final Collection<Map<String, Map<String, Object>>> 
MAP_MULTIPLE_VALUES =
+      new ArrayList<Map<String, Map<String, Object>>>() {
+        {
+          add(MAP_SINGLE_VALUE);
+          add(new HashMap<String, Map<String, Object>>() {
+            {
+              put("configuration-type2", new HashMap<String, Object>() {
+                {
+                  put("property1", "red");
+                  put("property2", "yellow");
+                  put("property3", "green");
+                }
+              });
+            }
+          });
+        }
+      };
+
+
+  @Test
+  public void testJSONDeserialize() {
+    Map<String, Map<String, Object>> jsonData = new 
Gson().fromJson(JSON_SINGLE_VALUE,
+        new TypeToken<Map<String, Map<String, Object>>>() {
+        }.getType());
+
+    KerberosConfigurationDescriptor configuration = new 
KerberosConfigurationDescriptor(jsonData);
+
+    Assert.assertNotNull(configuration);
+    Assert.assertFalse(configuration.isContainer());
+
+    Map<String, String> properties = configuration.getProperties();
+
+    Assert.assertEquals("configuration-type", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("${property-value1}", properties.get("property1"));
+    Assert.assertEquals("${property.value2}", properties.get("property2"));
+  }
+
+  @Test
+  public void testJSONDeserializeMultiple() {
+    List<Map<String, Object>> jsonData = new 
Gson().fromJson(JSON_MULTIPLE_VALUE,
+        new TypeToken<List<Map<String, Object>>>() {
+        }.getType());
+
+
+    List<KerberosConfigurationDescriptor> configurations = new 
ArrayList<KerberosConfigurationDescriptor>();
+
+    for (Map<String, Object> item : jsonData) {
+      configurations.add(new KerberosConfigurationDescriptor(item));
+    }
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(2, configurations.size());
+
+    for (KerberosConfigurationDescriptor configuration : configurations) {
+      Assert.assertFalse(configuration.isContainer());
+      String type = configuration.getType();
+      Assert.assertEquals(2, configurations.size());
+
+      Map<String, String> properties = configuration.getProperties();
+
+      if ("configuration-type".equals(type)) {
+        Assert.assertNotNull(properties);
+        Assert.assertEquals(2, properties.size());
+        Assert.assertEquals("value1", properties.get("property1"));
+        Assert.assertEquals("value2", properties.get("property2"));
+
+      } else if ("configuration-type2".equals(type)) {
+        Assert.assertNotNull(properties);
+        Assert.assertEquals(3, properties.size());
+        Assert.assertEquals("value1", properties.get("property1"));
+        Assert.assertEquals("value2", properties.get("property2"));
+        Assert.assertEquals("value3", properties.get("property3"));
+        Assert.assertEquals("value1", configuration.getProperty("property1"));
+        Assert.assertEquals("value2", configuration.getProperty("property2"));
+        Assert.assertEquals("value3", configuration.getProperty("property3"));
+      } else {
+        Assert.fail("Missing expected configuration type");
+      }
+    }
+  }
+
+  @Test
+  public void testMapDeserialize() {
+    KerberosConfigurationDescriptor configuration = new 
KerberosConfigurationDescriptor(MAP_SINGLE_VALUE);
+    Map<String, String> properties = configuration.getProperties();
+
+    Assert.assertNotNull(configuration);
+    Assert.assertFalse(configuration.isContainer());
+    Assert.assertEquals("configuration-type", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("black", properties.get("property1"));
+    Assert.assertEquals("white", properties.get("property2"));
+  }
+
+  @Test
+  public void testMapDeserializeMultiple() {
+
+    List<KerberosConfigurationDescriptor> configurations = new 
ArrayList<KerberosConfigurationDescriptor>();
+
+    for (Map<String, Map<String, Object>> item : MAP_MULTIPLE_VALUES) {
+      configurations.add(new KerberosConfigurationDescriptor(item));
+    }
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(2, configurations.size());
+
+    for (KerberosConfigurationDescriptor configuration : configurations) {
+      Assert.assertFalse(configuration.isContainer());
+      String type = configuration.getType();
+      Map<String, String> properties = configuration.getProperties();
+
+      if ("configuration-type".equals(type)) {
+        Assert.assertNotNull(properties);
+        Assert.assertEquals(2, properties.size());
+        Assert.assertEquals("black", properties.get("property1"));
+        Assert.assertEquals("white", properties.get("property2"));
+        Assert.assertEquals("black", configuration.getProperty("property1"));
+        Assert.assertEquals("white", configuration.getProperty("property2"));
+      } else if ("configuration-type2".equals(type)) {
+        Assert.assertNotNull(properties);
+        Assert.assertEquals(3, properties.size());
+        Assert.assertEquals("red", properties.get("property1"));
+        Assert.assertEquals("yellow", properties.get("property2"));
+        Assert.assertEquals("green", properties.get("property3"));
+        Assert.assertEquals("red", configuration.getProperty("property1"));
+        Assert.assertEquals("yellow", configuration.getProperty("property2"));
+        Assert.assertEquals("green", configuration.getProperty("property3"));
+      } else {
+        Assert.fail("Missing expected configuration type");
+      }
+    }
+  }
+
+  @Test
+  public void testToMap() throws AmbariException {
+    KerberosConfigurationDescriptor descriptor = new 
KerberosConfigurationDescriptor(MAP_SINGLE_VALUE);
+    Assert.assertNotNull(descriptor);
+    Assert.assertEquals(MAP_SINGLE_VALUE, descriptor.toMap());
+  }
+
+  @Test
+  public void testUpdate() {
+    Map<String, Map<String, Object>> jsonData = new 
Gson().fromJson(JSON_SINGLE_VALUE,
+        new TypeToken<Map<String, Map<String, Object>>>() {
+        }.getType());
+
+    KerberosConfigurationDescriptor configuration = new 
KerberosConfigurationDescriptor(jsonData);
+    KerberosConfigurationDescriptor updatedConfiguration = new 
KerberosConfigurationDescriptor(MAP_SINGLE_VALUE);
+
+    Map<String, String> properties;
+
+    properties = configuration.getProperties();
+
+    Assert.assertEquals("configuration-type", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("${property-value1}", properties.get("property1"));
+    Assert.assertEquals("${property.value2}", properties.get("property2"));
+
+    configuration.update(updatedConfiguration);
+
+    properties = configuration.getProperties();
+
+    Assert.assertEquals("configuration-type", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("black", properties.get("property1"));
+    Assert.assertEquals("white", properties.get("property2"));
+
+    updatedConfiguration.setType("updated-type");
+
+    configuration.update(updatedConfiguration);
+
+    Assert.assertEquals("updated-type", configuration.getType());
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("black", properties.get("property1"));
+    Assert.assertEquals("white", properties.get("property2"));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
new file mode 100644
index 0000000..e882984
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
@@ -0,0 +1,328 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import com.google.gson.*;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class KerberosDescriptorTest {
+  public static final String JSON_VALUE =
+      "{" +
+          "  \"properties\": {" +
+          "      \"realm\": \"${cluster-env/kerberos_domain}\"," +
+          "      \"keytab_dir\": \"/etc/security/keytabs\"" +
+          "    }," +
+          "  \"services\": [" +
+          KerberosServiceDescriptorTest.JSON_VALUE +
+          "    ]" +
+          "}";
+
+  public static final Map<String, Object> MAP_VALUE =
+      new HashMap<String, Object>() {
+        {
+          put("properties", new HashMap<String, Object>() {{
+            put("realm", "EXAMPLE.COM");
+            put("some.property", "Hello World");
+          }});
+
+          put(KerberosDescriptorType.SERVICE.getDescriptorPluralName(), new 
ArrayList<Object>() {{
+            add(KerberosServiceDescriptorTest.MAP_VALUE);
+          }});
+          put(KerberosDescriptorType.CONFIGURATION.getDescriptorPluralName(), 
new ArrayList<Map<String, Object>>() {{
+            add(new HashMap<String, Object>() {
+              {
+                put("cluster-conf", new HashMap<String, String>() {
+                  {
+                    put("property1", "red");
+                  }
+                });
+              }
+            });
+          }});
+          put(KerberosDescriptorType.IDENTITY.getDescriptorPluralName(), new 
ArrayList<Object>() {{
+            add(new HashMap<String, Object>() {
+              {
+                put("name", "shared");
+                put("principal", new HashMap<String, 
Object>(KerberosPrincipalDescriptorTest.MAP_VALUE));
+                put("keytab", new HashMap<String, Object>() {
+                  {
+                    put("file", 
"/etc/security/keytabs/subject.service.keytab");
+
+                    put("owner", new HashMap<String, Object>() {{
+                      put("name", "root");
+                      put("access", "rw");
+                    }});
+
+                    put("group", new HashMap<String, Object>() {{
+                      put("name", "hadoop");
+                      put("access", "r");
+                    }});
+
+                    put("configuration", 
"service-site/service2.component.keytab.file");
+                  }
+                });
+              }
+            });
+          }});
+        }
+      };
+
+  public static void validateFromJSON(KerberosDescriptor descriptor) {
+    Assert.assertNotNull(descriptor);
+    Assert.assertTrue(descriptor.isContainer());
+
+    Map<String, String> properties = descriptor.getProperties();
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("${cluster-env/kerberos_domain}", 
properties.get("realm"));
+    Assert.assertEquals("/etc/security/keytabs", properties.get("keytab_dir"));
+
+    Map<String, KerberosServiceDescriptor> serviceDescriptors = 
descriptor.getServices();
+    Assert.assertNotNull(serviceDescriptors);
+    Assert.assertEquals(1, serviceDescriptors.size());
+
+    for (KerberosServiceDescriptor serviceDescriptor : 
serviceDescriptors.values()) {
+      KerberosServiceDescriptorTest.validateFromJSON(serviceDescriptor);
+    }
+
+    Map<String, KerberosConfigurationDescriptor> configurations = 
descriptor.getConfigurations();
+
+    Assert.assertNull(configurations);
+  }
+
+  public static void validateFromMap(KerberosDescriptor descriptor) throws 
AmbariException {
+    Assert.assertNotNull(descriptor);
+    Assert.assertTrue(descriptor.isContainer());
+
+    Map<String, String> properties = descriptor.getProperties();
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(2, properties.size());
+    Assert.assertEquals("EXAMPLE.COM", properties.get("realm"));
+    Assert.assertEquals("Hello World", properties.get("some.property"));
+
+    Map<String, KerberosServiceDescriptor> services = descriptor.getServices();
+    Assert.assertNotNull(services);
+    Assert.assertEquals(1, services.size());
+
+    for (KerberosServiceDescriptor service : services.values()) {
+      KerberosComponentDescriptor component = 
service.getComponent("A_DIFFERENT_COMPONENT_NAME");
+      Assert.assertNotNull(component);
+
+      List<KerberosIdentityDescriptor> resolvedIdentities = 
component.getIdentities(true);
+      KerberosIdentityDescriptor resolvedIdentity = null;
+      Assert.assertNotNull(resolvedIdentities);
+      Assert.assertEquals(3, resolvedIdentities.size());
+
+      for (KerberosIdentityDescriptor item : resolvedIdentities) {
+        if ("/shared".equals(item.getName())) {
+          resolvedIdentity = item;
+          break;
+        }
+      }
+      Assert.assertNotNull(resolvedIdentity);
+
+      List<KerberosIdentityDescriptor> identities = 
component.getIdentities(false);
+      Assert.assertNotNull(identities);
+      Assert.assertEquals(3, identities.size());
+
+      KerberosIdentityDescriptor identityReference = 
component.getIdentity("/shared");
+      Assert.assertNotNull(identityReference);
+
+      KerberosIdentityDescriptor referencedIdentity = 
descriptor.getIdentity("shared");
+      Assert.assertNotNull(referencedIdentity);
+
+      Assert.assertEquals(identityReference.getKeytabDescriptor(), 
resolvedIdentity.getKeytabDescriptor());
+      Assert.assertEquals(referencedIdentity.getPrincipalDescriptor(), 
resolvedIdentity.getPrincipalDescriptor());
+
+      Map<String, KerberosConfigurationDescriptor> configurations = 
service.getConfigurations(true);
+      Assert.assertNotNull(configurations);
+      Assert.assertEquals(2, configurations.size());
+      Assert.assertNotNull(configurations.get("service-site"));
+      Assert.assertNotNull(configurations.get("cluster-conf"));
+    }
+
+    Map<String, KerberosConfigurationDescriptor> configurations = 
descriptor.getConfigurations();
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(1, configurations.size());
+
+    KerberosConfigurationDescriptor configuration = 
configurations.get("cluster-conf");
+
+    Assert.assertNotNull(configuration);
+
+    Map<String, String> configProperties = configuration.getProperties();
+
+    Assert.assertEquals("cluster-conf", configuration.getType());
+    Assert.assertNotNull(configProperties);
+    Assert.assertEquals(1, configProperties.size());
+    Assert.assertEquals("red", configProperties.get("property1"));
+  }
+
+  public void validateUpdatedData(KerberosDescriptor descriptor) {
+    Assert.assertNotNull(descriptor);
+
+    Map<String, String> properties = descriptor.getProperties();
+    Assert.assertNotNull(properties);
+    Assert.assertEquals(3, properties.size());
+    Assert.assertEquals("EXAMPLE.COM", properties.get("realm"));
+    Assert.assertEquals("/etc/security/keytabs", properties.get("keytab_dir"));
+    Assert.assertEquals("Hello World", properties.get("some.property"));
+
+    Map<String, KerberosServiceDescriptor> serviceDescriptors = 
descriptor.getServices();
+    Assert.assertNotNull(serviceDescriptors);
+    Assert.assertEquals(2, serviceDescriptors.size());
+
+    
KerberosServiceDescriptorTest.validateFromJSON(descriptor.getService("SERVICE_NAME"));
+    
KerberosServiceDescriptorTest.validateFromMap(descriptor.getService("A_DIFFERENT_SERVICE_NAME"));
+
+    Assert.assertNull(descriptor.getService("invalid service"));
+
+    Map<String, KerberosConfigurationDescriptor> configurations = 
descriptor.getConfigurations();
+
+    Assert.assertNotNull(configurations);
+    Assert.assertEquals(1, configurations.size());
+
+    KerberosConfigurationDescriptor configuration = 
configurations.get("cluster-conf");
+
+    Assert.assertNotNull(configuration);
+
+    Map<String, String> configProperties = configuration.getProperties();
+
+    Assert.assertEquals("cluster-conf", configuration.getType());
+    Assert.assertNotNull(configProperties);
+    Assert.assertEquals(1, configProperties.size());
+    Assert.assertEquals("red", configProperties.get("property1"));
+  }
+
+  private KerberosDescriptor createFromJSON() {
+    return KerberosDescriptor.fromJSON(JSON_VALUE);
+  }
+
+  private KerberosDescriptor createFromMap() throws AmbariException {
+    return new KerberosDescriptor(MAP_VALUE);
+  }
+
+  @Test
+  public void testFromMapViaGSON() throws AmbariException {
+    Object data = new Gson().fromJson(JSON_VALUE, Object.class);
+
+    Assert.assertNotNull(data);
+
+    KerberosDescriptor descriptor = new KerberosDescriptor((Map<?, ?>) data);
+
+    validateFromJSON(descriptor);
+  }
+
+  @Test
+  public void testJSONDeserialize() {
+    validateFromJSON(createFromJSON());
+  }
+
+  @Test
+  public void testMapDeserialize() throws AmbariException {
+    validateFromMap(createFromMap());
+  }
+
+
+  @Test
+  public void testEquals() throws AmbariException {
+    Assert.assertTrue(createFromJSON().equals(createFromJSON()));
+    Assert.assertFalse(createFromJSON().equals(createFromMap()));
+  }
+
+  @Test
+  public void testToMap() throws AmbariException {
+    KerberosDescriptor descriptor = createFromMap();
+    Assert.assertNotNull(descriptor);
+    Assert.assertEquals(MAP_VALUE, descriptor.toMap());
+  }
+
+  @Test
+  public void testUpdate() throws AmbariException {
+    KerberosDescriptor descriptor = createFromJSON();
+    KerberosDescriptor updatedDescriptor = createFromMap();
+
+    Assert.assertNotNull(descriptor);
+    Assert.assertNotNull(updatedDescriptor);
+
+    descriptor.update(updatedDescriptor);
+
+    validateUpdatedData(descriptor);
+  }
+
+  @Test
+  public void testReplaceVariables() throws AmbariException {
+    Map<String, Map<String, String>> configurations = new HashMap<String, 
Map<String, String>>() {
+      {
+        put("", new HashMap<String, String>() {{
+          put("global_variable", "Hello World");
+        }});
+
+        put("config-type", new HashMap<String, String>() {{
+          put("variable.name", "Replacement1");
+          put("variable.name1", "${config-type2/variable.name}");
+          put("variable.name2", "");
+        }});
+
+        put("config-type2", new HashMap<String, String>() {{
+          put("variable.name", "Replacement2");
+          put("self_reference", "${config-type2/self_reference}");  // This 
essentially references itself.
+        }});
+      }
+    };
+
+    Assert.assertEquals("concrete",
+        KerberosDescriptor.replaceVariables("concrete", configurations));
+
+    Assert.assertEquals("Hello World",
+        KerberosDescriptor.replaceVariables("${global_variable}", 
configurations));
+
+    Assert.assertEquals("Replacement1",
+        KerberosDescriptor.replaceVariables("${config-type/variable.name}", 
configurations));
+
+    Assert.assertEquals("Replacement1|Replacement2",
+        
KerberosDescriptor.replaceVariables("${config-type/variable.name}|${config-type2/variable.name}",
 configurations));
+
+    
Assert.assertEquals("Replacement1|Replacement2|${config-type3/variable.name}",
+        
KerberosDescriptor.replaceVariables("${config-type/variable.name}|${config-type2/variable.name}|${config-type3/variable.name}",
 configurations));
+
+    Assert.assertEquals("Replacement2|Replacement2",
+        
KerberosDescriptor.replaceVariables("${config-type/variable.name1}|${config-type2/variable.name}",
 configurations));
+
+    // Replacement yields an empty string
+    Assert.assertEquals("",
+        KerberosDescriptor.replaceVariables("${config-type/variable.name2}", 
configurations));
+
+    // This might cause an infinite loop... we assume protection is in place...
+    try {
+      Assert.assertEquals("${config-type2/self_reference}",
+          
KerberosDescriptor.replaceVariables("${config-type2/self_reference}", 
configurations));
+      Assert.fail(String.format("%s expected to be thrown", 
AmbariException.class.getName()));
+    } catch (AmbariException e) {
+      // This is expected...
+    }
+
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptorTest.java
new file mode 100644
index 0000000..0ea7b26
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptorTest.java
@@ -0,0 +1,154 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class KerberosIdentityDescriptorTest {
+  public static final String JSON_VALUE =
+      "{" +
+          "  \"name\": \"identity_1\"" +
+          "," +
+          "  \"principal\":" + KerberosPrincipalDescriptorTest.JSON_VALUE +
+          "," +
+          "  \"keytab\":" + KerberosKeytabDescriptorTest.JSON_VALUE +
+          "}";
+
+  public static final Map<String, Object> MAP_VALUE =
+      new HashMap<String, Object>() {
+        {
+          put("name", "identity_1");
+          put("principal", KerberosPrincipalDescriptorTest.MAP_VALUE);
+          put("keytab", KerberosKeytabDescriptorTest.MAP_VALUE);
+          put("password", "secret");
+        }
+      };
+
+  public static final Map<String, Object> MAP_VALUE_ALT =
+      new HashMap<String, Object>() {
+        {
+          put("name", "identity_2");
+          put("principal", KerberosPrincipalDescriptorTest.MAP_VALUE);
+          put("keytab", KerberosKeytabDescriptorTest.MAP_VALUE);
+          put("password", "secret2");
+        }
+      };
+
+  public static final Map<String, Object> MAP_VALUE_REFERENCE =
+      new HashMap<String, Object>() {
+        {
+          put("name", "/shared");
+          put("keytab", new HashMap<String, Object>() {
+            {
+              put("file", "/home/user/me/subject.service.keytab");
+
+              put("owner", new HashMap<String, Object>() {{
+                put("name", "me");
+                put("access", "rw");
+              }});
+
+              put("group", new HashMap<String, Object>() {{
+                put("name", "nobody");
+                put("access", "");
+              }});
+
+              put("configuration", "service-site/me.component.keytab.file");
+            }
+          });
+        }
+      };
+
+  public static void validateFromJSON(KerberosIdentityDescriptor 
identityDescriptor) {
+    Assert.assertNotNull(identityDescriptor);
+    Assert.assertFalse(identityDescriptor.isContainer());
+
+    
KerberosPrincipalDescriptorTest.validateFromJSON(identityDescriptor.getPrincipalDescriptor());
+    
KerberosKeytabDescriptorTest.validateFromJSON(identityDescriptor.getKeytabDescriptor());
+    Assert.assertNull(identityDescriptor.getPassword());
+  }
+
+  public static void validateFromMap(KerberosIdentityDescriptor 
identityDescriptor) {
+    Assert.assertNotNull(identityDescriptor);
+    Assert.assertFalse(identityDescriptor.isContainer());
+
+    
KerberosPrincipalDescriptorTest.validateFromMap(identityDescriptor.getPrincipalDescriptor());
+    
KerberosKeytabDescriptorTest.validateFromMap(identityDescriptor.getKeytabDescriptor());
+    Assert.assertEquals("secret", identityDescriptor.getPassword());
+  }
+
+  public static void validateUpdatedData(KerberosIdentityDescriptor 
identityDescriptor) {
+    Assert.assertNotNull(identityDescriptor);
+
+    
KerberosPrincipalDescriptorTest.validateUpdatedData(identityDescriptor.getPrincipalDescriptor());
+    
KerberosKeytabDescriptorTest.validateUpdatedData(identityDescriptor.getKeytabDescriptor());
+    Assert.assertEquals("secret", identityDescriptor.getPassword());
+  }
+
+  private static KerberosIdentityDescriptor createFromJSON() {
+    Map<?, ?> map = new Gson().fromJson(JSON_VALUE, new TypeToken<Map<?, ?>>() 
{
+    }.getType());
+    return new KerberosIdentityDescriptor(map);
+  }
+
+  private static KerberosIdentityDescriptor createFromMap() {
+    return new KerberosIdentityDescriptor(MAP_VALUE);
+  }
+
+  @Test
+  public void testJSONDeserialize() {
+    validateFromJSON(createFromJSON());
+  }
+
+  @Test
+  public void testMapDeserialize() {
+    validateFromMap(createFromMap());
+  }
+
+  @Test
+  public void testEquals() throws AmbariException {
+    Assert.assertTrue(createFromJSON().equals(createFromJSON()));
+    Assert.assertFalse(createFromJSON().equals(createFromMap()));
+  }
+
+  @Test
+  public void testToMap() throws AmbariException {
+    KerberosIdentityDescriptor descriptor = createFromMap();
+    Assert.assertNotNull(descriptor);
+    Assert.assertEquals(MAP_VALUE, descriptor.toMap());
+  }
+
+  @Test
+  public void testUpdate() {
+    KerberosIdentityDescriptor identityDescriptor = createFromJSON();
+    KerberosIdentityDescriptor updatedIdentityDescriptor = createFromMap();
+
+    Assert.assertNotNull(identityDescriptor);
+    Assert.assertNotNull(updatedIdentityDescriptor);
+
+    identityDescriptor.update(updatedIdentityDescriptor);
+
+    validateUpdatedData(identityDescriptor);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptorTest.java
new file mode 100644
index 0000000..c10d106
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosKeytabDescriptorTest.java
@@ -0,0 +1,146 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class KerberosKeytabDescriptorTest {
+  public static final String JSON_VALUE =
+      "{" +
+          "  \"file\": 
\"/etc/security/keytabs/${host}/subject.service.keytab\"," +
+          "  \"owner\": {" +
+          "      \"name\": \"subject\"," +
+          "      \"access\": \"rw\"" +
+          "  }," +
+          "  \"group\": {" +
+          "      \"name\": \"hadoop\"," +
+          "      \"access\": \"r\"" +
+          "  }," +
+          "  \"configuration\": 
\"service-site/service.component.keytab.file\"" +
+          "}";
+
+  public static final Map<String, Object> MAP_VALUE =
+      new HashMap<String, Object>() {
+        {
+          put("file", "/etc/security/keytabs/subject.service.keytab");
+
+          put("owner", new HashMap<String, Object>() {{
+            put("name", "root");
+            put("access", "rw");
+          }});
+
+          put("group", new HashMap<String, Object>() {{
+            put("name", "hadoop");
+            put("access", "r");
+          }});
+
+          put("configuration", "service-site/service2.component.keytab.file");
+        }
+      };
+
+  public static void validateFromJSON(KerberosKeytabDescriptor 
keytabDescriptor) {
+    Assert.assertNotNull(keytabDescriptor);
+    Assert.assertFalse(keytabDescriptor.isContainer());
+
+    
Assert.assertEquals("/etc/security/keytabs/${host}/subject.service.keytab", 
keytabDescriptor.getFile());
+    Assert.assertEquals("subject", keytabDescriptor.getOwnerName());
+    Assert.assertEquals("rw", keytabDescriptor.getOwnerAccess());
+    Assert.assertEquals("hadoop", keytabDescriptor.getGroupName());
+    Assert.assertEquals("r", keytabDescriptor.getGroupAccess());
+    Assert.assertEquals("service-site/service.component.keytab.file", 
keytabDescriptor.getConfiguration());
+  }
+
+  public static void validateFromMap(KerberosKeytabDescriptor 
keytabDescriptor) {
+    Assert.assertNotNull(keytabDescriptor);
+    Assert.assertFalse(keytabDescriptor.isContainer());
+
+    Assert.assertEquals("/etc/security/keytabs/subject.service.keytab", 
keytabDescriptor.getFile());
+    Assert.assertEquals("root", keytabDescriptor.getOwnerName());
+    Assert.assertEquals("rw", keytabDescriptor.getOwnerAccess());
+    Assert.assertEquals("hadoop", keytabDescriptor.getGroupName());
+    Assert.assertEquals("r", keytabDescriptor.getGroupAccess());
+    Assert.assertEquals("service-site/service2.component.keytab.file", 
keytabDescriptor.getConfiguration());
+  }
+
+  public static void validateUpdatedData(KerberosKeytabDescriptor 
keytabDescriptor) {
+    Assert.assertNotNull(keytabDescriptor);
+
+    Assert.assertEquals("/etc/security/keytabs/subject.service.keytab", 
keytabDescriptor.getFile());
+    Assert.assertEquals("root", keytabDescriptor.getOwnerName());
+    Assert.assertEquals("rw", keytabDescriptor.getOwnerAccess());
+    Assert.assertEquals("hadoop", keytabDescriptor.getGroupName());
+    Assert.assertEquals("r", keytabDescriptor.getGroupAccess());
+    Assert.assertEquals("service-site/service2.component.keytab.file", 
keytabDescriptor.getConfiguration());
+  }
+
+  private static KerberosKeytabDescriptor createFromJSON() {
+    Map<?, ?> map = new Gson().fromJson(JSON_VALUE,
+        new TypeToken<Map<?, ?>>() {
+        }.getType());
+    return new KerberosKeytabDescriptor(map);
+
+  }
+
+  private static KerberosKeytabDescriptor createFromMap() {
+    return new KerberosKeytabDescriptor(MAP_VALUE);
+  }
+
+  @Test
+  public void testJSONDeserialize() {
+    validateFromJSON(createFromJSON());
+  }
+
+  @Test
+  public void testMapDeserialize() {
+    validateFromMap(createFromMap());
+  }
+
+  @Test
+  public void testEquals() throws AmbariException {
+    Assert.assertTrue(createFromJSON().equals(createFromJSON()));
+    Assert.assertFalse(createFromJSON().equals(createFromMap()));
+  }
+
+  @Test
+  public void testToMap() throws AmbariException {
+    KerberosKeytabDescriptor descriptor = createFromMap();
+    Assert.assertNotNull(descriptor);
+    Assert.assertEquals(MAP_VALUE, descriptor.toMap());
+  }
+
+  @Test
+  public void testUpdate() {
+    KerberosKeytabDescriptor keytabDescriptor = createFromJSON();
+
+    KerberosKeytabDescriptor updatedKeytabDescriptor = createFromMap();
+
+    Assert.assertNotNull(keytabDescriptor);
+    Assert.assertNotNull(updatedKeytabDescriptor);
+
+    keytabDescriptor.update(updatedKeytabDescriptor);
+
+    validateUpdatedData(keytabDescriptor);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b8383b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptorTest.java
new file mode 100644
index 0000000..a35bad3
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosPrincipalDescriptorTest.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.kerberos;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.junit.Test;
+
+import java.util.*;
+
+public class KerberosPrincipalDescriptorTest {
+  public static final String JSON_VALUE =
+      "{" +
+          "\"value\": \"service/_HOST@_REALM\"," +
+          "\"configuration\": 
\"service-site/service.component.kerberos.principal\"" +
+          "}";
+
+  public static final Map<String, Object> MAP_VALUE =
+      new HashMap<String, Object>() {
+        {
+          put("value", "HTTP/_HOST@_REALM");
+          put("configuration", 
"service-site/service.component.kerberos.https.principal");
+        }
+      };
+
+  public static void validateFromJSON(KerberosPrincipalDescriptor 
principalDescriptor) {
+    Assert.assertNotNull(principalDescriptor);
+    Assert.assertFalse(principalDescriptor.isContainer());
+    Assert.assertEquals("service/_HOST@_REALM", 
principalDescriptor.getValue());
+    Assert.assertEquals("service-site/service.component.kerberos.principal", 
principalDescriptor.getConfiguration());
+  }
+
+  public static void validateFromMap(KerberosPrincipalDescriptor 
principalDescriptor) {
+    Assert.assertNotNull(principalDescriptor);
+    Assert.assertFalse(principalDescriptor.isContainer());
+    Assert.assertEquals("HTTP/_HOST@_REALM", principalDescriptor.getValue());
+    
Assert.assertEquals("service-site/service.component.kerberos.https.principal", 
principalDescriptor.getConfiguration());
+  }
+
+  public static void validateUpdatedData(KerberosPrincipalDescriptor 
principalDescriptor) {
+    Assert.assertNotNull(principalDescriptor);
+    Assert.assertEquals("HTTP/_HOST@_REALM", principalDescriptor.getValue());
+    
Assert.assertEquals("service-site/service.component.kerberos.https.principal", 
principalDescriptor.getConfiguration());
+  }
+
+  private static KerberosPrincipalDescriptor createFromJSON() {
+    Map<?, ?> map = new Gson().fromJson(JSON_VALUE,
+        new TypeToken<Map<?, ?>>() {
+        }.getType());
+    return new KerberosPrincipalDescriptor(map);
+  }
+
+  private static KerberosPrincipalDescriptor createFromMap() {
+    return new KerberosPrincipalDescriptor(MAP_VALUE);
+  }
+
+  @Test
+  public void testJSONDeserialize() {
+    validateFromJSON(createFromJSON());
+  }
+
+  @Test
+  public void testMapDeserialize() {
+    validateFromMap(createFromMap());
+  }
+
+  @Test
+  public void testEquals() throws AmbariException {
+    Assert.assertTrue(createFromJSON().equals(createFromJSON()));
+    Assert.assertFalse(createFromJSON().equals(createFromMap()));
+  }
+
+  @Test
+  public void testToMap() throws AmbariException {
+    KerberosPrincipalDescriptor descriptor = createFromMap();
+    Assert.assertNotNull(descriptor);
+    Assert.assertEquals(MAP_VALUE, descriptor.toMap());
+  }
+
+  @Test
+  public void testUpdate() {
+    KerberosPrincipalDescriptor principalDescriptor = createFromJSON();
+    KerberosPrincipalDescriptor updatedPrincipalDescriptor = createFromMap();
+
+    Assert.assertNotNull(principalDescriptor);
+    Assert.assertNotNull(updatedPrincipalDescriptor);
+
+    principalDescriptor.update(updatedPrincipalDescriptor);
+
+    validateUpdatedData(principalDescriptor);
+  }
+}
\ No newline at end of file

Reply via email to