/*
 * 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.controller;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity;
import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
import org.apache.ambari.server.serveraction.kerberos.Component;
import org.apache.ambari.server.serveraction.kerberos.KerberosAdminAuthenticationException;
import org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFileWriter;
import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException;
import org.apache.ambari.server.serveraction.kerberos.KerberosMissingAdminCredentialsException;
import org.apache.ambari.server.serveraction.kerberos.KerberosOperationException;
import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.DesiredConfig;
import org.apache.ambari.server.state.SecurityType;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.kerberos.KerberosConfigurationDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;

public interface KerberosHelper {
  /**
   * directive used to override the behavior of the kerberos-env/manage_identities property
   */
  String DIRECTIVE_MANAGE_KERBEROS_IDENTITIES = "manage_kerberos_identities";
  /**
   * directive used to indicate that the enable Kerberos operation is only to regenerate keytab files
   */
  String DIRECTIVE_REGENERATE_KEYTABS = "regenerate_keytabs";
  /**
   * directive used to pass host list to regenerate keytabs on
   */
  String DIRECTIVE_HOSTS = "regenerate_hosts";
  /**
   * directive used to pass list of services and their components to regenerate keytabs for
   */
  String DIRECTIVE_COMPONENTS = "regenerate_components";
  /**
   * directive used to indicate configurations are not to be updated (if set to "true") when regenerating
   * keytab files
   * @deprecated use {@link #DIRECTIVE_CONFIG_UPDATE_POLICY}
   */
  String DIRECTIVE_IGNORE_CONFIGS = "ignore_config_updates";
  /**
   * directive used to indicate how to handle configuration updates when regenerating keytab files
   *
   * expected values:
   * <ul>
   * <li>none</li>
   * <li>identities_only</li>
   * <li>new_and_identities</li>
   * <li>all</li>
   * </ul>
   *
   * @see UpdateConfigurationPolicy
   */
  String DIRECTIVE_CONFIG_UPDATE_POLICY = "config_update_policy";
  /**
   * directive used to indicate that the enable Kerberos operation should proceed even if the
   * cluster's security type is not changing
   */
  String DIRECTIVE_FORCE_TOGGLE_KERBEROS = "force_toggle_kerberos";
  /**
   * config type which contains the property used to determine if Kerberos is enabled
   */
  String SECURITY_ENABLED_CONFIG_TYPE = "cluster-env";
  /**
   * name of property which states whether kerberos is enabled
   */
  String SECURITY_ENABLED_PROPERTY_NAME = "security_enabled";
  /**
   * The alias to assign to the KDC administrator credential Keystore item
   */
  String KDC_ADMINISTRATOR_CREDENTIAL_ALIAS = "kdc.admin.credential";
  /**
   * The hostname used to hold the place of the actual hostname of the host that the Ambari server
   * is on.
   */
  String AMBARI_SERVER_HOST_NAME = "ambari_server";
  /**
   * The name of the Kerberos environment configuration type
   */
  String KERBEROS_ENV = "kerberos-env";
  /**
   * The name of the Ambari server's Kerberos identities as defined in the Kerberos descriptor
   */
  String AMBARI_SERVER_KERBEROS_IDENTITY_NAME = "ambari-server";
  /**
   * The kerberos-env property name declaring whether Ambari should manage its own required
   * identities or not
   */
  String CREATE_AMBARI_PRINCIPAL = "create_ambari_principal";
  /**
   * The kerberos-env property name declaring whether Ambari should manage the cluster's required
   * identities or not
   */
  String MANAGE_IDENTITIES = "manage_identities";
  /**
   * The kerberos-env property name declaring the default realm
   */
  String DEFAULT_REALM = "realm";
  /**
   * The kerberos-env property name declaring the kdc_type
   *
   * @see org.apache.ambari.server.serveraction.kerberos.KDCType
   */
  String KDC_TYPE = "kdc_type";
  /**
   * The kerberos-env property name declaring whether to manage auth-to-local rules or not
   */
  String MANAGE_AUTH_TO_LOCAL_RULES = "manage_auth_to_local";
  /**
   * The kerberos-env property name declaring whether the Hadoop auth_to_local rules should be included for all components of an installed service even if the component itself is not installed
   */
  String INCLUDE_ALL_COMPONENTS_IN_AUTH_TO_LOCAL_RULES = "include_all_components_in_auth_to_local_rules";
  /**
   * The kerberos-env property name declaring whether auth-to-local rules should be case-insensitive or not
   */
  String CASE_INSENSITIVE_USERNAME_RULES = "case_insensitive_username_rules";
  /**
   * The kerberos-env property name declaring how to preprocess services.
   * <p>
   * Expected values are <code>"ALL"</code>, <code>"DEFAULT"</code>, <code>"NONE"</code>
   *
   * @see org.apache.ambari.server.serveraction.kerberos.PreconfigureServiceType
   */
  String PRECONFIGURE_SERVICES = "preconfigure_services";

  /**
   * If {@code true}, then this will create the stages and tasks as being
   * retry-able. A failure during Kerberos operations will not cause the entire
   * request to be aborted.
   */
  String ALLOW_RETRY = "allow_retry_on_failure";

  /**
   * Used as key in config maps to store component to host assignment mapping.
   */
  String CLUSTER_HOST_INFO = "clusterHostInfo";

  /**
   * Toggles Kerberos security to enable it or remove it depending on the state of the cluster.
   * <p/>
   * The cluster "security_type" property is used to determine the security state of the cluster.
   * If the declared security type is KERBEROS, than an attempt will be make to enable Kerberos; if
   * the security type is NONE, an attempt will be made to disable Kerberos; otherwise, no operations
   * will be performed.
   * <p/>
   * It is expected tht the "kerberos-env" configuration type is available.   It is used to obtain
   * information about the Kerberos configuration, generally specific to the KDC being used.
   * <p/>
   * This process is idempotent such that it may be called several times, each time only affecting
   * items that need to be brought up to date.
   *
   * @param cluster               the relevant Cluster
   * @param securityType          the SecurityType to handle; this value is expected to be either
   *                              SecurityType.KERBEROS or SecurityType.NONE
   * @param requestStageContainer a RequestStageContainer to place generated stages, if needed -
   *                              if null a new RequestStageContainer will be created.
   * @param manageIdentities      a Boolean value indicating how to override the configured behavior
   *                              of managing Kerberos identities; if null the configured behavior
   *                              will not be overridden
   * @return the updated or a new RequestStageContainer containing the stages that need to be
   * executed to complete this task; or null if no stages need to be executed.
   * @throws AmbariException
   * @throws KerberosInvalidConfigurationException if an issue occurs trying to get the
   *                                               Kerberos-specific configuration details
   * @throws KerberosOperationException
   */
  RequestStageContainer toggleKerberos(Cluster cluster, SecurityType securityType,
                                       RequestStageContainer requestStageContainer,
                                       Boolean manageIdentities)
      throws AmbariException, KerberosOperationException;

  /**
   * Used to execute custom security operations which are sent as directives in URI
   *
   * @param cluster               the relevant Cluster
   * @param requestProperties     this structure is expected to hold already supported and validated directives
   *                              for the 'Cluster' resource. See ClusterResourceDefinition#getUpdateDirectives
   * @param requestStageContainer a RequestStageContainer to place generated stages, if needed -
   *                              if null a new RequestStageContainer will be created.
   * @param manageIdentities      a Boolean value indicating how to override the configured behavior
   *                              of managing Kerberos identities; if null the configured behavior
   *                              will not be overridden
   * @return the updated or a new RequestStageContainer containing the stages that need to be
   * executed to complete this task; or null if no stages need to be executed.
   * @throws AmbariException
   * @throws KerberosOperationException
   * @throws KerberosInvalidConfigurationException if an issue occurs trying to get the
   *                                               Kerberos-specific configuration details
   */
  RequestStageContainer executeCustomOperations(Cluster cluster, Map<String, String> requestProperties,
                                                RequestStageContainer requestStageContainer,
                                                Boolean manageIdentities)
      throws AmbariException, KerberosOperationException;

  /**
   * Ensures the set of filtered principals and keytabs exist on the cluster.
   * <p/>
   * No configurations will be altered as a result of this operation, however principals and keytabs
   * may be updated or created.
   * <p/>
   * It is expected that the "kerberos-env" configuration type is available.  It is used to obtain
   * information about the relevant KDC.  For example, the "kdc_type" property is used to determine
   * what type of KDC is being used so that the appropriate actions maybe taken in order interact
   * with it properly.
   * <p/>
   * It is expected tht the "kerberos-env" configuration type is available.   It is used to obtain
   * information about the Kerberos configuration, generally specific to the KDC being used.
   *
   * @param cluster                        the relevant Cluster
   * @param serviceComponentFilter         a Map of service names to component names indicating the
   *                                       relevant set of services and components - if null, no
   *                                       filter is relevant; if empty, the filter indicates no
   *                                       relevant services or components
   * @param hostFilter                     a set of hostname indicating the set of hosts to process -
   *                                       if null, no filter is relevant; if empty, the filter
   *                                       indicates no relevant hosts
   * @param identityFilter                 a Collection of identity names indicating the relevant
   *                                       identities - if null, no filter is relevant; if empty,
   *                                       the filter indicates no relevant identities
   * @param hostsToForceKerberosOperations a set of host names on which it is expected that the
   *                                       Kerberos client is or will be in the INSTALLED state by
   *                                       the time the operations targeted for them are to be
   *                                       executed - if empty or null, this no hosts will be
   *                                       "forced"
   * @param requestStageContainer          a RequestStageContainer to place generated stages, if
   *                                       needed - if null a new RequestStageContainer will be
   *                                       created.
   * @param manageIdentities               a Boolean value indicating how to override the configured behavior
   *                                       of managing Kerberos identities; if null the configured behavior
   *                                       will not be overridden
   * @return the updated or a new RequestStageContainer containing the stages that need to be
   * executed to complete this task; or null if no stages need to be executed.
   * @throws AmbariException
   * @throws KerberosOperationException
   * @throws KerberosInvalidConfigurationException if an issue occurs trying to get the
   *                                               Kerberos-specific configuration details
   */
  RequestStageContainer ensureIdentities(Cluster cluster, Map<String, ? extends Collection<String>> serviceComponentFilter,
                                         Set<String> hostFilter, Collection<String> identityFilter,
                                         Set<String> hostsToForceKerberosOperations, RequestStageContainer requestStageContainer,
                                         Boolean manageIdentities)
      throws AmbariException, KerberosOperationException;

  /**
   * Deletes the set of filtered principals and keytabs from the cluster.
   * <p/>
   * No configurations will be altered as a result of this operation, however principals and keytabs
   * may be removed.
   * <p/>
   * It is expected that the "kerberos-env" configuration type is available.  It is used to obtain
   * information about the relevant KDC.  For example, the "kdc_type" property is used to determine
   * what type of KDC is being used so that the appropriate actions maybe taken in order interact
   * with it properly.
   * <p/>
   * It is expected tht the "kerberos-env" configuration type is available.   It is used to obtain
   * information about the Kerberos configuration, generally specific to the KDC being used.
   *
   * @param cluster                the relevant Cluster
   * @param serviceComponentFilter a Map of service names to component names indicating the relevant
   *                               set of services and components - if null, no filter is relevant;
   *                               if empty, the filter indicates no relevant services or components
   * @param hostFilter             a set of hostname indicating the set of hosts to process -
   *                               if null, no filter is relevant; if empty, the filter
   *                               indicates no relevant hosts
   * @param identityFilter         a Collection of identity names indicating the relevant identities -
   *                               if null, no filter is relevant; if empty, the filter indicates no
   *                               relevant identities
   * @param requestStageContainer  a RequestStageContainer to place generated stages, if needed -
   *                               if null a new RequestStageContainer will be created.
   * @param manageIdentities       a Boolean value indicating how to override the configured behavior
   *                               of managing Kerberos identities; if null the configured behavior
   *                               will not be overridden
   * @return the updated or a new RequestStageContainer containing the stages that need to be
   * executed to complete this task; or null if no stages need to be executed.
   * @throws AmbariException
   * @throws KerberosOperationException
   * @throws KerberosInvalidConfigurationException if an issue occurs trying to get the
   *                                               Kerberos-specific configuration details
   */
  RequestStageContainer deleteIdentities(Cluster cluster, Map<String, ? extends Collection<String>> serviceComponentFilter,
                                         Set<String> hostFilter, Collection<String> identityFilter,
                                         RequestStageContainer requestStageContainer, Boolean manageIdentities)
      throws AmbariException, KerberosOperationException;

  void deleteIdentities(Cluster cluster, List<Component> components, Set<String> identities) throws AmbariException, KerberosOperationException;

  /**
   * Updates the relevant configurations for the components specified in the service filter.
   * <p/>
   * If <code>null</code> is passed in as the service filter, all installed services and components
   * will be affected.  If an empty map is passed in, no services or components will be affected.
   * <p/>
   * If the relevant services and components have Kerberos descriptors, configuration values from
   * the descriptors are used to update the relevant configuration sets.
   *
   * @param cluster       the relevant Cluster
   * @param serviceFilter a Map of service names to component names indicating the
   *                      relevant set of services and components - if null, no
   *                      filter is relevant; if empty, the filter indicates no
   *                      relevant services or components
   * @throws AmbariException
   */
  void configureServices(Cluster cluster, Map<String, Collection<String>> serviceFilter)
      throws AmbariException, KerberosInvalidConfigurationException;

  /**
   * Returns the updates configurations that are expected when the given set of services are configured
   * for Kerberos.
   *
   * @param cluster                    the cluster
   * @param existingConfigurations     the cluster's existing configurations
   * @param installedServices          the map of services and relevant components to process
   * @param serviceFilter              a Map of service names to component names indicating the
   *                                   relevant set of services and components - if null, no
   *                                   filter is relevant; if empty, the filter indicates no
   *                                   relevant services or components
   * @param previouslyExistingServices a set of previously existing service names - null or a subset of installedServices
   * @param kerberosEnabled            true if kerberos is (to be) enabled; otherwise false
   * @param applyStackAdvisorUpdates   true to invoke the stack advisor to validate property updates;
   *                                   false to skip
   * @return a map of configuration updates
   * @throws AmbariException
   * @throws KerberosInvalidConfigurationException if an issue occurs trying to get the
   *                                               Kerberos-specific configuration details
   */
  Map<String, Map<String, String>> getServiceConfigurationUpdates(Cluster cluster,
                                                                  Map<String, Map<String, String>> existingConfigurations,
                                                                  Map<String, Set<String>> installedServices,
                                                                  Map<String, Collection<String>> serviceFilter,
                                                                  Set<String> previouslyExistingServices,
                                                                  boolean kerberosEnabled,
                                                                  boolean applyStackAdvisorUpdates)
      throws KerberosInvalidConfigurationException, AmbariException;

  /**
   * Invokes the Stack Advisor to help determine relevant configuration changes when enabling or
   * disabling Kerberos. If kerberosEnabled = true, recommended properties are inserted into kerberosConfigurations,
   * while properties to remove in propertiesToRemove map. In case kerberosEnabled = false, recommended properties
   * are inserted into propertiesToInsert and properties to remove in propertiesToInsert map. This is because in
   * first case properties in kerberosConfigurations are going to be set, while in second case going to be
   * removed from cluster config.
   *
   * @param cluster                a cluster
   * @param services               a set of services that are being configured to enabled or disable Kerberos
   * @param existingConfigurations the cluster's existing configurations
   * @param kerberosConfigurations the configuration updates to make
   * @param propertiesToIgnore     the configuration properties that should be ignored when applying recommendations
   * @param propertiesToRemove     the configuration properties that must be removed from cluster config are inserted
   *                               into this map in case if provided (not null) and kerberosEnabled
   * @param kerberosEnabled        true if kerberos is (to be) enabled; otherwise false
   * @return the configuration updates
   * @throws AmbariException
   */
  Map<String, Map<String, String>> applyStackAdvisorUpdates(Cluster cluster, Set<String> services,
                                                            Map<String, Map<String, String>> existingConfigurations,
                                                            Map<String, Map<String, String>> kerberosConfigurations,
                                                            Map<String, Set<String>> propertiesToIgnore,
                                                            Map<String, Set<String>> propertiesToRemove,
                                                            boolean kerberosEnabled)
      throws AmbariException;

  /**
   * Ensures that the relevant headless (or user) Kerberos identities are created and cached.
   * <p/>
   * This can be called any number of times and only the missing identities will be created.
   *
   * @param cluster                the cluster
   * @param existingConfigurations the cluster's existing configurations
   * @param services               the set of services to process
   * @return
   * @throws AmbariException
   * @throws KerberosInvalidConfigurationException if an issue occurs trying to get the
   *                                               Kerberos-specific configuration details
   */
  boolean ensureHeadlessIdentities(Cluster cluster,
                                   Map<String, Map<String, String>> existingConfigurations,
                                   Set<String> services)
      throws KerberosInvalidConfigurationException, AmbariException;

  /**
   * Create a unique identity to use for testing the general Kerberos configuration.
   *
   * @param cluster               the relevant Cluster
   * @param commandParamsStage    the command parameters map that will be sent to the agent side command
   * @param requestStageContainer a RequestStageContainer to place generated stages, if needed -
   *                              if null a new RequestStageContainer will be created.
   * @return the updated or a new RequestStageContainer containing the stages that need to be
   * executed to complete this task; or null if no stages need to be executed.
   */
  RequestStageContainer createTestIdentity(Cluster cluster, Map<String, String> commandParamsStage,
                                           RequestStageContainer requestStageContainer)
      throws KerberosOperationException, AmbariException;

  /**
   * Deletes the unique identity to use for testing the general Kerberos configuration.
   *
   * @param cluster               the relevant Cluster
   * @param commandParamsStage    the command parameters map that will be sent to the agent side command
   * @param requestStageContainer a RequestStageContainer to place generated stages, if needed -
   *                              if null a new RequestStageContainer will be created.
   * @return the updated or a new RequestStageContainer containing the stages that need to be
   * executed to complete this task; or null if no stages need to be executed.
   */
  RequestStageContainer deleteTestIdentity(Cluster cluster, Map<String, String> commandParamsStage,
                                           RequestStageContainer requestStageContainer)
      throws KerberosOperationException, AmbariException;

  /**
   * Validate the KDC admin credentials.
   *
   * @param cluster associated cluster
   * @throws AmbariException if any other error occurs while trying to validate the credentials
   */
  void validateKDCCredentials(Cluster cluster) throws KerberosMissingAdminCredentialsException,
      KerberosAdminAuthenticationException,
      KerberosInvalidConfigurationException,
      AmbariException;

  /**
   * Sets the relevant auth-to-local rule configuration properties using the services installed on
   * the cluster and their relevant Kerberos descriptors to determine the rules to be created.
   *
   * @param cluster                 cluster instance
   * @param kerberosDescriptor      the current Kerberos descriptor
   * @param realm                   the default realm
   * @param installedServices       the map of services and relevant components to process
   * @param existingConfigurations  a map of the current configurations
   * @param kerberosConfigurations  a map of the configurations to update, this where the generated
   *                                auth-to-local values will be stored
   * @param includePreconfigureData <code>true</code> to include the preconfigure data; <code>false</code> otherwise
   * @throws AmbariException
   */
  void setAuthToLocalRules(Cluster cluster, KerberosDescriptor kerberosDescriptor,
                           String realm,
                           Map<String, Set<String>> installedServices,
                           Map<String, Map<String, String>> existingConfigurations,
                           Map<String, Map<String, String>> kerberosConfigurations,
                           boolean includePreconfigureData)
      throws AmbariException;

  /**
   * @param cluster                the cluster
   * @param kerberosDescriptor     the current Kerberos descriptor
   * @param serviceComponentFilter a Map of service names to component names indicating the
   *                               relevant set of services and components - if null, no
   *                               filter is relevant; if empty, the filter indicates no
   *                               relevant services or components
   * @param hostFilter             a set of hostname indicating the set of hosts to process -
   *                               if null, no filter is relevant; if empty, the filter
   *                               indicates no relevant hosts
   * @return a list of ServiceComponentHost instances and should be processed during the relevant
   * Kerberos operation.
   * @throws AmbariException
   */
  List<ServiceComponentHost> getServiceComponentHostsToProcess(Cluster cluster,
                                                               KerberosDescriptor kerberosDescriptor,
                                                               Map<String, ? extends Collection<String>> serviceComponentFilter,
                                                               Collection<String> hostFilter)
      throws AmbariException;

  Set<String> getHostsWithValidKerberosClient(Cluster cluster) throws AmbariException;

  /**
   * Builds a composite Kerberos descriptor using the default Kerberos descriptor and a user-specified
   * Kerberos descriptor, if it exists.
   * <p/>
   * The default Kerberos descriptor is built from the kerberos.json files in the stack. It can be
   * retrieved via the <code>stacks/:stackName/versions/:version/artifacts/kerberos_descriptor</code>
   * endpoint
   * <p/>
   * The user-specified Kerberos descriptor was registered to the
   * <code>cluster/:clusterName/artifacts/kerberos_descriptor</code> endpoint.
   * <p/>
   * If the user-specified Kerberos descriptor exists, it is used to update the default Kerberos
   * descriptor and the composite is returned.  If not, the default cluster descriptor is returned
   * as-is.
   *
   * @param cluster                 cluster instance
   * @param includePreconfigureData <code>true</code> to include the preconfigure data; <code>false</code> otherwise
   * @return the kerberos descriptor associated with the specified cluster
   * @throws AmbariException if unable to obtain the descriptor
   * @see #getKerberosDescriptor(KerberosDescriptorType, Cluster, boolean, Collection, boolean, KerberosDescriptor, Map)
   */
  KerberosDescriptor getKerberosDescriptor(Cluster cluster, boolean includePreconfigureData) throws AmbariException;

  /**
   * Builds a composite Kerberos descriptor using the default Kerberos descriptor and a user-specified
   * Kerberos descriptor, if it exists.
   * <p/>
   * The default Kerberos descriptor is built from the kerberos.json files in the stack. It can be
   * retrieved via the <code>stacks/:stackName/versions/:version/artifacts/kerberos_descriptor</code>
   * endpoint
   * <p/>
   * The user-specified Kerberos descriptor was registered to the
   * <code>cluster/:clusterName/artifacts/kerberos_descriptor</code> endpoint.
   * <p/>
   * If the user-specified Kerberos descriptor exists, it is used to update the default Kerberos
   * descriptor and the composite is returned.  If not, the default cluster descriptor is returned
   * as-is.
   *
   * @param cluster                 cluster instance
   * @param includePreconfigureData <code>true</code> to include the preconfigure data; <code>false</code> otherwise
   * @param userDescriptor user defined Kerberos descriptor properties
   * @param desiredConfigs desired config map
   * @return the kerberos descriptor associated with the specified cluster
   * @throws AmbariException if unable to obtain the descriptor
   * @see #getKerberosDescriptor(KerberosDescriptorType, Cluster, boolean, Collection, boolean, KerberosDescriptor, Map)
   */
  KerberosDescriptor getKerberosDescriptor(Cluster cluster, boolean includePreconfigureData,
                                           @Nullable KerberosDescriptor userDescriptor,
                                           @Nullable Map<String, DesiredConfig> desiredConfigs)
    throws AmbariException;

  /**
   * Gets the requested Kerberos descriptor.
   * <p>
   * One of the following Kerberos descriptors will be returned - with or without pruning identity
   * definitions based on the evaluation of their <code>when</code> clauses:
   * <dl>
   * <dt>{@link KerberosDescriptorType#STACK}</dt>
   * <dd>A Kerberos descriptor built using data from the current stack definition, only</dd>
   * <dt>{@link KerberosDescriptorType#USER}</dt>
   * <dd>A Kerberos descriptor built using user-specified data stored as an artifact of the cluster, only</dd>
   * <dt>{@link KerberosDescriptorType#COMPOSITE}</dt>
   * <dd>A Kerberos descriptor built using data from the current stack definition with user-specified data stored as an artifact of the cluster applied
   * - see {@link #getKerberosDescriptor(Cluster, boolean)}</dd>
   * </dl>
   *
   * @param kerberosDescriptorType  the type of Kerberos descriptor to retrieve - see {@link KerberosDescriptorType}
   * @param cluster                 the relevant Cluster
   * @param evaluateWhenClauses     true to evaluate Kerberos identity <code>when</code> clauses and
   *                                prune if necessary; false otherwise.
   * @param additionalServices      an optional collection of service names declaring additional
   *                                services to add to the set of currently installed services to use
   *                                while evaluating <code>when</code> clauses
   * @param includePreconfigureData <code>true</code> to include the preconfigure data; <code>false</code> otherwise
