You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2018/01/02 16:55:55 UTC

[04/37] ambari git commit: AMBARI-22530. Refactor internal code of handling info between kerberos wizard actions (echekanskiy)

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
index 52ab9b5..d90d5bf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
@@ -36,9 +36,10 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.dao.KerberosKeytabPrincipalDAO;
 import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
-import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
 import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity;
 import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
@@ -101,12 +102,6 @@ public class HostKerberosIdentityResourceProvider extends ReadOnlyResourceProvid
   private KerberosHelper kerberosHelper;
 
   /**
-   * KerberosPrincipalHostDAO used to get Kerberos principal details
-   */
-  @Inject
-  private KerberosPrincipalHostDAO kerberosPrincipalHostDAO;
-
-  /**
    * KerberosPrincipalDAO used to get Kerberos principal details
    */
   @Inject
@@ -118,6 +113,9 @@ public class HostKerberosIdentityResourceProvider extends ReadOnlyResourceProvid
   @Inject
   private HostDAO hostDAO;
 
+  @Inject
+  private KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO;
+
   /**
    * Create a  new resource provider for the given management controller.
    *
@@ -200,7 +198,8 @@ public class HostKerberosIdentityResourceProvider extends ReadOnlyResourceProvid
 
                     if ((hostId != null) && kerberosPrincipalDAO.exists(principal)) {
                       if (keytabDescriptor != null) {
-                        if (kerberosPrincipalHostDAO.exists(principal, hostId, keytabDescriptor.getFile())) {
+                        KerberosKeytabPrincipalEntity entity = kerberosKeytabPrincipalDAO.findByNaturalKey(hostId, keytabDescriptor.getFile(), principal);
+                        if (entity != null && entity.isDistributed()) {
                           installedStatus = "true";
                         } else {
                           installedStatus = "false";

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabDAO.java
index a8723b7..ca7d23c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabDAO.java
@@ -18,14 +18,13 @@
 
 package org.apache.ambari.server.orm.dao;
 
-import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.orm.RequiresSession;
-import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.KerberosKeytabEntity;
 
 import com.google.inject.Inject;
@@ -35,76 +34,103 @@ import com.google.inject.persist.Transactional;
 
 @Singleton
 public class KerberosKeytabDAO {
-    @Inject
-    Provider<EntityManager> entityManagerProvider;
-
-    @Transactional
-    public void create(KerberosKeytabEntity kerberosKeytabEntity) {
-        entityManagerProvider.get().persist(kerberosKeytabEntity);
-    }
-
-    public void create(String keytabPath) {
-        create(new KerberosKeytabEntity(keytabPath));
-    }
-
-    @Transactional
-    public KerberosKeytabEntity merge(KerberosKeytabEntity kerberosKeytabEntity) {
-        return entityManagerProvider.get().merge(kerberosKeytabEntity);
-    }
-
-    @Transactional
-    public void remove(KerberosKeytabEntity kerberosKeytabEntity) {
-        entityManagerProvider.get().remove(merge(kerberosKeytabEntity));
-    }
-
-    public void remove(String keytabPath) {
-        KerberosKeytabEntity kke = find(keytabPath);
-        if (kke != null) {
-            remove(kke);
-        }
-    }
-
-    @Transactional
-    public void refresh(KerberosKeytabEntity kerberosKeytabEntity) {
-        entityManagerProvider.get().refresh(kerberosKeytabEntity);
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+
+  @Inject
+  KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO;
+
+  @Transactional
+  public void create(KerberosKeytabEntity kerberosKeytabEntity) {
+    entityManagerProvider.get().persist(kerberosKeytabEntity);
+  }
+
+  public void create(String keytabPath) {
+    create(new KerberosKeytabEntity(keytabPath));
+  }
+
+  @Transactional
+  public KerberosKeytabEntity merge(KerberosKeytabEntity kerberosKeytabEntity) {
+    return entityManagerProvider.get().merge(kerberosKeytabEntity);
+  }
+
+  @Transactional
+  public void remove(KerberosKeytabEntity kerberosKeytabEntity) {
+    entityManagerProvider.get().remove(merge(kerberosKeytabEntity));
+  }
+
+  public void remove(String keytabPath) {
+    KerberosKeytabEntity kke = find(keytabPath);
+    if (kke != null) {
+      remove(kke);
     }
+  }
 
+  @Transactional
+  public void refresh(KerberosKeytabEntity kerberosKeytabEntity) {
+    entityManagerProvider.get().refresh(kerberosKeytabEntity);
+  }
 
-    @RequiresSession
-    public KerberosKeytabEntity find(String keytabPath) {
-        return entityManagerProvider.get().find(KerberosKeytabEntity.class, keytabPath);
-    }
 
-    @RequiresSession
-    public List<KerberosKeytabEntity> findAll() {
-        TypedQuery<KerberosKeytabEntity> query = entityManagerProvider.get().
-                createNamedQuery("KerberosKeytabEntity.findAll", KerberosKeytabEntity.class);
+  @RequiresSession
+  public KerberosKeytabEntity find(String keytabPath) {
+    return entityManagerProvider.get().find(KerberosKeytabEntity.class, keytabPath);
+  }
 
-        return query.getResultList();
+  @RequiresSession
+  public List<KerberosKeytabEntity> findByPrincipalAndHost(String principalName, Long hostId) {
+    if(hostId == null) {
+      return findByPrincipalAndNullHost(principalName);
     }
-
-    @RequiresSession
-    public boolean exists(String keytabPath) {
-        return find(keytabPath) != null;
+    TypedQuery<KerberosKeytabEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabEntity.findByPrincipalAndHost", KerberosKeytabEntity.class);
+    query.setParameter("hostId", hostId);
+    query.setParameter("principalName", principalName);
+    List<KerberosKeytabEntity> result = query.getResultList();
+    if(result == null) {
+      return Collections.emptyList();
     }
-
-    @RequiresSession
-    public Collection<KerberosKeytabEntity> findByHost(Long hostId) {
-        TypedQuery<KerberosKeytabEntity> query = entityManagerProvider.get().
-            createNamedQuery("KerberosKeytabEntity.findByHost", KerberosKeytabEntity.class);
-        query.setParameter("hostId", hostId);
-        return query.getResultList();
+    return result;
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabEntity> findByPrincipalAndNullHost(String principalName) {
+    TypedQuery<KerberosKeytabEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabEntity.findByPrincipalAndNullHost", KerberosKeytabEntity.class);
+    query.setParameter("principalName", principalName);
+    List<KerberosKeytabEntity> result = query.getResultList();
+    if(result == null) {
+      return Collections.emptyList();
     }
-
-    public Collection<KerberosKeytabEntity> findByHost(HostEntity hostEntity) {
-        return findByHost(hostEntity.getHostId());
+    return result;
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabEntity> findAll() {
+    TypedQuery<KerberosKeytabEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabEntity.findAll", KerberosKeytabEntity.class);
+    List<KerberosKeytabEntity> result = query.getResultList();
+    if(result == null) {
+      return Collections.emptyList();
     }
-
-    public void remove(List<KerberosKeytabEntity> entities) {
-        if (entities != null) {
-            for (KerberosKeytabEntity entity : entities) {
-                entityManagerProvider.get().remove(entity);
-            }
-        }
+    return result;
+  }
+
+  @RequiresSession
+  public boolean exists(String keytabPath) {
+    return find(keytabPath) != null;
+  }
+
+  @RequiresSession
+  public boolean exists(KerberosKeytabEntity kerberosKeytabEntity) {
+    return find(kerberosKeytabEntity.getKeytabPath()) != null;
+  }
+
+  public void remove(List<KerberosKeytabEntity> entities) {
+    if (entities != null) {
+      for (KerberosKeytabEntity entity : entities) {
+        remove(entity);
+      }
     }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java
new file mode 100644
index 0000000..bf4b75b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java
@@ -0,0 +1,309 @@
+/*
+ * 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.orm.dao;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Join;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.KerberosKeytabEntity;
+import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity;
+import org.apache.ambari.server.orm.entities.KerberosKeytabServiceMappingEntity;
+import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+
+@Singleton
+public class KerberosKeytabPrincipalDAO {
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+
+  @Inject
+  HostDAO hostDAO;
+
+  @Transactional
+  public void create(KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity) {
+    entityManagerProvider.get().persist(kerberosKeytabPrincipalEntity);
+  }
+
+  @Transactional
+  public void create(
+    KerberosKeytabEntity kerberosKeytabEntity,
+    HostEntity hostEntity,
+    KerberosPrincipalEntity principalEntity) {
+    entityManagerProvider.get().persist(
+      new KerberosKeytabPrincipalEntity(kerberosKeytabEntity, hostEntity, principalEntity)
+    );
+  }
+
+  /**
+   * Find or create {@link KerberosKeytabPrincipalEntity} with specified dependecies.
+   *
+   * @param kerberosKeytabEntity {@link KerberosKeytabEntity} which owns this principal
+   * @param hostEntity  {@link HostEntity} which owns this principal
+   * @param principalEntity {@link KerberosPrincipalEntity} which related to this principal
+   * @return evaluated entity
+   */
+  public KerberosKeytabPrincipalEntity findOrCreate(KerberosKeytabEntity kerberosKeytabEntity, HostEntity hostEntity, KerberosPrincipalEntity principalEntity)
+  {
+    Long hostId = hostEntity == null ? null : hostEntity.getHostId();
+    KerberosKeytabPrincipalEntity kkp = findByNaturalKey(hostId, kerberosKeytabEntity.getKeytabPath(), principalEntity.getPrincipalName());
+    if (kkp == null) {
+      kkp = new KerberosKeytabPrincipalEntity(
+        kerberosKeytabEntity,
+        hostEntity,
+        principalEntity
+      );
+      create(kkp);
+      kerberosKeytabEntity.addKerberosKeytabPrincipal(kkp);
+    }
+    return kkp;
+  }
+
+  @Transactional
+  public KerberosKeytabPrincipalEntity merge(KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity) {
+    return entityManagerProvider.get().merge(kerberosKeytabPrincipalEntity);
+  }
+
+  @Transactional
+  public void remove(KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity) {
+    entityManagerProvider.get().remove(merge(kerberosKeytabPrincipalEntity));
+  }
+
+  public void remove(Collection<KerberosKeytabPrincipalEntity> kerberosKeytabPrincipalEntities) {
+    for (KerberosKeytabPrincipalEntity entity : kerberosKeytabPrincipalEntities) {
+      remove(entity);
+    }
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabPrincipalEntity> findByPrincipal(String principal) {
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabPrincipalEntity.findByPrincipal", KerberosKeytabPrincipalEntity.class);
+    query.setParameter("principalName", principal);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null) {
+      return Collections.emptyList();
+    }
+    return result;
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabPrincipalEntity> findByHost(Long hostId) {
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabPrincipalEntity.findByHost", KerberosKeytabPrincipalEntity.class);
+    query.setParameter("hostId", hostId);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null) {
+      return Collections.emptyList();
+    }
+    return result;
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabPrincipalEntity> findByHostAndKeytab(Long hostId, String keytabPath) {
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabPrincipalEntity.findByHostAndKeytab", KerberosKeytabPrincipalEntity.class);
+    query.setParameter("hostId", hostId);
+    query.setParameter("keytabPath", keytabPath);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null) {
+      return Collections.emptyList();
+    }
+    return result;
+  }
+
+  @RequiresSession
+  public KerberosKeytabPrincipalEntity findByHostKeytabAndPrincipal(Long hostId, String keytabPath, String principalName) {
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabPrincipalEntity.findByHostKeytabAndPrincipal", KerberosKeytabPrincipalEntity.class);
+    query.setParameter("hostId", hostId);
+    query.setParameter("keytabPath", keytabPath);
+    query.setParameter("principalName", principalName);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null || result.size() == 0) {
+      return null;
+    } else {
+      return result.get(0);
+    }
+  }
+
+  @RequiresSession
+  public KerberosKeytabPrincipalEntity findByKeytabAndPrincipalNullHost(String keytabPath, String principal) {
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabPrincipalEntity.findByKeytabAndPrincipalNullHost", KerberosKeytabPrincipalEntity.class);
+    query.setParameter("keytabPath", keytabPath);
+    query.setParameter("principalName", principal);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null || result.size() == 0) {
+      return null;
+    } else {
+      return result.get(0);
+    }
+  }
+
+  /**
+   * Ideally for this record PK must be (hostId, keytabPath, principalName), but in some cases hostId can be null.
+   * So surrogate auto-generated PK used, and unique constraint for (hostId, keytabPath, principalName) applied.
+   * This method checks if hostId is null and calls specific method.
+   *
+   * @param hostId host id
+   * @param keytabPath keytab path
+   * @param principalName principal name
+   * @return keytab found
+   */
+  public KerberosKeytabPrincipalEntity findByNaturalKey(Long hostId, String keytabPath, String principalName) {
+    if (hostId == null) {
+      return findByKeytabAndPrincipalNullHost(keytabPath, principalName);
+    } else {
+      return findByHostKeytabAndPrincipal(hostId, keytabPath, principalName);
+    }
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabPrincipalEntity> findByFilter(KerberosKeytabPrincipalFilter filter) {
+    CriteriaBuilder cb = entityManagerProvider.get().getCriteriaBuilder();
+    CriteriaQuery<KerberosKeytabPrincipalEntity> cq = cb.createQuery(KerberosKeytabPrincipalEntity.class);
+    Root<KerberosKeytabPrincipalEntity> root = cq.from(KerberosKeytabPrincipalEntity.class);
+    ArrayList<Predicate> predicates = new ArrayList<>();
+    if (filter.getServiceNames() != null && filter.getServiceNames().size() > 0)
+    {
+      Join<KerberosKeytabPrincipalEntity, KerberosKeytabServiceMappingEntity> mappingJoin = root.join("serviceMapping");
+      predicates.add(mappingJoin.get("serviceName").in(filter.getServiceNames()));
+      if (filter.getComponentNames() != null && filter.getComponentNames().size() > 0) {
+        predicates.add(mappingJoin.get("componentName").in(filter.getComponentNames()));
+      }
+    }
+    if (filter.getHostNames() != null && filter.getHostNames().size() > 0) {
+      List<Long> hostIds = new ArrayList<>();
+      for (String hostname : filter.getHostNames()) {
+        hostIds.add(hostDAO.findByName(hostname).getHostId());
+      }
+      predicates.add(root.get("hostId").in(hostIds));
+    }
+    if (filter.getPrincipals() != null && filter.getPrincipals().size() > 0) {
+      predicates.add(root.get("principalName").in(filter.getPrincipals()));
+    }
+    cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
+
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().createQuery(cq);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null) {
+      return Collections.emptyList();
+    }
+    return result;
+  }
+
+
+  public List<KerberosKeytabPrincipalEntity> findByFilters(Collection<KerberosKeytabPrincipalFilter> filters) {
+    ArrayList<KerberosKeytabPrincipalEntity> result = new ArrayList<>();
+    for (KerberosKeytabPrincipalFilter filter : filters) {
+      result.addAll(findByFilter(filter));
+    }
+    return result;
+  }
+
+  @RequiresSession
+  public boolean exists(Long hostId, String keytabPath, String principalName) {
+    return findByNaturalKey(hostId, keytabPath, principalName) != null;
+  }
+
+  @RequiresSession
+  public List<KerberosKeytabPrincipalEntity> findAll() {
+    TypedQuery<KerberosKeytabPrincipalEntity> query = entityManagerProvider.get().
+      createNamedQuery("KerberosKeytabPrincipalEntity.findAll", KerberosKeytabPrincipalEntity.class);
+    List<KerberosKeytabPrincipalEntity> result = query.getResultList();
+    if (result == null) {
+      return Collections.emptyList();
+    }
+    return result;
+  }
+
+  @Transactional
+  public void remove(List<KerberosKeytabPrincipalEntity> entities) {
+    if (entities != null) {
+      for (KerberosKeytabPrincipalEntity entity : entities) {
+        entityManagerProvider.get().remove(merge(entity));
+      }
+    }
+  }
+
+  public void removeByHost(Long hostId) {
+    remove(findByHost(hostId));
+  }
+
+  public static class KerberosKeytabPrincipalFilter {
+    private Collection<String> hostNames;
+    private Collection<String> serviceNames;
+    private Collection<String> componentNames;
+    private Collection<String> principals;
+
+    public KerberosKeytabPrincipalFilter(Collection<String> hostNames, Collection<String> serviceNames, Collection<String> componentNames, Collection<String> principals) {
+      this.hostNames = hostNames;
+      this.serviceNames = serviceNames;
+      this.componentNames = componentNames;
+      this.principals = principals;
+    }
+
+    public Collection<String> getHostNames() {
+      return hostNames;
+    }
+
+    public void setHostNames(Collection<String> hostNames) {
+      this.hostNames = hostNames;
+    }
+
+    public Collection<String> getServiceNames() {
+      return serviceNames;
+    }
+
+    public void setServiceNames(Collection<String> serviceNames) {
+      this.serviceNames = serviceNames;
+    }
+
+    public Collection<String> getComponentNames() {
+      return componentNames;
+    }
+
+    public void setComponentNames(Collection<String> componentNames) {
+      this.componentNames = componentNames;
+    }
+
+    public Collection<String> getPrincipals() {
+      return principals;
+    }
+
+    public void setPrincipals(Collection<String> principals) {
+      this.principals = principals;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalDAO.java
index 81e4b3d..5367e9b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalDAO.java
@@ -46,12 +46,6 @@ public class KerberosPrincipalDAO {
   Provider<EntityManager> entityManagerProvider;
 
   /**
-   * Kerberos Principal Host DAO
-   */
-  @Inject
-  private KerberosPrincipalHostDAO kerberosPrincipalHostDAO;
-
-  /**
    * Make an instance managed and persistent.
    *
    * @param kerberosPrincipalEntity entity to persist
@@ -95,9 +89,6 @@ public class KerberosPrincipalDAO {
       EntityManager entityManager = entityManagerProvider.get();
       String principalName = kerberosPrincipalEntity.getPrincipalName();
 
-      // Remove child entities...
-      kerberosPrincipalHostDAO.removeByPrincipal(principalName);
-
       kerberosPrincipalEntity = find(principalName);
       if (kerberosPrincipalEntity != null) {
         entityManager.remove(kerberosPrincipalEntity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalHostDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalHostDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalHostDAO.java
deleted file mode 100644
index f27dc48..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosPrincipalHostDAO.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 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.orm.dao;
-
-
-import java.util.List;
-
-import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
-
-import org.apache.ambari.server.orm.RequiresSession;
-import org.apache.ambari.server.orm.entities.KerberosPrincipalHostEntity;
-import org.apache.ambari.server.orm.entities.KerberosPrincipalHostEntityPK;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.google.inject.persist.Transactional;
-
-
-/**
- * HostKerberosPrincipal Data Access Object.
- */
-@Singleton
-public class KerberosPrincipalHostDAO {
-
-  /**
-   * JPA entity manager
-   */
-  @Inject
-  Provider<EntityManager> entityManagerProvider;
-
-  /**
-   * Make an instance managed and persistent.
-   *
-   * @param kerberosPrincipalHostEntity entity to persist
-   */
-  @Transactional
-  public void create(KerberosPrincipalHostEntity kerberosPrincipalHostEntity) {
-    entityManagerProvider.get().persist(kerberosPrincipalHostEntity);
-  }
-
-  public void create(String principal, Long hostId, String keytabPath) {
-    create(new KerberosPrincipalHostEntity(principal, hostId, keytabPath));
-  }
-
-  /**
-   * Merge the state of the given entity into the current persistence context.
-   *
-   * @param kerberosPrincipalHostEntity entity to merge
-   * @return the merged entity
-   */
-  @Transactional
-  public KerberosPrincipalHostEntity merge(KerberosPrincipalHostEntity kerberosPrincipalHostEntity) {
-    return entityManagerProvider.get().merge(kerberosPrincipalHostEntity);
-  }
-
-  /**
-   * Remove the entity instance.
-   *
-   * @param kerberosPrincipalHostEntity entity to remove
-   */
-  @Transactional
-  public void remove(KerberosPrincipalHostEntity kerberosPrincipalHostEntity) {
-    entityManagerProvider.get().remove(merge(kerberosPrincipalHostEntity));
-  }
-
-  /**
-   * Refresh the state of the instance from the database,
-   * overwriting changes made to the entity, if any.
-   *
-   * @param kerberosPrincipalHostEntity entity to refresh
-   */
-  @Transactional
-  public void refresh(KerberosPrincipalHostEntity kerberosPrincipalHostEntity) {
-    entityManagerProvider.get().refresh(kerberosPrincipalHostEntity);
-  }
-
-  /**
-   * Finds KerberosPrincipalHostEntities for the requested principal
-   *
-   * @param principalName a String indicating the name of the requested principal
-   * @return a List of requested KerberosPrincipalHostEntities or null if none were found
-   */
-  @RequiresSession
-  public List<KerberosPrincipalHostEntity> findByPrincipal(String principalName) {
-    final TypedQuery<KerberosPrincipalHostEntity> query = entityManagerProvider.get()
-        .createNamedQuery("KerberosPrincipalHostEntityFindByPrincipal", KerberosPrincipalHostEntity.class);
-    query.setParameter("principalName", principalName);
-    return query.getResultList();
-  }
-
-  /**
-   * Find KerberosPrincipalHostEntities for the requested host
-   *
-   * @param hostId a Long indicating the id of the requested host
-   * @return a List of requested KerberosPrincipalHostEntities or null if none were found
-   */
-  @RequiresSession
-  public List<KerberosPrincipalHostEntity> findByHost(Long hostId) {
-    final TypedQuery<KerberosPrincipalHostEntity> query = entityManagerProvider.get()
-        .createNamedQuery("KerberosPrincipalHostEntityFindByHost", KerberosPrincipalHostEntity.class);
-    query.setParameter("hostId", hostId);
-    return query.getResultList();
-  }
-
-  /**
-   * Find KerberosPrincipalHostEntities for the requested host
-   *
-   * @return a List of requested KerberosPrincipalHostEntities or null if none were found
-   */
-  @RequiresSession
-  public List<KerberosPrincipalHostEntity> findByKeytabPath(String keytabPath) {
-    final TypedQuery<KerberosPrincipalHostEntity> query = entityManagerProvider.get()
-        .createNamedQuery("KerberosPrincipalHostEntityFindByKeytabPath", KerberosPrincipalHostEntity.class);
-    query.setParameter("keytabPath", keytabPath);
-    return query.getResultList();
-  }
-
-  /**
-   * Find the KerberosPrincipalHostEntity for the specified primary key
-   *
-   * @param primaryKey a KerberosPrincipalHostEntityPK containing the requested principal and host names
-   * @return the KerberosPrincipalHostEntity or null if not found
-   */
-  @RequiresSession
-  public KerberosPrincipalHostEntity find(KerberosPrincipalHostEntityPK primaryKey) {
-    return entityManagerProvider.get().find(KerberosPrincipalHostEntity.class, primaryKey);
-  }
-
-  /**
-   * Find the KerberosPrincipalHostEntity for the requested principal name and host
-   *
-   * @param principalName a String indicating the name of the requested principal
-   * @param hostId        a Long indicating the id of the requested host
-   * @return the KerberosPrincipalHostEntity or null if not found
-   */
-  @RequiresSession
-  public KerberosPrincipalHostEntity find(String principalName, Long hostId, String keytabPath) {
-    return entityManagerProvider.get().find(KerberosPrincipalHostEntity.class,
-        new KerberosPrincipalHostEntityPK(principalName, hostId, keytabPath));
-  }
-
-  /**
-   * Find all KerberosPrincipalHostEntities.
-   *
-   * @return a List of requested KerberosPrincipalHostEntities or null if none were found
-   */
-  @RequiresSession
-  public List<KerberosPrincipalHostEntity> findAll() {
-    TypedQuery<KerberosPrincipalHostEntity> query = entityManagerProvider.get().
-        createNamedQuery("KerberosPrincipalHostEntityFindAll", KerberosPrincipalHostEntity.class);
-
-    return query.getResultList();
-  }
-
-
-  /**
-   * Remove KerberosPrincipalHostEntity instances for the specified principal name
-   *
-   * @param principalName a String indicating the name of the principal
-   */
-  @Transactional
-  public void removeByPrincipal(String principalName) {
-    remove(findByPrincipal(principalName));
-  }
-
-  /**
-   * Remove KerberosPrincipalHostEntity instances for the specified host
-   *
-   * @param hostId a Long indicating the id of the host
-   */
-  @Transactional
-  public void removeByHost(Long hostId) {
-    remove(findByHost(hostId));
-  }
-
-  /**
-   * Remove KerberosPrincipalHostEntity instances for the specified host
-   *
-   * @param keytabPath a String indicating the keytab path of principal
-   */
-  @Transactional
-  public void removeByKeytabPath(String keytabPath) {
-    remove(findByKeytabPath(keytabPath));
-  }
-  /**
-   * Remove KerberosPrincipalHostEntity instance for the specified principal and host
-   *
-   * @param principalName a String indicating the name of the principal
-   * @param hostId        a Long indicating the id of the host
-   * @see #remove(org.apache.ambari.server.orm.entities.KerberosPrincipalHostEntity)
-   */
-  @Transactional
-  public void remove(String principalName, Long hostId, String keytabPath) {
-    remove(new KerberosPrincipalHostEntity(principalName, hostId, keytabPath));
-  }
-
-  /**
-   * Tests the existence of a principal on at least one host
-   *
-   * @param principalName a String indicating the name of the principal to test
-   * @return true if a principal is related to one or more hosts; otherwise false
-   */
-  @RequiresSession
-  public boolean exists(String principalName) {
-    List<KerberosPrincipalHostEntity> foundEntries = findByPrincipal(principalName);
-    return (foundEntries != null) && !foundEntries.isEmpty();
-  }
-
-  /**
-   * Tests the existence of a particular principal on a specific host
-   *
-   * @param principalName a String indicating the name of the principal to test
-   * @param hostId      a Long indicating the id of the host to test
-   * @return true if the requested principal exists
-   */
-  @RequiresSession
-  public boolean exists(String principalName, Long hostId, String keytabPath) {
-    return find(principalName, hostId, keytabPath) != null;
-  }
-
-  /**
-   * Removes multiple KerberosPrincipalHostEntity items
-   *
-   * @param entities a collection of KerberosPrincipalHostEntity items to remove
-   */
-  public void remove(List<KerberosPrincipalHostEntity> entities) {
-    if (entities != null) {
-      for (KerberosPrincipalHostEntity entity : entities) {
-        entityManagerProvider.get().remove(entity);
-      }
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupComponentEntityPK.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupComponentEntityPK.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupComponentEntityPK.java
index 0898133..0d99d79 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupComponentEntityPK.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupComponentEntityPK.java
@@ -18,13 +18,15 @@
 
 package org.apache.ambari.server.orm.entities;
 
+import java.io.Serializable;
+
 import javax.persistence.Column;
 import javax.persistence.Id;
 
 /**
  * Composite primary key for HostGroupComponentEntity.
  */
-public class HostGroupComponentEntityPK {
+public class HostGroupComponentEntityPK implements Serializable {
 
   @Id
   @Column(name = "hostgroup_name", nullable = false, insertable = true, updatable = false, length = 100)

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabEntity.java
index a25931b..1757b9f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabEntity.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.orm.entities;
 
+import java.util.ArrayList;
 import java.util.Collection;
 
 import javax.persistence.CascadeType;
@@ -33,54 +34,113 @@ import javax.persistence.Table;
 @Entity
 @Table(name = "kerberos_keytab")
 @NamedQueries({
-    @NamedQuery(name = "KerberosKeytabEntity.findAll", query = "SELECT kk FROM KerberosKeytabEntity kk"),
-    @NamedQuery(name = "KerberosKeytabEntity.findByHost",
-        query = "SELECT kk FROM KerberosKeytabEntity kk JOIN kk.kerberosPrincipalHostEntities he WHERE he.hostId=:hostId")
+  @NamedQuery(name = "KerberosKeytabEntity.findAll", query = "SELECT kk FROM KerberosKeytabEntity kk"),
+  @NamedQuery(
+    name = "KerberosKeytabEntity.findByPrincipalAndHost",
+    query = "SELECT kk FROM KerberosKeytabEntity kk JOIN kk.kerberosKeytabPrincipalEntities kkp WHERE kkp.hostId=:hostId AND kkp.principalName=:principalName"
+  ),
+  @NamedQuery(
+    name = "KerberosKeytabEntity.findByPrincipalAndNullHost",
+    query = "SELECT kk FROM KerberosKeytabEntity kk JOIN kk.kerberosKeytabPrincipalEntities kkp WHERE kkp.hostId IS NULL AND kkp.principalName=:principalName"
+  )
 })
 public class KerberosKeytabEntity {
-    @Id
-    @Column(name = "keytab_path", insertable = true, updatable = false, nullable = false)
-    private String keytabPath = null;
-
-    @OneToMany(mappedBy = "keytabEntity", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
-    private Collection<KerberosPrincipalHostEntity> kerberosPrincipalHostEntities;
-
-    public KerberosKeytabEntity(){
-
-    }
-
-    public KerberosKeytabEntity(String keytabPath){
-        setKeytabPath(keytabPath);
-    }
-
-    public String getKeytabPath() {
-        return keytabPath;
-    }
-
-    public void setKeytabPath(String keytabPath) {
-        this.keytabPath = keytabPath;
+  @Id
+  @Column(name = "keytab_path", updatable = false, nullable = false)
+  private String keytabPath = null;
+
+  @Column(name = "owner_name")
+  private String ownerName;
+  @Column(name = "owner_access")
+  private String ownerAccess;
+  @Column(name = "group_name")
+  private String groupName;
+  @Column(name = "group_access")
+  private String groupAccess;
+  @Column(name = "is_ambari_keytab")
+  private Integer isAmbariServerKeytab = 0;
+  @Column(name = "write_ambari_jaas")
+  private Integer writeAmbariJaasFile = 0;
+
+  @OneToMany(mappedBy = "kerberosKeytabEntity", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
+  private Collection<KerberosKeytabPrincipalEntity> kerberosKeytabPrincipalEntities = new ArrayList<>();
+
+  public KerberosKeytabEntity() {
+
+  }
+
+  public KerberosKeytabEntity(String keytabPath) {
+    setKeytabPath(keytabPath);
+  }
+
+  public String getKeytabPath() {
+    return keytabPath;
+  }
+
+  public void setKeytabPath(String keytabPath) {
+    this.keytabPath = keytabPath;
+  }
+
+  public Collection<KerberosKeytabPrincipalEntity> getKerberosKeytabPrincipalEntities() {
+    return kerberosKeytabPrincipalEntities;
+  }
+
+  public void setKerberosKeytabPrincipalEntities(Collection<KerberosKeytabPrincipalEntity> kerberosKeytabPrincipalEntities) {
+    this.kerberosKeytabPrincipalEntities = kerberosKeytabPrincipalEntities;
+  }
+
+  public String getOwnerName() {
+    return ownerName;
+  }
+
+  public void setOwnerName(String ownerName) {
+    this.ownerName = ownerName;
+  }
+
+  public String getOwnerAccess() {
+    return ownerAccess;
+  }
+
+  public void setOwnerAccess(String ownerAccess) {
+    this.ownerAccess = ownerAccess;
+  }
+
+  public String getGroupName() {
+    return groupName;
+  }
+
+  public void setGroupName(String groupName) {
+    this.groupName = groupName;
+  }
+
+  public String getGroupAccess() {
+    return groupAccess;
+  }
+
+  public void setGroupAccess(String groupAccess) {
+    this.groupAccess = groupAccess;
+  }
+
+  public boolean isAmbariServerKeytab() {
+    return isAmbariServerKeytab == 1;
+  }
+
+  public void setAmbariServerKeytab(boolean ambariServerKeytab) {
+    this.isAmbariServerKeytab = (ambariServerKeytab) ? 1 : 0;
+  }
+
+  public boolean isWriteAmbariJaasFile() {
+    return writeAmbariJaasFile == 1;
+  }
+
+  public void setWriteAmbariJaasFile(boolean writeAmbariJaasFile) {
+    this.writeAmbariJaasFile = (writeAmbariJaasFile) ? 1 : 0;
+  }
+
+  public void addKerberosKeytabPrincipal(KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity) {
+    if (!kerberosKeytabPrincipalEntities.contains(kerberosKeytabPrincipalEntity)) {
+      kerberosKeytabPrincipalEntities.add(kerberosKeytabPrincipalEntity);
     }
+  }
 
-    public Collection<KerberosPrincipalHostEntity> getKerberosPrincipalHostEntities() {
-        return kerberosPrincipalHostEntities;
-    }
-
-    public void setKerberosPrincipalHostEntities(Collection<KerberosPrincipalHostEntity> kerberosPrincipalHostEntities) {
-        this.kerberosPrincipalHostEntities = kerberosPrincipalHostEntities;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        KerberosKeytabEntity that = (KerberosKeytabEntity) o;
-
-        return keytabPath.equals(that.keytabPath);
-    }
-
-    @Override
-    public int hashCode() {
-        return keytabPath.hashCode();
-    }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabPrincipalEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabPrincipalEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabPrincipalEntity.java
new file mode 100644
index 0000000..9a55587
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabPrincipalEntity.java
@@ -0,0 +1,236 @@
+/*
+ * 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.orm.entities;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * Represents entity to hold principal for keytab.
+ * Ideally this entity must have natural PK based on ({@link #keytabPath}, {@link #principalName}, {@link #hostId}),
+ * but {@link #hostId} in some cases can be null, and also this entity must be used in service mappings(this can
+ * cause dup of {@link #keytabPath}, {@link #principalName} fields in related entities), so we have surrogate {@link #kkpId}
+ * id and unique constraint on ({@link #keytabPath}, {@link #principalName}, {@link #hostId}).
+ */
+@Entity
+@Table(name = "kerberos_keytab_principal")
+@TableGenerator(name = "kkp_id_generator",
+  table = "ambari_sequences",
+  pkColumnName = "sequence_name",
+  valueColumnName = "sequence_value",
+  pkColumnValue = "kkp_id_seq"
+)
+@NamedQueries({
+  @NamedQuery(
+    name = "KerberosKeytabPrincipalEntity.findAll",
+    query = "SELECT kkpe FROM KerberosKeytabPrincipalEntity kkpe"
+  ),
+  @NamedQuery(
+    name = "KerberosKeytabPrincipalEntity.findByHostAndKeytab",
+    query = "SELECT kkpe FROM KerberosKeytabPrincipalEntity kkpe WHERE kkpe.hostId=:hostId AND kkpe.keytabPath=:keytabPath"
+  ),
+  @NamedQuery(
+    name = "KerberosKeytabPrincipalEntity.findByPrincipal",
+    query = "SELECT kkpe FROM KerberosKeytabPrincipalEntity kkpe WHERE kkpe.principalName=:principalName"
+  ),
+  @NamedQuery(
+    name = "KerberosKeytabPrincipalEntity.findByHost",
+    query = "SELECT kkpe FROM KerberosKeytabPrincipalEntity kkpe WHERE kkpe.hostId=:hostId"
+  ),
+  @NamedQuery(
+    name = "KerberosKeytabPrincipalEntity.findByHostKeytabAndPrincipal",
+    query = "SELECT kkpe FROM KerberosKeytabPrincipalEntity kkpe WHERE kkpe.hostId=:hostId AND kkpe.keytabPath=:keytabPath AND kkpe.principalName=:principalName"
+  ),
+  @NamedQuery(
+    name = "KerberosKeytabPrincipalEntity.findByKeytabAndPrincipalNullHost",
+    query = "SELECT kkpe FROM KerberosKeytabPrincipalEntity kkpe WHERE kkpe.principalName=:principalName AND kkpe.keytabPath=:keytabPath AND kkpe.hostId IS NULL"
+  )
+})
+public class KerberosKeytabPrincipalEntity {
+  @Id
+  @GeneratedValue(strategy = GenerationType.TABLE, generator = "kkp_id_generator")
+  @Column(name = "kkp_id")
+  private Long kkpId;
+
+  @Column(name = "keytab_path", updatable = false, nullable = false)
+  private String keytabPath;
+
+  @Column(name = "principal_name", updatable = false, nullable = false)
+  private String principalName;
+
+  @Column(name = "host_id")
+  private Long hostId;
+
+  @Column(name = "is_distributed", nullable = false)
+  private Integer isDistributed = 0;
+
+  @ManyToOne
+  @JoinColumn(name = "keytab_path", referencedColumnName = "keytab_path", updatable = false, nullable = false, insertable = false)
+  private KerberosKeytabEntity kerberosKeytabEntity;
+
+  @ManyToOne
+  @JoinColumn(name = "host_id", referencedColumnName = "host_id", updatable = false, insertable = false)
+  private HostEntity hostEntity;
+
+  @ManyToOne
+  @JoinColumn(name = "principal_name", referencedColumnName = "principal_name", updatable = false, nullable = false, insertable = false)
+  private KerberosPrincipalEntity principalEntity;
+
+  @OneToMany(cascade = CascadeType.ALL, mappedBy = "kerberosKeytabPrincipalEntity")
+  private List<KerberosKeytabServiceMappingEntity> serviceMapping = new ArrayList<>();
+
+  public KerberosKeytabPrincipalEntity() {
+
+  }
+
+  public KerberosKeytabPrincipalEntity(
+    KerberosKeytabEntity kerberosKeytabEntity,
+    HostEntity hostEntity,
+    KerberosPrincipalEntity principalEntity
+  ) {
+    setKerberosKeytabEntity(kerberosKeytabEntity);
+    setHostEntity(hostEntity);
+    setPrincipalEntity(principalEntity);
+  }
+
+  public Long getKkpId() {
+    return kkpId;
+  }
+
+  public void setKkpId(Long kkpId) {
+    this.kkpId = kkpId;
+  }
+
+  public Boolean isDistributed() {
+    return isDistributed == 1;
+  }
+
+  public void setDistributed(Boolean isDistributed) {
+    this.isDistributed = isDistributed ? 1 : 0;
+  }
+
+  public KerberosKeytabEntity getKerberosKeytabEntity() {
+    return kerberosKeytabEntity;
+  }
+
+  public void setKerberosKeytabEntity(KerberosKeytabEntity kke) {
+    this.kerberosKeytabEntity = kke;
+    if (kke != null) {
+      keytabPath = kke.getKeytabPath();
+    }
+  }
+
+  public HostEntity getHostEntity() {
+    return hostEntity;
+  }
+
+  public void setHostEntity(HostEntity hostEntity) {
+    this.hostEntity = hostEntity;
+    if (hostEntity != null) {
+      hostId = hostEntity.getHostId();
+    }
+  }
+
+  public KerberosPrincipalEntity getPrincipalEntity() {
+    return principalEntity;
+  }
+
+  public void setPrincipalEntity(KerberosPrincipalEntity principalEntity) {
+    this.principalEntity = principalEntity;
+    if (principalEntity != null) {
+      principalName = principalEntity.getPrincipalName();
+    }
+  }
+
+  public String getKeytabPath() {
+    return kerberosKeytabEntity != null ? kerberosKeytabEntity.getKeytabPath() : null;
+  }
+
+
+  public String getPrincipalName() {
+    return principalEntity != null ? principalEntity.getPrincipalName() : null;
+  }
+
+  public Long getHostId() {
+    return hostEntity != null ? hostEntity.getHostId() : null;
+  }
+
+  public String getHostName() {
+    return hostEntity != null ? hostEntity.getHostName() : null;
+  }
+
+  public boolean putServiceMapping(String service, String component) {
+    if (containsMapping(service, component)) {
+      return false;
+    } else {
+      serviceMapping.add(new KerberosKeytabServiceMappingEntity(this, service, component));
+      return true;
+    }
+  }
+
+  public Multimap<String, String> getServiceMappingAsMultimap() {
+    Multimap<String, String> result = ArrayListMultimap.create();
+    for (KerberosKeytabServiceMappingEntity mappingEntity : serviceMapping) {
+      result.put(mappingEntity.getServiceName(), mappingEntity.getComponentName());
+    }
+    return result;
+  }
+
+  public boolean containsMapping(String serviceName, String componentName) {
+    for (KerberosKeytabServiceMappingEntity mappingEntity : serviceMapping) {
+      if (Objects.equal(mappingEntity.getComponentName(), componentName)
+        && Objects.equal(mappingEntity.getServiceName(), serviceName)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    KerberosKeytabPrincipalEntity that = (KerberosKeytabPrincipalEntity) o;
+    return Objects.equal(keytabPath, that.keytabPath) &&
+      Objects.equal(principalName, that.principalName) &&
+      Objects.equal(hostId, that.hostId);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(keytabPath, principalName, hostId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabServiceMappingEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabServiceMappingEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabServiceMappingEntity.java
new file mode 100644
index 0000000..f3ad7b7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosKeytabServiceMappingEntity.java
@@ -0,0 +1,88 @@
+/*
+ * 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.orm.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "kkp_mapping_service")
+public class KerberosKeytabServiceMappingEntity {
+  @Id
+  @Column(name = "kkp_id", nullable = false, insertable = false, updatable = false)
+  private  Long kerberosKeytabPrincipalId;
+
+  @Id
+  @Column(name = "service_name", nullable = false)
+  private  String serviceName;
+
+  @Id
+  @Column(name = "component_name", nullable = false)
+  private  String componentName;
+
+  @ManyToOne
+  @JoinColumn(name = "kkp_id")
+  private KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity;
+
+  public KerberosKeytabServiceMappingEntity() {
+  }
+
+  public KerberosKeytabServiceMappingEntity(KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity, String serviceName, String componentName) {
+    this.kerberosKeytabPrincipalId = kerberosKeytabPrincipalEntity.getKkpId();
+    this.kerberosKeytabPrincipalEntity = kerberosKeytabPrincipalEntity;
+    this.serviceName = serviceName;
+    this.componentName = componentName;
+  }
+
+  public Long getKerberosKeytabPrincipalId() {
+    return kerberosKeytabPrincipalId;
+  }
+
+  public void setKerberosKeytabPrincipalId(Long kerberosKeytabPrincipalId) {
+    this.kerberosKeytabPrincipalId = kerberosKeytabPrincipalId;
+  }
+
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public void setServiceName(String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  public String getComponentName() {
+    return componentName;
+  }
+
+  public void setComponentName(String componentName) {
+    this.componentName = componentName;
+  }
+
+  public KerberosKeytabPrincipalEntity getKerberosKeytabPrincipalEntity() {
+    return kerberosKeytabPrincipalEntity;
+  }
+
+  public void setKerberosKeytabPrincipalEntity(KerberosKeytabPrincipalEntity kerberosKeytabPrincipalEntity) {
+    this.kerberosKeytabPrincipalEntity = kerberosKeytabPrincipalEntity;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalEntity.java
index 5dd54ca..5f7cc56 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalEntity.java
@@ -18,16 +18,11 @@
 
 package org.apache.ambari.server.orm.entities;
 
-import java.util.Collection;
-
-import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
-import javax.persistence.FetchType;
 import javax.persistence.Id;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
-import javax.persistence.OneToMany;
 import javax.persistence.Table;
 
 /**
@@ -54,9 +49,6 @@ public class KerberosPrincipalEntity {
   @Column(name = "cached_keytab_path", insertable = true, updatable = true, nullable = true)
   private String cachedKeytabPath = null;
 
-  @OneToMany(mappedBy = "principalEntity", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
-  private Collection<KerberosPrincipalHostEntity> kerberosPrincipalHostEntities;
-
   /**
    * Constructs an empty KerberosPrincipalEntity
    */
@@ -130,21 +122,4 @@ public class KerberosPrincipalEntity {
     this.cachedKeytabPath = cachedKeytabPath;
   }
 
-  /**
-   * Gets the list of related KerberosPrincipalHostEntities
-   *
-   * @return a List of related KerberosPrincipalHostEntities or null if none exist
-   */
-  public Collection<KerberosPrincipalHostEntity> getKerberosPrincipalHostEntities() {
-    return kerberosPrincipalHostEntities;
-  }
-
-  /**
-   * Sets the list of related KerberosPrincipalHostEntities
-   *
-   * @param kerberosPrincipalHostEntities a List of related KerberosPrincipalHostEntities or null if none exist
-   */
-  public void setKerberosPrincipalHostEntities(Collection<KerberosPrincipalHostEntity> kerberosPrincipalHostEntities) {
-    this.kerberosPrincipalHostEntities = kerberosPrincipalHostEntities;
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntity.java
deleted file mode 100644
index d4e80c6..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntity.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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.orm.entities;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.IdClass;
-import javax.persistence.JoinColumn;
-import javax.persistence.JoinColumns;
-import javax.persistence.ManyToOne;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-
-/**
- * Entity representing a KerberosPrincipal stored on a host.
- */
-@Entity
-@IdClass(KerberosPrincipalHostEntityPK.class)
-@Table(name = "kerberos_principal_host")
-@NamedQueries({
-    @NamedQuery(name = "KerberosPrincipalHostEntityFindAll",
-        query = "SELECT kph FROM KerberosPrincipalHostEntity kph"),
-    @NamedQuery(name = "KerberosPrincipalHostEntityFindByPrincipal",
-        query = "SELECT kph FROM KerberosPrincipalHostEntity kph WHERE kph.principalName=:principalName"),
-    @NamedQuery(name = "KerberosPrincipalHostEntityFindByHost",
-        query = "SELECT kph FROM KerberosPrincipalHostEntity kph WHERE kph.hostId=:hostId"),
-    @NamedQuery(name = "KerberosPrincipalHostEntityFindByKeytabPath",
-    query = "SELECT kph FROM KerberosPrincipalHostEntity kph WHERE kph.keytabPath=:keytabPath"),
-})
-public class KerberosPrincipalHostEntity {
-
-  @Id
-  @Column(name = "principal_name", insertable = true, updatable = false, nullable = false)
-  private String principalName;
-
-  @Id
-  @Column(name = "host_id", insertable = true, updatable = false, nullable = false)
-  private Long hostId;
-
-  @Id
-  @Column(name = "keytab_path", updatable = false, nullable = false)
-  private String keytabPath;
-
-  @ManyToOne
-  @JoinColumn(name = "principal_name", referencedColumnName = "principal_name", nullable = false, insertable = false, updatable = false)
-  private KerberosPrincipalEntity principalEntity;
-
-  @ManyToOne
-  @JoinColumn(name = "host_id", referencedColumnName = "host_id", nullable = false, insertable = false, updatable = false)
-  private HostEntity hostEntity;
-
-  @ManyToOne
-  @JoinColumns({
-          @JoinColumn(name = "keytab_path", referencedColumnName = "keytab_path", nullable = false, insertable = false, updatable = false)
-  })
-  private KerberosKeytabEntity keytabEntity;
-
-  @Column(name = "is_distributed", insertable = true, updatable = true, nullable = false)
-  private Integer isDistributed = 0;
-  /**
-   * Constucts an empty KerberosPrincipalHostEntity
-   */
-  public KerberosPrincipalHostEntity() {
-  }
-
-  /**
-   * Constructs a new KerberosPrincipalHostEntity
-   *
-   * @param principalName a String indicating this KerberosPrincipalHostEntity's principal name
-   * @param hostId a Long indicating the KerberosPrincipalHostEntity's host id
-   */
-  public KerberosPrincipalHostEntity(String principalName, Long hostId, String keytabPath) {
-    setPrincipalName(principalName);
-    setHostId(hostId);
-    setKeytabPath(keytabPath);
-  }
-
-  /**
-   * Constructs a new KerberosPrincipalHostEntity
-   *
-   * @param principalName a String indicating this KerberosPrincipalHostEntity's principal name
-   * @param hostId a Long indicating the KerberosPrincipalHostEntity's host id
-   */
-  public KerberosPrincipalHostEntity(String principalName, Long hostId, String keytabPath, boolean isDistributed) {
-    setPrincipalName(principalName);
-    setHostId(hostId);
-    setKeytabPath(keytabPath);
-    setDistributed(isDistributed);
-  }
-
-  /**
-   * Gets the principal name for this KerberosPrincipalHostEntity
-   *
-   * @return a String indicating this KerberosPrincipalHostEntity's principal name
-   */
-  public String getPrincipalName() {
-    return principalName;
-  }
-
-  /**
-   * Sets the principal name for this KerberosPrincipalHostEntity
-   *
-   * @param principalName a String indicating this KerberosPrincipalHostEntity's principal name
-   */
-  public void setPrincipalName(String principalName) {
-    this.principalName = principalName;
-  }
-
-  /**
-   * Gets the host name for this KerberosHostHostEntity
-   *
-   * @return a String indicating this KerberosHostHostEntity's host name
-   */
-  public String getHostName() {
-    return hostEntity != null ? hostEntity.getHostName() : null;
-  }
-
-  /**
-   * Gets the host id for this KerberosHostHostEntity
-   *
-   * @return a Long indicating this KerberosHostHostEntity's host id
-   */
-  public Long getHostId() {
-    return hostId;
-  }
-
-  /**
-   * Sets the host id for this KerberosHostHostEntity
-   *
-   * @param hostId a Long indicating this KerberosHostHostEntity's host id
-   */
-  public void setHostId(Long hostId) {
-    this.hostId = hostId;
-  }
-
-  /**
-   * Gets the related HostEntity
-   *
-   * @return the related HostEntity
-   */
-  public HostEntity getHostEntity() {
-    return hostEntity;
-  }
-
-  /**
-   * Sets the related HostEntity
-   *
-   * @param hostEntity the related HostEntity
-   */
-  public void setHostEntity(HostEntity hostEntity) {
-    this.hostEntity = hostEntity;
-  }
-
-  /**
-   * Gets the related KerberosPrincipalEntity
-   *
-   * @return the related KerberosPrincipalEntity
-   */
-  public KerberosPrincipalEntity getPrincipalEntity() {
-    return principalEntity;
-  }
-
-  /**
-   * Sets the related KerberosPrincipalEntity
-   *
-   * @param principalEntity the related KerberosPrincipalEntity
-   */
-  public void setPrincipalEntity(KerberosPrincipalEntity principalEntity) {
-    this.principalEntity = principalEntity;
-  }
-
-  public String getKeytabPath() {
-    return keytabPath;
-  }
-
-  public void setKeytabPath(String keytabPath) {
-    this.keytabPath = keytabPath;
-  }
-
-  public KerberosKeytabEntity getKeytabEntity() {
-    return keytabEntity;
-  }
-
-  public void setKeytabEntity(KerberosKeytabEntity keytabEntity) {
-    this.keytabEntity = keytabEntity;
-  }
-
-  public Boolean getDistributed() {
-    return isDistributed == 1;
-  }
-
-  public void setDistributed(Boolean isDistributed) {
-    this.isDistributed = (isDistributed) ? 1 : 0;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntityPK.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntityPK.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntityPK.java
deleted file mode 100644
index 7e57e4a..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/KerberosPrincipalHostEntityPK.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.orm.entities;
-
-import java.io.Serializable;
-
-import javax.persistence.Column;
-import javax.persistence.Id;
-
-/**
- * Composite primary key for KerberosPrincipalHostEntity.
- */
-public class KerberosPrincipalHostEntityPK implements Serializable{
-
-  @Id
-  @Column(name = "principal_name", insertable = false, updatable = false, nullable = false)
-  private String principalName = null;
-
-  @Id
-  @Column(name = "host_id", insertable = false, updatable = false, nullable = false)
-  private Long hostId = null;
-
-  @Id
-  @Column(name = "keytab_path", insertable = false, updatable = false, nullable = false)
-  private String keytabPath = null;
-
-  public KerberosPrincipalHostEntityPK() {
-  }
-
-  public KerberosPrincipalHostEntityPK(String principalName, Long hostId, String keytabPath) {
-    setPrincipalName(principalName);
-    setHostId(hostId);
-    setKeytabPath(keytabPath);
-  }
-
-  /**
-   * Get the name of the associated principal.
-   *
-   * @return principal name
-   */
-  public String getPrincipalName() {
-    return principalName;
-  }
-
-  /**
-   * Set the name of the associated principal.
-   *
-   * @param principalName principal name
-   */
-  public void setPrincipalName(String principalName) {
-    this.principalName = principalName;
-  }
-
-  /**
-   * Get the host id.
-   *
-   * @return host id
-   */
-  public Long getHostId() {
-    return hostId;
-  }
-
-  /**
-   * Set the configuration type.
-   *
-   * @param hostId host id
-   */
-  public void setHostId(Long hostId) {
-    this.hostId = hostId;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-
-    KerberosPrincipalHostEntityPK that = (KerberosPrincipalHostEntityPK) o;
-
-    return this.principalName.equals(that.principalName) &&
-        this.hostId.equals(that.hostId) && this.keytabPath.equals(that.keytabPath);
-  }
-
-  @Override
-  public int hashCode() {
-    return 31 * principalName.hashCode() + hostId.hashCode() + keytabPath.hashCode();
-  }
-
-  public String getKeytabPath() {
-    return keytabPath;
-  }
-
-  public void setKeytabPath(String keytabPath) {
-    this.keytabPath = keytabPath;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
index b8affb4..cffd8e1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
@@ -20,7 +20,6 @@ package org.apache.ambari.server.serveraction.kerberos;
 
 import java.io.File;
 import java.io.IOException;
-import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -36,6 +35,7 @@ import org.apache.ambari.server.controller.KerberosHelper;
 import org.apache.ambari.server.controller.RootComponent;
 import org.apache.ambari.server.controller.RootService;
 import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab;
+import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
@@ -47,7 +47,6 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.reflect.TypeToken;
 import com.google.inject.Inject;
 
 public abstract class AbstractPrepareKerberosServerAction extends KerberosServerAction {
@@ -66,7 +65,7 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
   private KerberosConfigDataFileWriterFactory kerberosConfigDataFileWriterFactory;
 
   @Override
-  protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException {
+  protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException {
     throw new UnsupportedOperationException();
   }
 
@@ -211,7 +210,7 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
 
         // create database records for keytabs that must be presented on cluster
         for (ResolvedKerberosKeytab keytab : resolvedKeytabs.values()) {
-          kerberosHelper.processResolvedKeytab(keytab);
+          kerberosHelper.createResolvedKeytab(keytab);
         }
       } catch (IOException e) {
         String message = String.format("Failed to write index file - %s", identityDataFile.getAbsolutePath());
@@ -235,30 +234,6 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
     }
   }
 
-  protected Map<String, ? extends Collection<String>> getServiceComponentFilter() {
-    String serializedValue = getCommandParameterValue(SERVICE_COMPONENT_FILTER);
-
-    if (serializedValue != null) {
-      Type type = new TypeToken<Map<String, ? extends Collection<String>>>() {
-      }.getType();
-      return StageUtils.getGson().fromJson(serializedValue, type);
-    } else {
-      return null;
-    }
-  }
-
-  protected Collection<String> getIdentityFilter() {
-    String serializedValue = getCommandParameterValue(IDENTITY_FILTER);
-
-    if (serializedValue != null) {
-      Type type = new TypeToken<Collection<String>>() {
-      }.getType();
-      return StageUtils.getGson().fromJson(serializedValue, type);
-    } else {
-      return null;
-    }
-  }
-
   private Map<String, Set<String>> gatherPropertiesToIgnore(List<KerberosIdentityDescriptor> identities,
                                                             Map<String, Set<String>> propertiesToIgnore) {
     Map<String, Map<String, String>> identityConfigurations = kerberosHelper.getIdentityConfigurations(identities);

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CleanupServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CleanupServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CleanupServerAction.java
index 002076d..1b7d128 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CleanupServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CleanupServerAction.java
@@ -34,6 +34,7 @@ import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.orm.dao.KerberosKeytabDAO;
 import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
+import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.SecurityType;
 import org.slf4j.Logger;
@@ -58,8 +59,7 @@ public class CleanupServerAction extends KerberosServerAction {
    * <p/>
    * This method is not used since the {@link #processIdentities(java.util.Map)} is not invoked
    *
-   * @param identityRecord           a Map containing the data for the current identity record
-   * @param evaluatedPrincipal       a String indicating the relevant principal
+   * @param resolvedPrincipal        a ResolvedKerberosPrincipal object to process
    * @param operationHandler         a KerberosOperationHandler used to perform Kerberos-related
    *                                 tasks for specific Kerberos implementations
    *                                 (MIT, Active Directory, etc...)
@@ -70,7 +70,7 @@ public class CleanupServerAction extends KerberosServerAction {
    * @throws AmbariException if an error occurs while processing the identity record
    */
   @Override
-  protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal,
+  protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal,
                                           KerberosOperationHandler operationHandler,
                                           Map<String, String> kerberosConfiguration,
                                           Map<String, Object> requestSharedDataContext)

http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
index 3384152..f6fdecd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
@@ -24,13 +24,20 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.controller.RootService;
 import org.apache.ambari.server.controller.utilities.KerberosChecker;
+import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.KerberosKeytabDAO;
-import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
-import org.apache.ambari.server.orm.entities.KerberosPrincipalHostEntity;
+import org.apache.ambari.server.orm.dao.KerberosKeytabPrincipalDAO;
+import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
+import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.KerberosKeytabEntity;
+import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity;
+import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity;
 import org.apache.ambari.server.serveraction.ActionLog;
+import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab;
+import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal;
 import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.codec.digest.DigestUtils;
@@ -47,7 +54,7 @@ import com.google.inject.Inject;
  * This class mainly relies on the KerberosServerAction to iterate through metadata identifying
  * the Kerberos keytab files that need to be created. For each identity in the metadata, this
  * implementation's
- * {@link KerberosServerAction#processIdentity(Map, String, KerberosOperationHandler, Map, Map)}
+ * {@link KerberosServerAction#processIdentity(ResolvedKerberosPrincipal, KerberosOperationHandler, Map, Map)}
  * is invoked attempting the creation of the relevant keytab file.
  */
 public class ConfigureAmbariIdentitiesServerAction extends KerberosServerAction {
@@ -59,10 +66,16 @@ public class ConfigureAmbariIdentitiesServerAction extends KerberosServerAction
   private final static Logger LOG = LoggerFactory.getLogger(ConfigureAmbariIdentitiesServerAction.class);
 
   @Inject
-  private KerberosPrincipalHostDAO kerberosPrincipalHostDAO;
+  private KerberosKeytabDAO kerberosKeytabDAO;
 
   @Inject
-  private KerberosKeytabDAO kerberosKeytabDAO;
+  private KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO;
+
+  @Inject
+  private KerberosPrincipalDAO kerberosPrincipalDAO;
+
+  @Inject
+  private HostDAO hostDAO;
 
   /**
    * Called to execute this action.  Upon invocation, calls
@@ -90,8 +103,7 @@ public class ConfigureAmbariIdentitiesServerAction extends KerberosServerAction
    * It is expected that the {@link CreatePrincipalsServerAction}
    * (or similar) and {@link CreateKeytabFilesServerAction} has executed before this action.
    *
-   * @param identityRecord           a Map containing the data for the current identity record
-   * @param evaluatedPrincipal       a String indicating the relevant principal
+   * @param resolvedPrincipal        a ResolvedKerberosPrincipal object to process
    * @param operationHandler         a KerberosOperationHandler used to perform Kerberos-related
    *                                 tasks for specific Kerberos implementations
    *                                 (MIT, Active Directory, etc...)
@@ -102,45 +114,39 @@ public class ConfigureAmbariIdentitiesServerAction extends KerberosServerAction
    * @throws AmbariException if an error occurs while processing the identity record
    */
   @Override
-  protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal,
+  protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal,
                                           KerberosOperationHandler operationHandler,
                                           Map<String, String> kerberosConfiguration,
                                           Map<String, Object> requestSharedDataContext)
       throws AmbariException {
     CommandReport commandReport = null;
 
-    if (identityRecord != null) {
-      String message;
+    if (resolvedPrincipal != null) {
       String dataDirectory = getDataDirectoryPath();
-
-      if (dataDirectory == null) {
-        message = "The data directory has not been set. Generated keytab files can not be stored.";
-        LOG.error(message);
-        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
-      } else {
-
-        String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
-        String serviceName = identityRecord.get(KerberosIdentityDataFileReader.SERVICE);
-        if (hostName != null && serviceName.equals("AMBARI")) {
-          String destKeytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
+      String hostName = resolvedPrincipal.getHostName();
+      for (Map.Entry<String, String> serviceMappingEntry : resolvedPrincipal.getServiceMapping().entries()){
+        String serviceName = serviceMappingEntry.getKey();
+        // distribute ambari keytabs only if host id is null, otherwise they will
+        // be distributed by usual process using ambari-agent.
+        // TODO check if changes needed for multiple principals in one keytab
+        if (resolvedPrincipal.getHostId() == null && hostName != null && serviceName.equals(RootService.AMBARI.name())) {
+          ResolvedKerberosKeytab keytab = resolvedPrincipal.getResolvedKerberosKeytab();
+          String destKeytabFilePath = resolvedPrincipal.getResolvedKerberosKeytab().getFile();
+          hostName = StageUtils.getHostName();
           File hostDirectory = new File(dataDirectory, hostName);
-          File srcKeytabFile = new File(hostDirectory, DigestUtils.sha1Hex(destKeytabFilePath));
+          File srcKeytabFile = new File(hostDirectory, DigestUtils.sha256Hex(destKeytabFilePath));
 
           if (srcKeytabFile.exists()) {
-            String ownerAccess = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS);
-            boolean ownerWritable = "w".equalsIgnoreCase(ownerAccess) || "rw".equalsIgnoreCase(ownerAccess);
-            boolean ownerReadable = "r".equalsIgnoreCase(ownerAccess) || "rw".equalsIgnoreCase(ownerAccess);
-            String groupAccess = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS);
-            boolean groupWritable = "w".equalsIgnoreCase(groupAccess) || "rw".equalsIgnoreCase(groupAccess);
-            boolean groupReadable = "r".equalsIgnoreCase(groupAccess) || "rw".equalsIgnoreCase(groupAccess);
-
-            installAmbariServerIdentity(evaluatedPrincipal, srcKeytabFile.getAbsolutePath(), destKeytabFilePath,
-                identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_NAME), ownerReadable, ownerWritable,
-                identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_GROUP_NAME), groupReadable, groupWritable, actionLog);
-
-            if ("AMBARI_SERVER_SELF".equals(identityRecord.get(KerberosIdentityDataFileReader.COMPONENT))) {
+            String ownerAccess = keytab.getOwnerAccess();
+            String groupAccess = keytab.getGroupAccess();
+
+            installAmbariServerIdentity(resolvedPrincipal, srcKeytabFile.getAbsolutePath(), destKeytabFilePath,
+              keytab.getOwnerName(), ownerAccess,
+              keytab.getGroupName(), groupAccess, actionLog);
+
+            if (serviceMappingEntry.getValue().contains("AMBARI_SERVER_SELF")) {
               // Create/update the JAASFile...
-              configureJAAS(evaluatedPrincipal, destKeytabFilePath, actionLog);
+              configureJAAS(resolvedPrincipal.getPrincipal(), destKeytabFilePath, actionLog);
             }
           }
         }
@@ -158,53 +164,56 @@ public class ConfigureAmbariIdentitiesServerAction extends KerberosServerAction
    * @param srcKeytabFilePath  the source location of the ambari server keytab file
    * @param destKeytabFilePath the destination location of the ambari server keytab file
    * @param ownerName          the username for the owner of the generated keytab file
-   * @param ownerReadable      true if the owner should be able to read this file; otherwise false
-   * @param ownerWritable      true if the owner should be able to write to this file; otherwise false
+   * @param ownerAccess        the user file access, "", "r" or "rw"
    * @param groupName          the name of the group for the generated keytab file
-   * @param groupReadable      true if the group should be able to read this file; otherwise false
-   * @param groupWritable      true if the group should be able to write to this file; otherwise false
+   * @param groupAccess        the group file access, "", "r" or "rw"
    * @param actionLog          the logger
    * @return true if success; false otherwise
    * @throws AmbariException
    */
-  public boolean installAmbariServerIdentity(String principal,
+  public boolean installAmbariServerIdentity(ResolvedKerberosPrincipal principal,
                                              String srcKeytabFilePath,
                                              String destKeytabFilePath,
-                                             String ownerName, boolean ownerReadable, boolean ownerWritable,
-                                             String groupName, boolean groupReadable, boolean groupWritable,
+                                             String ownerName, String ownerAccess,
+                                             String groupName, String groupAccess,
                                              ActionLog actionLog) throws AmbariException {
 
     try {
       // Copy the keytab file into place (creating the parent directory, if necessary...
+      boolean ownerWritable = "w".equalsIgnoreCase(ownerAccess) || "rw".equalsIgnoreCase(ownerAccess);
+      boolean ownerReadable = "r".equalsIgnoreCase(ownerAccess) || "rw".equalsIgnoreCase(ownerAccess);
+      boolean groupWritable = "w".equalsIgnoreCase(groupAccess) || "rw".equalsIgnoreCase(groupAccess);
+      boolean groupReadable = "r".equalsIgnoreCase(groupAccess) || "rw".equalsIgnoreCase(groupAccess);
+
       copyFile(srcKeytabFilePath, destKeytabFilePath);
       setFileACL(destKeytabFilePath,
           ownerName, ownerReadable, ownerWritable,
           groupName, groupReadable, groupWritable);
 
-      String ambariServerHostName = StageUtils.getHostName();
       Long ambariServerHostID = ambariServerHostID();
-      if (ambariServerHostID == null) {
-        String message = String.format("Failed to add the kerberos_principal_host record for %s on " +
-                "the Ambari server host since the host id for Ambari server host, %s, was not found." +
-                "  This is not an error if an Ambari agent is not installed on the Ambari server host.",
-            principal, ambariServerHostName);
-        LOG.warn(message);
-        if (actionLog != null) {
-          actionLog.writeStdErr(message);
-        }
-      } else if (!kerberosPrincipalHostDAO.exists(principal, ambariServerHostID, destKeytabFilePath)) {
-        if (!kerberosKeytabDAO.exists(destKeytabFilePath)) {
-          kerberosKeytabDAO.create(destKeytabFilePath);
-        }
-        if(!kerberosPrincipalHostDAO.exists(principal, ambariServerHostID, destKeytabFilePath)) {
-          kerberosPrincipalHostDAO.create(
-              new KerberosPrincipalHostEntity(principal, ambariServerHostID, destKeytabFilePath, true)
-          );
-        } else {
-          KerberosPrincipalHostEntity kphe = kerberosPrincipalHostDAO.find(principal, ambariServerHostID, destKeytabFilePath);
-          kphe.setDistributed(true);
-          kerberosPrincipalHostDAO.merge(kphe);
-        }
+      HostEntity hostEntity = null;
+      if (ambariServerHostID != null) {
+        hostEntity = hostDAO.findById(ambariServerHostID);
+      }
+
+      KerberosKeytabEntity kke = kerberosKeytabDAO.find(destKeytabFilePath);
+      if (!kerberosKeytabDAO.exists(destKeytabFilePath)) {
+        kke = new KerberosKeytabEntity(destKeytabFilePath);
+        kke.setOwnerName(ownerName);
+        kke.setOwnerAccess(ownerAccess);
+        kke.setGroupName(groupName);
+        kke.setGroupAccess(groupAccess);
+        kerberosKeytabDAO.create(kke);
+      }
+
+      for(Map.Entry<String, String> mapping : principal.getServiceMapping().entries()) {
+        String serviceName = mapping.getKey();
+        String componentName = mapping.getValue();
+        KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(principal.getPrincipal());
+        KerberosKeytabPrincipalEntity entity = kerberosKeytabPrincipalDAO.findOrCreate(kke, hostEntity, principalEntity);
+        entity.setDistributed(true);
+        entity.putServiceMapping(serviceName, componentName);
+        kerberosKeytabPrincipalDAO.merge(entity);
       }
 
       if (actionLog != null) {