@Override
  public int addIdentities(KerberosIdentityDataFileWriter kerberosIdentityDataFileWriter,
                           Collection<KerberosIdentityDescriptor> identities,
                           Collection<String> identityFilter, String hostname, Long hostId, String serviceName,
                           String componentName, Map<String, Map<String, String>> kerberosConfigurations,
                           Map<String, Map<String, String>> configurations,
                           Map<String, ResolvedKerberosKeytab> resolvedKeytabs, String realm)
    throws IOException {
    int identitiesAdded = 0;

    if (identities != null) {
      for (KerberosIdentityDescriptor identity : identities) {
        // If there is no filter or the filter contains the current identity's path...
        if ((identityFilter == null) || identityFilter.contains(identity.getPath())) {

          KerberosPrincipalDescriptor principalDescriptor = identity.getPrincipalDescriptor();
          String principal = null;
          String principalType = null;
          String principalConfiguration = null;

          if (principalDescriptor != null) {
            principal = variableReplacementHelper.replaceVariables(principalDescriptor.getValue(), configurations);
            principalType = KerberosPrincipalType.translate(principalDescriptor.getType());
            principalConfiguration = variableReplacementHelper.replaceVariables(principalDescriptor.getConfiguration(), configurations);
          }

          if (principal != null) {
            KerberosKeytabDescriptor keytabDescriptor = identity.getKeytabDescriptor();
            String keytabFilePath = null;
            String keytabFileOwnerName = null;
            String keytabFileOwnerAccess = null;
            String keytabFileGroupName = null;
            String keytabFileGroupAccess = null;
            String keytabFileConfiguration = null;

            if (keytabDescriptor != null) {
              keytabFilePath = variableReplacementHelper.replaceVariables(keytabDescriptor.getFile(), configurations);
              keytabFileOwnerName = variableReplacementHelper.replaceVariables(keytabDescriptor.getOwnerName(), configurations);
              keytabFileOwnerAccess = variableReplacementHelper.replaceVariables(keytabDescriptor.getOwnerAccess(), configurations);
              keytabFileGroupName = variableReplacementHelper.replaceVariables(keytabDescriptor.getGroupName(), configurations);
              keytabFileGroupAccess = variableReplacementHelper.replaceVariables(keytabDescriptor.getGroupAccess(), configurations);
              keytabFileConfiguration = variableReplacementHelper.replaceVariables(keytabDescriptor.getConfiguration(), configurations);
              if (keytabFileOwnerName == null || keytabFileGroupName == null) {
                LOG.warn("Missing owner ({}) or group name ({}) of kerberos descriptor {}", keytabFileOwnerName, keytabFileGroupName, keytabDescriptor.getName());
              }
            } else {
              throw new AmbariException("Missing keytab descriptor for " + identity.getName());
            }

            // Evaluate the principal "pattern" found in the record to generate the "evaluated principal"
            // by replacing the _HOST and _REALM variables.
            String evaluatedPrincipal = principal.replace("_HOST", hostname).replace("_REALM", realm);

            ResolvedKerberosKeytab resolvedKeytab = new ResolvedKerberosKeytab(
              keytabFilePath,
              keytabFileOwnerName,
              keytabFileOwnerAccess,
              keytabFileGroupName,
              keytabFileGroupAccess,
              Sets.newHashSet(new ResolvedKerberosPrincipal(
                  hostId,
                  hostname,
                  evaluatedPrincipal,
                  "service".equalsIgnoreCase(principalType),
                  null,
                  serviceName,
                  componentName,
                  keytabFilePath
                )
              ),
              serviceName.equalsIgnoreCase(RootService.AMBARI.name()),
              componentName.equalsIgnoreCase("AMBARI_SERVER_SELF")
            );
            if (resolvedKeytabs.containsKey(keytabFilePath)) {
              ResolvedKerberosKeytab sameKeytab = resolvedKeytabs.get(keytabFilePath);
              // validating owner and group
              boolean differentOwners = false;
              String warnTemplate = "Keytab '{}' on host '{}' has different {}, originally set to '{}' and '{}:{}' has '{}', using '{}'";
              if (!StringUtils.equals(resolvedKeytab.getOwnerName(), sameKeytab.getOwnerName())) {
                LOG.warn(warnTemplate,
                  keytabFilePath, hostname, "owners", sameKeytab.getOwnerName(),
                  serviceName, componentName, resolvedKeytab.getOwnerName(),
                  sameKeytab.getOwnerName());
                differentOwners = true;
              }
              if (!StringUtils.equals(resolvedKeytab.getOwnerAccess(), sameKeytab.getOwnerAccess())) {
                LOG.warn(warnTemplate,
                  keytabFilePath, hostname, "owner access", sameKeytab.getOwnerAccess(),
                  serviceName, componentName, resolvedKeytab.getOwnerAccess(),
                  sameKeytab.getOwnerAccess());
              }
              // TODO probably fail on group difference. Some services can inject its principals to same keytab, but
              // TODO with different owners, so make sure that keytabs are accessible through group acls
              // TODO this includes same group name and group 'r' mode
              if (!StringUtils.equals(resolvedKeytab.getGroupName(), sameKeytab.getGroupName())) {
                if (differentOwners) {
                  LOG.error(warnTemplate,
                    keytabFilePath, hostname, "groups", sameKeytab.getGroupName(),
                    serviceName, componentName, resolvedKeytab.getGroupName(),
                    sameKeytab.getGroupName());
                } else {
                  LOG.warn(warnTemplate,
                    keytabFilePath, hostname, "groups", sameKeytab.getGroupName(),
                    serviceName, componentName, resolvedKeytab.getGroupName(),
                    sameKeytab.getGroupName());
                }
              }
              if (!StringUtils.equals(resolvedKeytab.getGroupAccess(), sameKeytab.getGroupAccess())) {
                if (differentOwners) {
                  if (!sameKeytab.getGroupAccess().contains("r")) {
                    LOG.error("Keytab '{}' on host '{}' referenced by multiple identities which have different owners," +
                        "but 'r' attribute missing for group. Make sure all users (that need this keytab) are in '{}' +" +
                        "group and keytab can be read by this group",
                      keytabFilePath,
                      hostname,
                      sameKeytab.getGroupName()
                    );
                  }
                  LOG.error(warnTemplate,
                    keytabFilePath, hostname, "group access", sameKeytab.getGroupAccess(),
                    serviceName, componentName, resolvedKeytab.getGroupAccess(),
                    sameKeytab.getGroupAccess());
                } else {
                  LOG.warn(warnTemplate,
                    keytabFilePath, hostname, "group access", sameKeytab.getGroupAccess(),
                    serviceName, componentName, resolvedKeytab.getGroupAccess(),
                    sameKeytab.getGroupAccess());
                }
              }
              // end validating
              // merge principal to keytab
              sameKeytab.mergePrincipals(resolvedKeytab);
              // ensure that keytab file on ambari-server host creating jass file
              if (sameKeytab.isMustWriteAmbariJaasFile() || resolvedKeytab.isMustWriteAmbariJaasFile()) {
                sameKeytab.setMustWriteAmbariJaasFile(true);
              }
              // ensure that this keytab is ambari-keytab, server will distribute it manually
              if (sameKeytab.isAmbariServerKeytab() || resolvedKeytab.isAmbariServerKeytab()) {
                sameKeytab.setAmbariServerKeytab(true);
              }
            } else {
              resolvedKeytabs.put(keytabFilePath, resolvedKeytab);
              LOG.info("Keytab {} owner:'{}:{}', group:'{}:{}' is defined", keytabFilePath,
                keytabFileOwnerName, keytabFileOwnerAccess, keytabFileGroupName, keytabFileGroupAccess);
            }

            // Append an entry to the action data file builder...
            // TODO obsolete, move to ResolvedKerberosKeytab
            if (kerberosIdentityDataFileWriter != null) {
              kerberosIdentityDataFileWriter.writeRecord(
                hostname,
                serviceName,
                componentName,
                evaluatedPrincipal,
                principalType,
                keytabFilePath,
                keytabFileOwnerName,
                keytabFileOwnerAccess,
                keytabFileGroupName,
                keytabFileGroupAccess,
                "true");
            }

            // Add the principal-related configuration to the map of configurations
            mergeConfiguration(kerberosConfigurations, principalConfiguration, principal, null);

            // Add the keytab-related configuration to the map of configurations
            mergeConfiguration(kerberosConfigurations, keytabFileConfiguration, keytabFilePath, null);

            identitiesAdded++;
          }
        }
      }
    }

    return identitiesAdded;
  }
Find the {@link ServiceComponentHost}s for the cluster, filtering using the
supplied "should include" command (<code>shouldIncludeCommand</code>).
<p>
If <code>shouldIncludeCommand</code> is <code>null/code>, no filtering will be performed causing
all found {@link ServiceComponentHost}s to be returned.

@param cluster              the cluster
@param shouldIncludeCommand the filtering logic
@return a list of (filtered) {@link ServiceComponentHost}s
@throws AmbariException if an error occurs
ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java