http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java index 0997f65..bbcd6e8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java @@ -18,21 +18,17 @@ package org.apache.ambari.server.serveraction.kerberos; -import java.text.NumberFormat; -import java.text.ParseException; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Queue; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.Set; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.security.credential.PrincipalKeyCredential; import org.apache.ambari.server.utils.ShellCommandUtil; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; +import org.apache.directory.shared.kerberos.codec.types.EncryptionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,37 +41,24 @@ import com.google.inject.Inject; * It is assumed that a MIT Kerberos client is installed and that the kdamin shell command is * available */ -public class MITKerberosOperationHandler extends KerberosOperationHandler { +public class MITKerberosOperationHandler extends KDCKerberosOperationHandler { + + private final static Logger LOG = LoggerFactory.getLogger(MITKerberosOperationHandler.class); @Inject private Configuration configuration; /** - * A regular expression pattern to use to parse the key number from the text captured from the - * get_principal kadmin command - */ - private final static Pattern PATTERN_GET_KEY_NUMBER = Pattern.compile("^.*?Key: vno (\\d+).*$", Pattern.DOTALL); - - private final static Logger LOG = LoggerFactory.getLogger(MITKerberosOperationHandler.class); - - /** * A String containing user-specified attributes used when creating principals */ private String createAttributes = null; - private String adminServerHost = null; - /** * A String containing the resolved path to the kdamin executable */ private String executableKadmin = null; /** - * A String containing the resolved path to the kdamin.local executable - */ - private String executableKadminLocal = null; - - /** * Prepares and creates resources to be used by this KerberosOperationHandler * <p/> * It is expected that this KerberosOperationHandler will not be used before this call. @@ -92,39 +75,25 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { * @throws KerberosOperationException if an unexpected error occurred */ @Override - public void open(PrincipalKeyCredential administratorCredentials, String realm, - Map<String, String> kerberosConfiguration) + public void open(PrincipalKeyCredential administratorCredentials, String realm, Map<String, String> kerberosConfiguration) throws KerberosOperationException { - setAdministratorCredential(administratorCredentials); - setDefaultRealm(realm); - if (kerberosConfiguration != null) { - setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+")); - setAdminServerHost(kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST)); - setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS)); - setCreateAttributes(kerberosConfiguration.get(KERBEROS_ENV_KDC_CREATE_ATTRIBUTES)); - } else { - setKeyEncryptionTypes(null); - setAdminServerHost(null); - setExecutableSearchPaths((String) null); - setCreateAttributes(null); + createAttributes = kerberosConfiguration.get(KERBEROS_ENV_KDC_CREATE_ATTRIBUTES); } // Pre-determine the paths to relevant Kerberos executables executableKadmin = getExecutable("kadmin"); - executableKadminLocal = getExecutable("kadmin.local"); - setOpen(true); + super.open(administratorCredentials, realm, kerberosConfiguration); } @Override public void close() throws KerberosOperationException { - // There is nothing to do here. - setOpen(false); - + createAttributes = null; executableKadmin = null; - executableKadminLocal = null; + + super.close(); } /** @@ -134,6 +103,7 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { * the result from STDOUT to determine if the presence of the specified principal. * * @param principal a String containing the principal to test + * @param service a boolean value indicating whether the principal is for a service or not * @return true if the principal exists; false otherwise * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate @@ -141,26 +111,25 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { * @throws KerberosOperationException if an unexpected error occurred */ @Override - public boolean principalExists(String principal) + public boolean principalExists(String principal, boolean service) throws KerberosOperationException { if (!isOpen()) { throw new KerberosOperationException("This operation handler has not been opened"); } - if (principal == null) { - return false; - } else { + if (!StringUtils.isEmpty(principal)) { // Create the KAdmin query to execute: - ShellCommandUtil.Result result = invokeKAdmin(String.format("get_principal %s", principal), null); + ShellCommandUtil.Result result = invokeKAdmin(String.format("get_principal %s", principal)); // If there is data from STDOUT, see if the following string exists: // Principal: <principal> String stdOut = result.getStdout(); return (stdOut != null) && stdOut.contains(String.format("Principal: %s", principal)); } - } + return false; + } /** * Creates a new principal in a previously configured MIT KDC @@ -188,72 +157,25 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { if (StringUtils.isEmpty(principal)) { throw new KerberosOperationException("Failed to create new principal - no principal specified"); - } else if (StringUtils.isEmpty(password)) { - throw new KerberosOperationException("Failed to create new principal - no password specified"); - } else { - String createAttributes = getCreateAttributes(); - // Create the kdamin query: add_principal <-randkey|-pw <password>> [<options>] <principal> - ShellCommandUtil.Result result = invokeKAdmin(String.format("add_principal %s %s", - (createAttributes == null) ? "" : createAttributes, principal), password); - - // If there is data from STDOUT, see if the following string exists: - // Principal "<principal>" created - String stdOut = result.getStdout(); - String stdErr = result.getStderr(); - if ((stdOut != null) && stdOut.contains(String.format("Principal \"%s\" created", principal))) { - return getKeyNumber(principal); - } else if ((stdErr != null) && stdErr.contains(String.format("Principal or policy already exists while creating \"%s\"", principal))) { - throw new KerberosPrincipalAlreadyExistsException(principal); - } else { - LOG.error("Failed to execute kadmin query: add_principal -pw \"********\" {} {}\nSTDOUT: {}\nSTDERR: {}", - (createAttributes == null) ? "" : createAttributes, principal, stdOut, result.getStderr()); - throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s", - principal, stdOut, result.getStderr())); - } - } - } - - /** - * Updates the password for an existing principal in a previously configured MIT KDC - * <p/> - * This implementation creates a query to send to the kadmin shell command and then interrogates - * the exit code to determine if the operation executed successfully. - * - * @param principal a String containing the principal to update - * @param password a String containing the password to set - * @return an Integer declaring the new key number - * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made - * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate - * @throws KerberosRealmException if the realm does not map to a KDC - * @throws KerberosPrincipalDoesNotExistException if the principal does not exist - * @throws KerberosOperationException if an unexpected error occurred - */ - @Override - public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException { - if (!isOpen()) { - throw new KerberosOperationException("This operation handler has not been opened"); } - if (StringUtils.isEmpty(principal)) { - throw new KerberosOperationException("Failed to set password - no principal specified"); - } else if (StringUtils.isEmpty(password)) { - throw new KerberosOperationException("Failed to set password - no password specified"); + // Create the kdamin query: add_principal <-randkey|-pw <password>> [<options>] <principal> + ShellCommandUtil.Result result = invokeKAdmin(String.format("add_principal -randkey %s %s", + (createAttributes == null) ? "" : createAttributes, principal)); + + // If there is data from STDOUT, see if the following string exists: + // Principal "<principal>" created + String stdOut = result.getStdout(); + String stdErr = result.getStderr(); + if ((stdOut != null) && stdOut.contains(String.format("Principal \"%s\" created", principal))) { + return 0; + } else if ((stdErr != null) && stdErr.contains(String.format("Principal or policy already exists while creating \"%s\"", principal))) { + throw new KerberosPrincipalAlreadyExistsException(principal); } else { - // Create the kdamin query: change_password <-randkey|-pw <password>> <principal> - ShellCommandUtil.Result result = invokeKAdmin(String.format("change_password %s", principal), password); - - String stdOut = result.getStdout(); - String stdErr = result.getStderr(); - if ((stdOut != null) && stdOut.contains(String.format("Password for \"%s\" changed", principal))) { - return getKeyNumber(principal); - } else if ((stdErr != null) && stdErr.contains("Principal does not exist")) { - throw new KerberosPrincipalDoesNotExistException(principal); - } else { - LOG.error("Failed to execute kadmin query: change_password -pw \"********\" {} \nSTDOUT: {}\nSTDERR: {}", - principal, stdOut, result.getStderr()); - throw new KerberosOperationException(String.format("Failed to update password for %s\nSTDOUT: %s\nSTDERR: %s", - principal, stdOut, result.getStderr())); - } + LOG.error("Failed to execute kadmin query: add_principal -pw \"********\" {} {}\nSTDOUT: {}\nSTDERR: {}", + (createAttributes == null) ? "" : createAttributes, principal, stdOut, result.getStderr()); + throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s", + principal, stdOut, result.getStderr())); } } @@ -263,6 +185,7 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { * The implementation is specific to a particular type of KDC. * * @param principal a String containing the principal to remove + * @param service a boolean value indicating whether the principal is for a service or not * @return true if the principal was successfully removed; otherwise false * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate @@ -270,181 +193,63 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { * @throws KerberosOperationException if an unexpected error occurred */ @Override - public boolean removePrincipal(String principal) throws KerberosOperationException { + public boolean removePrincipal(String principal, boolean service) throws KerberosOperationException { if (!isOpen()) { throw new KerberosOperationException("This operation handler has not been opened"); } if (StringUtils.isEmpty(principal)) { - throw new KerberosOperationException("Failed to remove new principal - no principal specified"); - } else { - ShellCommandUtil.Result result = invokeKAdmin(String.format("delete_principal -force %s", principal), null); - - // If there is data from STDOUT, see if the following string exists: - // Principal "<principal>" created - String stdOut = result.getStdout(); - return (stdOut != null) && !stdOut.contains("Principal does not exist"); + throw new KerberosOperationException("Failed to remove principal - no principal specified"); } - } - /** - * Sets the KDC administrator server host address - * - * @param adminServerHost the ip address or FQDN of the KDC administrator server - */ - public void setAdminServerHost(String adminServerHost) { - this.adminServerHost = adminServerHost; - } + ShellCommandUtil.Result result = invokeKAdmin(String.format("delete_principal -force %s", principal)); - /** - * Gets the IP address or FQDN of the KDC administrator server - * - * @return the IP address or FQDN of the KDC administrator server - */ - public String getAdminServerHost() { - return this.adminServerHost; - } - - /** - * Sets the (additional) principal creation attributes - * - * @param createAttributes the additional principal creations attributes - */ - public void setCreateAttributes(String createAttributes) { - this.createAttributes = createAttributes; - } - - /** - * Gets the (additional) principal creation attributes - * - * @return the additional principal creations attributes or null - */ - public String getCreateAttributes() { - return createAttributes; - } - - /** - * Retrieves the current key number assigned to the identity identified by the specified principal - * - * @param principal a String declaring the principal to look up - * @return an Integer declaring the current key number - * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made - * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate - * @throws KerberosRealmException if the realm does not map to a KDC - * @throws KerberosOperationException if an unexpected error occurred - */ - private Integer getKeyNumber(String principal) throws KerberosOperationException { - if (!isOpen()) { - throw new KerberosOperationException("This operation handler has not been opened"); - } - - if (StringUtils.isEmpty(principal)) { - throw new KerberosOperationException("Failed to get key number for principal - no principal specified"); - } else { - // Create the kdamin query: get_principal <principal> - ShellCommandUtil.Result result = invokeKAdmin(String.format("get_principal %s", principal), null); - - String stdOut = result.getStdout(); - if (stdOut == null) { - String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s", - principal, result.getExitCode(), result.getStderr()); - LOG.warn(message); - throw new KerberosOperationException(message); - } - - Matcher matcher = PATTERN_GET_KEY_NUMBER.matcher(stdOut); - if (matcher.matches()) { - NumberFormat numberFormat = NumberFormat.getIntegerInstance(); - String keyNumber = matcher.group(1); - - numberFormat.setGroupingUsed(false); - try { - Number number = numberFormat.parse(keyNumber); - return (number == null) ? 0 : number.intValue(); - } catch (ParseException e) { - String message = String.format("Failed to get key number for %s - invalid key number value (%s):\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s", - principal, keyNumber, result.getExitCode(), result.getStderr()); - LOG.warn(message); - throw new KerberosOperationException(message); - } - } else { - String message = String.format("Failed to get key number for %s - unexpected STDOUT data:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s", - principal, result.getExitCode(), result.getStderr()); - LOG.warn(message); - throw new KerberosOperationException(message); - } - } + // If there is data from STDOUT, see if the following string exists: + // Principal "<principal>" created + String stdOut = result.getStdout(); + return (stdOut != null) && !stdOut.contains("Principal does not exist"); } /** * Invokes the kadmin shell command to issue queries * - * @param query a String containing the query to send to the kdamin command - * @param userPassword a String containing the user's password to set or update if necessary, - * null if not needed + * @param query a String containing the query to send to the kdamin command * @return a ShellCommandUtil.Result containing the result of the operation * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate * @throws KerberosRealmException if the realm does not map to a KDC * @throws KerberosOperationException if an unexpected error occurred */ - protected ShellCommandUtil.Result invokeKAdmin(String query, String userPassword) + protected ShellCommandUtil.Result invokeKAdmin(String query) throws KerberosOperationException { if (StringUtils.isEmpty(query)) { throw new KerberosOperationException("Missing kadmin query"); } - ShellCommandUtil.Result result = null; - PrincipalKeyCredential administratorCredential = getAdministratorCredential(); - String defaultRealm = getDefaultRealm(); + if (StringUtils.isEmpty(executableKadmin)) { + throw new KerberosOperationException("No path for kadmin is available - this KerberosOperationHandler may not have been opened."); + } List<String> command = new ArrayList<>(); + command.add(executableKadmin); - String adminPrincipal = (administratorCredential == null) - ? null - : administratorCredential.getPrincipal(); - - ShellCommandUtil.InteractiveHandler interactiveHandler = null; - - if (StringUtils.isEmpty(adminPrincipal)) { - // Set the kdamin interface to be kadmin.local - if (StringUtils.isEmpty(executableKadminLocal)) { - throw new KerberosOperationException("No path for kadmin.local is available - this KerberosOperationHandler may not have been opened."); - } - - command.add(executableKadminLocal); - - if (userPassword != null) { - interactiveHandler = new InteractivePasswordHandler(null, userPassword); - } - } else { - if (StringUtils.isEmpty(executableKadmin)) { - throw new KerberosOperationException("No path for kadmin is available - this KerberosOperationHandler may not have been opened."); - } - char[] adminPassword = administratorCredential.getKey(); - - // Set the kdamin interface to be kadmin - command.add(executableKadmin); - - // Add explicit KDC admin host, if available - if (!StringUtils.isEmpty(getAdminServerHost())) { - command.add("-s"); - command.add(getAdminServerHost()); - } - - // Add the administrative principal - command.add("-p"); - command.add(adminPrincipal); + // Add the credential cache, if available + String credentialCacheFilePath = getCredentialCacheFilePath(); + if (!StringUtils.isEmpty(credentialCacheFilePath)) { + command.add("-c"); + command.add(credentialCacheFilePath); + } - if (!ArrayUtils.isEmpty(adminPassword)) { - interactiveHandler = new InteractivePasswordHandler(String.valueOf(adminPassword), userPassword); - } else if (userPassword != null) { - interactiveHandler = new InteractivePasswordHandler(null, userPassword); - } + // Add explicit KDC admin host, if available + String adminSeverHost = getAdminServerHost(); + if (!StringUtils.isEmpty(adminSeverHost)) { + command.add("-s"); + command.add(adminSeverHost); } + // Add default realm clause, if available + String defaultRealm = getDefaultRealm(); if (!StringUtils.isEmpty(defaultRealm)) { - // Add default realm clause command.add("-r"); command.add(defaultRealm); } @@ -457,12 +262,13 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { LOG.debug("Executing: {}", command); } + ShellCommandUtil.Result result = null; int retryCount = configuration.getKerberosOperationRetries(); int tries = 0; while (tries <= retryCount) { try { - result = executeCommand(command.toArray(new String[command.size()]), null, interactiveHandler); + result = executeCommand(command.toArray(new String[command.size()])); } catch (KerberosOperationException exception) { if (tries == retryCount) { throw exception; @@ -486,13 +292,16 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { } - if (!result.isSuccessful()) { + if ((result == null) || !result.isSuccessful()) { + int exitCode = (result == null) ? -999 : result.getExitCode(); + String stdOut = (result == null) ? "" : result.getStdout(); + String stdErr = (result == null) ? "" : result.getStderr(); + String message = String.format("Failed to execute kadmin:\n\tCommand: %s\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s", - command, result.getExitCode(), result.getStdout(), result.getStderr()); + command, exitCode, stdOut, stdErr); LOG.warn(message); // Test STDERR to see of any "expected" error conditions were encountered... - String stdErr = result.getStderr(); // Did admin credentials fail? if (stdErr.contains("Client not found in Kerberos database")) { throw new KerberosAdminAuthenticationException(stdErr); @@ -513,57 +322,56 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler { } else { throw new KerberosOperationException(String.format("Unexpected error condition executing the kadmin command. STDERR: %s", stdErr)); } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Executed the following command:\n{}\nSTDOUT: {}\nSTDERR: {}", + StringUtils.join(command, " "), result.getStdout(), result.getStderr()); + } } return result; } - /** - * InteractivePasswordHandler is a {@link org.apache.ambari.server.utils.ShellCommandUtil.InteractiveHandler} - * implementation that answers queries from kadmin or kdamin.local command for the admin and/or user - * passwords. - */ - protected static class InteractivePasswordHandler implements ShellCommandUtil.InteractiveHandler { - /** - * The queue of responses to return - */ - private LinkedList<String> responses; - private Queue<String> currentResponses; - - /** - * Constructor. - * - * @param adminPassword the KDC administrator's password (optional) - * @param userPassword the user's password (optional) - */ - public InteractivePasswordHandler(String adminPassword, String userPassword) { - responses = new LinkedList<>(); - - if (adminPassword != null) { - responses.offer(adminPassword); - } + @Override + protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache) { + // kinit -c <path> -S kadmin/`hostname -f` <principal> + return new String[]{ + executableKinit, + "-c", + credentialsCache, + "-S", + String.format("kadmin/%s", getAdminServerHost()), + credentials.getPrincipal() + }; + } - if (userPassword != null) { - responses.offer(userPassword); - responses.offer(userPassword); // Add a 2nd time for the password "confirmation" request + @Override + protected void exportKeytabFile(String principal, String keytabFileDestinationPath, Set<EncryptionType> keyEncryptionTypes) throws KerberosOperationException { + String encryptionTypeSpec = null; + if (!CollectionUtils.isEmpty(keyEncryptionTypes)) { + StringBuilder encryptionTypeSpecBuilder = new StringBuilder(); + for (EncryptionType encryptionType : keyEncryptionTypes) { + if (encryptionTypeSpecBuilder.length() > 0) { + encryptionTypeSpecBuilder.append(','); + } + encryptionTypeSpecBuilder.append(encryptionType.getName()); + encryptionTypeSpecBuilder.append(":normal"); } - currentResponses = new LinkedList<>(responses); + encryptionTypeSpec = encryptionTypeSpecBuilder.toString(); } - @Override - public boolean done() { - return currentResponses.size() == 0; - } + String query = (StringUtils.isEmpty(encryptionTypeSpec)) + ? String.format("xst -k \"%s\" %s", keytabFileDestinationPath, principal) + : String.format("xst -k \"%s\" -e %s %s", keytabFileDestinationPath, encryptionTypeSpec, principal); - @Override - public String getResponse(String query) { - return currentResponses.poll(); - } + ShellCommandUtil.Result result = invokeKAdmin(query); - @Override - public void start() { - currentResponses = new LinkedList<>(responses); + if (!result.isSuccessful()) { + String message = String.format("Failed to export the keytab file for %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s", + principal, result.getExitCode(), result.getStdout(), result.getStderr()); + LOG.warn(message); + throw new KerberosOperationException(message); } } }
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java index e1f8419..b9381b4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java @@ -107,7 +107,7 @@ public class PrepareDisableKerberosServerAction extends AbstractPrepareKerberosS Map<String, Map<String, String>> configurations = kerberosHelper.calculateConfigurations(cluster, null, kerberosDescriptor, false, false); processServiceComponentHosts(cluster, kerberosDescriptor, schToProcess, identityFilter, dataDirectory, - configurations, kerberosConfigurations, includeAmbariIdentity, propertiesToIgnore, false); + configurations, kerberosConfigurations, includeAmbariIdentity, propertiesToIgnore); // Add auth-to-local configurations to the set of changes Map<String, Set<String>> authToLocalProperties = kerberosHelper.translateConfigurationSpecifications(kerberosDescriptor.getAllAuthToLocalProperties()); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java index 335451f..671ad95 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java @@ -119,7 +119,7 @@ public class PrepareEnableKerberosServerAction extends PrepareKerberosIdentities Map<String, Map<String, String>> configurations = kerberosHelper.calculateConfigurations(cluster, null, kerberosDescriptor, false, false); processServiceComponentHosts(cluster, kerberosDescriptor, schToProcess, identityFilter, dataDirectory, - configurations, kerberosConfigurations, true, propertiesToIgnore, false); + configurations, kerberosConfigurations, true, propertiesToIgnore); // Calculate the set of configurations to update and replace any variables // using the previously calculated Map of configurations for the host. http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java index 038d1b5..83a2106 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java @@ -30,6 +30,8 @@ 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.KerberosHelper; +import org.apache.ambari.server.controller.RootComponent; +import org.apache.ambari.server.controller.RootService; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor; @@ -110,7 +112,8 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber if (serviceComponentFilter != null) { // If we are including the Ambari identity; then ensure that if a service/component filter is set, // it contains the AMBARI/AMBARI_SERVER component; else do not include the Ambari service identity. - includeAmbariIdentity &= (serviceComponentFilter.get("AMBARI") != null) && serviceComponentFilter.get("AMBARI").contains("AMBARI_SERVER"); + includeAmbariIdentity &= (serviceComponentFilter.get(RootService.AMBARI.name()) != null) + && serviceComponentFilter.get(RootService.AMBARI.name()).contains(RootComponent.AMBARI_SERVER.name()); if((operationType != OperationType.DEFAULT)) { // Update the identity filter, if necessary @@ -123,8 +126,7 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber Map<String, Map<String, String>> configurations = kerberosHelper.calculateConfigurations(cluster, null, kerberosDescriptor, false, false); processServiceComponentHosts(cluster, kerberosDescriptor, schToProcess, identityFilter, dataDirectory, - configurations, kerberosConfigurations, includeAmbariIdentity, propertiesToIgnore, - hostFilter != null); + configurations, kerberosConfigurations, includeAmbariIdentity, propertiesToIgnore); kerberosHelper.applyStackAdvisorUpdates(cluster, services, configurations, kerberosConfigurations, propertiesToIgnore, propertiesToRemove, true); http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java new file mode 100644 index 0000000..17e484a --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java @@ -0,0 +1,257 @@ +/* + * 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.serveraction.kerberos.stageutils; + +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.state.kerberos.VariableReplacementHelper; +import org.apache.commons.lang3.tuple.Pair; + +import com.google.common.collect.ImmutableSet; + +/** + * Class that represents keytab. Contains principals that mapped to host. + * Same keytab can have different set of principals on different hosts. + */ +// TODO This class need to replace {@link org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFile} +// TODO and all related structures and become main item that {@link org.apache.ambari.server.serveraction.kerberos.KerberosServerAction} +// TODO operates with instead of identity records. +public class ResolvedKerberosKeytab { + + private String ownerName = null; + private String ownerAccess = null; + private String groupName = null; + private String groupAccess = null; + private String file = null; + private Set<Pair<Long, Pair<String, String>>> mappedPrincipals = null; + private boolean isAmbariServerKeytab = false; + private boolean mustWriteAmbariJaasFile = false; + + public ResolvedKerberosKeytab( + String file, + String ownerName, + String ownerAccess, + String groupName, + String groupAccess, + Set<Pair<Long, Pair<String, String>>> mappedPrincipals, + boolean isAmbariServerKeytab, + boolean writeAmbariJaasFile + ) { + this.ownerName = ownerName; + this.ownerAccess = ownerAccess; + this.groupName = groupName; + this.groupAccess = groupAccess; + this.file = file; + this.mappedPrincipals = mappedPrincipals; + this.isAmbariServerKeytab = isAmbariServerKeytab; + this.mustWriteAmbariJaasFile = writeAmbariJaasFile; + } + + /** + * Gets the path to the keytab file + * <p/> + * The value may include variable placeholders to be replaced as needed + * <ul> + * <li> + * ${variable} placeholders are replaced on the server - see + * {@link VariableReplacementHelper#replaceVariables(String, Map)} + * </li> + * </ul> + * + * @return a String declaring the keytab file's absolute path + * @see VariableReplacementHelper#replaceVariables(String, Map) + */ + public String getFile() { + return file; + } + + /** + * Sets the path to the keytab file + * + * @param file a String declaring this keytab's file path + * @see #getFile() + */ + public void setFile(String file) { + this.file = file; + } + + /** + * Gets the local username to set as the owner of the keytab file + * + * @return a String declaring the name of the user to own the keytab file + */ + public String getOwnerName() { + return ownerName; + } + + /** + * Sets the local username to set as the owner of the keytab file + * + * @param name a String declaring the name of the user to own the keytab file + */ + public void setOwnerName(String name) { + this.ownerName = name; + } + + /** + * Gets the access permissions that should be set on the keytab file related to the file's owner + * + * @return a String declaring the access permissions that should be set on the keytab file related + * to the file's owner + * @see #ownerAccess + */ + public String getOwnerAccess() { + return ownerAccess; + } + + /** + * Sets the access permissions that should be set on the keytab file related to the file's owner + * + * @param access a String declaring the access permissions that should be set on the keytab file + * related to the file's owner + * @see #ownerAccess + */ + public void setOwnerAccess(String access) { + this.ownerAccess = access; + } + + /** + * Gets the local group name to set as the group owner of the keytab file + * + * @return a String declaring the name of the group to own the keytab file + */ + public String getGroupName() { + return groupName; + } + + /** + * Sets the local group name to set as the group owner of the keytab file + * + * @param name a String declaring the name of the group to own the keytab file + */ + public void setGroupName(String name) { + this.groupName = name; + } + + /** + * Gets the access permissions that should be set on the keytab file related to the file's group + * + * @return a String declaring the access permissions that should be set on the keytab file related + * to the file's group + * @see #groupAccess + */ + public String getGroupAccess() { + return groupAccess; + } + + /** + * Sets the access permissions that should be set on the keytab file related to the file's group + * + * @param access a String declaring the access permissions that should be set on the keytab file + * related to the file's group + * @see #groupAccess + */ + public void setGroupAccess(String access) { + this.groupAccess = access; + } + + /** + * Gets evaluated host-to-principal set associated with given keytab. + * + * @return a Set with mappedPrincipals associated with given keytab + */ + public Set<Pair<Long, Pair<String, String>>> getMappedPrincipals() { + return mappedPrincipals; + } + + /** + * Sets evaluated host-to-principal set associated with given keytab. + * + * @param mappedPrincipals a Map with host-to-principal mapping associated with given keytab + */ + public void setMappedPrincipals(Set<Pair<Long, Pair<String, String>>> mappedPrincipals) { + this.mappedPrincipals = mappedPrincipals; + } + + /** + * Gets set of hosts associated with given keytab. + * + * @return a Set with hosts + */ + public Set<Long> getHosts() { + ImmutableSet.Builder<Long> builder = ImmutableSet.builder(); + for (Pair<Long, Pair<String, String>> principal : getMappedPrincipals()) { + if (principal.getLeft() != null) { + builder.add(principal.getLeft()); + } + } + return builder.build(); + } + + /** + * Gets a set of principals associated with given keytab. + * + * @return a Set of principals + */ + public Set<Pair<String, String>> getPrincipals() { + ImmutableSet.Builder<Pair<String, String>> builder = ImmutableSet.builder(); + for (Pair<Long, Pair<String, String>> principal : getMappedPrincipals()) { + builder.add(principal.getRight()); + } + return builder.build(); + } + + /** + * Indicates if given keytab is Ambari Server keytab and can be distributed to host with Ambari Server side action. + * + * @return true, if given keytab is Ambari Server keytab. + */ + public boolean isAmbariServerKeytab() { + return isAmbariServerKeytab; + } + + /** + * Sets flag to indicate if given keytab is Ambari Server keytab and can be distributed to host with Ambari Server + * side action. + * + * @param isAmbariServerKeytab flag value + */ + public void setAmbariServerKeytab(boolean isAmbariServerKeytab) { + this.isAmbariServerKeytab = isAmbariServerKeytab; + } + + /** + * Indicates if this keytab must be written to Ambari Server jaas file. + * + * @return true, if this keytab must be written to Ambari Server jaas file. + */ + public boolean isMustWriteAmbariJaasFile() { + return mustWriteAmbariJaasFile; + } + + /** + * Sets flag to indicate if this keytab must be written to Ambari Server jaas file. + * + * @param mustWriteAmbariJaasFile flag value + */ + public void setMustWriteAmbariJaasFile(boolean mustWriteAmbariJaasFile) { + this.mustWriteAmbariJaasFile = mustWriteAmbariJaasFile; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java new file mode 100644 index 0000000..ad031c8 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/CreateAndConfigureAction.java @@ -0,0 +1,164 @@ +/* + * 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.serveraction.upgrades; + +import java.util.Iterator; +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.AmbariManagementController; +import org.apache.ambari.server.controller.ConfigurationRequest; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.ConfigHelper; +import org.apache.ambari.server.state.DesiredConfig; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.UpgradeContext; +import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask; +import org.apache.ambari.server.state.stack.upgrade.Direction; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.Inject; + +/** + * The {@link CreateAndConfigureAction} is used to alter a configuration property during + * an upgrade. It also creates the config type if it does not exist as a desired config for the cluster. + * It will only produce a new configuration if an actual change is + * occuring. For some configure tasks, the value is already at the desired + * property or the conditions of the task are not met. In these cases, a new + * configuration will not be created. This task can perform any of the following + * actions in a single declaration: + * <ul> + * <li>Copy a configuration to a new property key, optionally setting a default + * if the original property did not exist</li> + * <li>Copy a configuration to a new property key from one configuration type to + * another, optionally setting a default if the original property did not exist</li> + * <li>Rename a configuration, optionally setting a default if the original + * property did not exist</li> + * <li>Delete a configuration property</li> + * <li>Set a configuration property</li> + * <li>Conditionally set a configuration property based on another configuration + * property value</li> + * </ul> + */ +public class CreateAndConfigureAction extends ConfigureAction { + + private static final Logger LOG = LoggerFactory.getLogger(CreateAndConfigureAction.class); + + /** + * Used to lookup the cluster. + */ + @Inject + private Clusters m_clusters; + + /** + * Used to update the configuration properties. + */ + @Inject + private AmbariManagementController m_controller; + + /** + * Used to assist in the creation of a {@link ConfigurationRequest} to update + * configuration values. + */ + @Inject + private ConfigHelper m_configHelper; + + + @Override + public CommandReport execute( + ConcurrentMap<String, Object> requestSharedDataContext) + throws AmbariException, InterruptedException { + + LOG.info("Create and Configure..."); + + Map<String,String> commandParameters = getCommandParameters(); + if( null == commandParameters || commandParameters.isEmpty() ){ + return createCommandReport(0, HostRoleStatus.FAILED, "{}", "", + "Unable to change configuration values without command parameters"); + } + + String clusterName = commandParameters.get("clusterName"); + Cluster cluster = m_clusters.getCluster(clusterName); + UpgradeContext upgradeContext = getUpgradeContext(cluster); + + Direction direction = upgradeContext.getDirection(); + if (direction == Direction.DOWNGRADE) { + return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", "", "Skip changing configuration values for downgrade"); + } + + String configType = commandParameters.get(CreateAndConfigureTask.PARAMETER_CONFIG_TYPE); + String serviceName = cluster.getServiceByConfigType(configType).getName(); + + if (StringUtils.isBlank(serviceName)) { + serviceName = commandParameters.get(CreateAndConfigureTask.PARAMETER_ASSOCIATED_SERVICE); + } + + RepositoryVersionEntity sourceRepoVersion = upgradeContext.getSourceRepositoryVersion(serviceName); + RepositoryVersionEntity targetRepoVersion = upgradeContext.getTargetRepositoryVersion(serviceName); + StackId sourceStackId = sourceRepoVersion.getStackId(); + StackId targetStackId = targetRepoVersion.getStackId(); + + if (!sourceStackId.equals(targetStackId)){ + return createCommandReport(0, HostRoleStatus.FAILED, "{}", "", + "Unable to change configuration values across stacks. Use regular config task type instead."); + } + + Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs(); + DesiredConfig desiredConfig = desiredConfigs.get(configType); + if (desiredConfig == null) { + LOG.info(String.format("Could not find desired config type with name %s. Create it with default values.", configType)); + + // populate a map with default configurations from the new stack + Map<String, Map<String, String>> newServiceDefaultConfigsByType = m_configHelper.getDefaultProperties( + targetStackId, serviceName); + + if (!newServiceDefaultConfigsByType.containsKey(configType)){ + String error = String.format("%s in %s does not contain configuration type %s", serviceName, targetStackId.getStackId(), configType); + LOG.error(error); + return createCommandReport(0, HostRoleStatus.FAILED, "{}", "", error); + } + + Map<String, String> defaultConfigsForType = newServiceDefaultConfigsByType.get(configType); + // Remove any property for the new config type whose value is NULL + Iterator<Map.Entry<String, String>> iter = defaultConfigsForType.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry<String, String> entry = iter.next(); + if (entry.getValue() == null) { + iter.remove(); + } + } + + String serviceVersionNote = String.format("%s %s %s", direction.getText(true), + direction.getPreposition(), upgradeContext.getRepositoryVersion().getVersion()); + + m_configHelper.createConfigType(cluster, targetStackId, + m_controller, + configType, defaultConfigsForType, + m_controller.getAuthName(), serviceVersionNote); + } + + return super.execute(requestSharedDataContext); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java index 02cb70a..36b0491 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/PreconfigureKerberosAction.java @@ -38,8 +38,14 @@ import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.KerberosHelper; +import org.apache.ambari.server.orm.dao.HostDAO; +import org.apache.ambari.server.orm.dao.KerberosKeytabDAO; +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.RepositoryVersionEntity; import org.apache.ambari.server.serveraction.kerberos.PreconfigureServiceType; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.ConfigHelper; import org.apache.ambari.server.state.Host; @@ -56,6 +62,7 @@ import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor; import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor; import org.apache.ambari.server.state.kerberos.VariableReplacementHelper; import org.apache.ambari.server.state.stack.upgrade.Direction; +import org.apache.ambari.server.utils.StageUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; @@ -82,6 +89,18 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { @Inject private VariableReplacementHelper variableReplacementHelper; + @Inject + private HostDAO hostDAO; + + @Inject + private KerberosKeytabDAO kerberosKeytabDAO; + + @Inject + KerberosPrincipalHostDAO kerberosPrincipalHostDAO; + + @Inject + KerberosPrincipalDAO kerberosPrincipalDAO; + @Override public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException { Map<String, String> commandParameters = getCommandParameters(); @@ -131,7 +150,7 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { } } - processServiceComponentHosts(cluster, kerberosDescriptor, configurations, kerberosConfigurations, propertiesToIgnore); + processServiceComponentHosts(cluster, kerberosDescriptor, configurations, kerberosConfigurations, propertiesToIgnore, getDefaultRealm(configurations)); // Calculate the set of configurations to update and replace any variables // using the previously calculated Map of configurations for the host. @@ -280,7 +299,7 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { private void processServiceComponentHosts(Cluster cluster, KerberosDescriptor kerberosDescriptor, Map<String, Map<String, String>> currentConfigurations, Map<String, Map<String, String>> kerberosConfigurations, - Map<String, Set<String>> propertiesToBeIgnored) + Map<String, Set<String>> propertiesToBeIgnored, String realm) throws AmbariException { Collection<Host> hosts = cluster.getHosts(); @@ -292,7 +311,7 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { try { Map<String, Set<String>> propertiesToIgnore = null; - + HashMap<String, ResolvedKerberosKeytab> resolvedKeytabs = new HashMap<>(); for (Host host : hosts) { // Iterate over the components installed on the current host to get the service and // component-level Kerberos descriptors in order to determine which principals, @@ -323,7 +342,8 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { // Add service-level principals (and keytabs) kerberosHelper.addIdentities(null, serviceIdentities, - null, hostName, serviceName, componentName, kerberosConfigurations, currentConfigurations, false); + null, hostName, host.getHostId(), serviceName, componentName, kerberosConfigurations, currentConfigurations, + resolvedKeytabs, realm); propertiesToIgnore = gatherPropertiesToIgnore(serviceIdentities, propertiesToIgnore); KerberosComponentDescriptor componentDescriptor = serviceDescriptor.getComponent(componentName); @@ -338,7 +358,8 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { // Add component-level principals (and keytabs) kerberosHelper.addIdentities(null, componentIdentities, - null, hostName, serviceName, componentName, kerberosConfigurations, currentConfigurations, false); + null, hostName, host.getHostId(), serviceName, componentName, kerberosConfigurations, currentConfigurations, + resolvedKeytabs,realm); propertiesToIgnore = gatherPropertiesToIgnore(componentIdentities, propertiesToIgnore); } } @@ -359,7 +380,8 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { List<KerberosIdentityDescriptor> componentIdentities = Collections.singletonList(identity); kerberosHelper.addIdentities(null, componentIdentities, - null, KerberosHelper.AMBARI_SERVER_HOST_NAME, "AMBARI", componentName, kerberosConfigurations, currentConfigurations, false); + null, KerberosHelper.AMBARI_SERVER_HOST_NAME, ambariServerHostID(), "AMBARI", componentName, kerberosConfigurations, currentConfigurations, + resolvedKeytabs, realm); propertiesToIgnore = gatherPropertiesToIgnore(componentIdentities, propertiesToIgnore); } } @@ -367,6 +389,11 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { if ((propertiesToBeIgnored != null) && (propertiesToIgnore != null)) { propertiesToBeIgnored.putAll(propertiesToIgnore); } + + // create database records for keytabs that must be presented on cluster + for (ResolvedKerberosKeytab keytab : resolvedKeytabs.values()) { + kerberosHelper.processResolvedKeytab(keytab); + } } catch (IOException e) { throw new AmbariException(e.getMessage(), e); } @@ -582,5 +609,14 @@ public class PreconfigureKerberosAction extends AbstractUpgradeServerAction { } } } + + protected Long ambariServerHostID(){ + String ambariServerHostName = StageUtils.getHostName(); + HostEntity ambariServerHostEntity = hostDAO.findByName(ambariServerHostName); + return (ambariServerHostEntity == null) + ? null + : ambariServerHostEntity.getHostId(); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java index 073fd82..eaddb2e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java @@ -191,6 +191,7 @@ public class RepoUtil { re.setRepositoryId(repoInfo.getRepoId()); re.setDistribution(repoInfo.getDistribution()); re.setComponents(repoInfo.getComponents()); + re.setTags(repoInfo.getTags()); return re; } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java index f0d6c27..760d987 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java @@ -93,6 +93,11 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { protected File checksDir; /** + * server side action directory path + */ + protected File serverActionsDir; + + /** * service metainfo file object representation */ private ServiceMetainfoXml metaInfoXml; @@ -118,6 +123,11 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { protected static final String CHECKS_FOLDER_NAME = "checks"; /** + * Server actions directory name + */ + protected static final String SERVER_ACTIONS_FOLDER_NAME = "server_actions"; + + /** * service metainfo file name */ private static final String SERVICE_METAINFO_FILE_NAME = "metainfo.xml"; @@ -172,6 +182,15 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { } /** + * Obtain the server side actions directory path. + * + * @return server side actions directory path + */ + public File getServerActionsDir() { + return serverActionsDir; + } + + /** * Obtain the metrics file. * * @return metrics file @@ -303,6 +322,7 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { calculatePackageDirectory(stack, service); calculateUpgradesDirectory(stack, service); calculateChecksDirectory(stack, service); + calculateServerActionsDirectory(stack, service); } /** @@ -378,6 +398,15 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { } /** + * Sets the serverActionsDir if the dir exists and is not empty + * @param stack + * @param service + */ + protected void calculateServerActionsDirectory(String stack, String service) { + serverActionsDir = resolveDirectory(SERVER_ACTIONS_FOLDER_NAME, stack, service); + } + + /** * Unmarshal the metainfo file into its object representation. * * @throws AmbariException if the metainfo file doesn't exist or http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java index ec4382e..ea992e1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java @@ -150,6 +150,7 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem serviceInfo.setServicePackageFolder(serviceDirectory.getPackageDir()); serviceInfo.setServiceUpgradesFolder(serviceDirectory.getUpgradesDir()); serviceInfo.setChecksFolder(serviceDirectory.getChecksDir()); + serviceInfo.setServerActionsFolder(serviceDirectory.getServerActionsDir()); serviceInfo.setAdvisorFile(serviceDirectory.getAdvisorFile()); serviceInfo.setAdvisorName(serviceDirectory.getAdvisorName(serviceInfo.getName())); @@ -270,6 +271,13 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem } /* + * Use parent's server actions if the current one does not have any. + */ + if (serviceInfo.getServerActionsFolder() == null) { + serviceInfo.setServerActionsFolder(parent.getServerActionsFolder()); + } + + /* * If current stack version does not specify the credential store information * for the service, then use parent definition. */ http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java index 9b740d0..fc49a24 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java @@ -85,11 +85,6 @@ public class StackManager { public static final String COMMON_SERVICES = "common-services"; /** - * Prefix used for common stack hooks parent path string - */ - public static final String DEFAULT_HOOKS_FOLDER = "stack-hooks"; - - /** * Prefix used for extension services parent path string */ public static final String EXTENSIONS = "extensions"; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java index e999e24..4008c21 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java @@ -1508,22 +1508,22 @@ public class ConfigHelper { } /** - * Compares values as double in case they are numbers. - * @param actualValue - * @param newValue - * @return + * Checks for equality of parsed numbers if both values are numeric, + * otherwise using regular equality. */ - private boolean valuesAreEqual(String actualValue, String newValue) { - boolean actualValueIsNumber = NumberUtils.isNumber(actualValue); - boolean newValueIsNumber = NumberUtils.isNumber(newValue); - if (actualValueIsNumber && newValueIsNumber) { - Double ab = Double.parseDouble(actualValue); - Double bb = Double.parseDouble(newValue); - return ab.equals(bb); - } else if (!actualValueIsNumber && !newValueIsNumber) { - return actualValue.equals(newValue); + static boolean valuesAreEqual(String value1, String value2) { // exposed for unit test + if (NumberUtils.isNumber(value1) && NumberUtils.isNumber(value2)) { + try { + Number number1 = NumberUtils.createNumber(value1); + Number number2 = NumberUtils.createNumber(value2); + return Objects.equal(number1, number2) || + number1.doubleValue() == number2.doubleValue(); + } catch (NumberFormatException e) { + // fall back to regular equality + } } - return false; + + return Objects.equal(value1, value2); } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java index 8ab1fe9..a7bbc1b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java @@ -18,7 +18,11 @@ package org.apache.ambari.server.state; +import java.util.HashSet; +import java.util.Set; + import org.apache.ambari.server.controller.RepositoryResponse; +import org.apache.ambari.server.state.stack.RepoTag; import com.google.common.base.Function; import com.google.common.base.Objects; @@ -36,6 +40,7 @@ public class RepositoryInfo { private boolean repoSaved = false; private boolean unique = false; private boolean ambariManagedRepositories = true; + private Set<RepoTag> tags = new HashSet<>(); /** * @return the baseUrl @@ -207,7 +212,8 @@ public class RepositoryInfo { public RepositoryResponse convertToResponse() { return new RepositoryResponse(getBaseUrl(), getOsType(), getRepoId(), - getRepoName(), getDistribution(), getComponents(), getMirrorsList(), getDefaultBaseUrl()); + getRepoName(), getDistribution(), getComponents(), getMirrorsList(), getDefaultBaseUrl(), + getTags()); } /** @@ -259,4 +265,19 @@ public class RepositoryInfo { public void setAmbariManagedRepositories(boolean ambariManagedRepositories) { this.ambariManagedRepositories = ambariManagedRepositories; } + + /** + * @return the tags for this repository + */ + public Set<RepoTag> getTags() { + return tags; + } + + /** + * @param repoTags the tags for this repository + */ + public void setTags(Set<RepoTag> repoTags) { + tags = repoTags; + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java index c6b187a..9dc77c1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java @@ -822,7 +822,7 @@ public class ServiceImpl implements Service { List<Component> result = new ArrayList<>(); for (ServiceComponent component : getServiceComponents().values()) { for (ServiceComponentHost host : component.getServiceComponentHosts().values()) { - result.add(new Component(host.getHostName(), getName(), component.getName())); + result.add(new Component(host.getHostName(), getName(), component.getName(), host.getHost().getHostId())); } } return result; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java index 0e6e3c3..184be38 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java @@ -307,6 +307,12 @@ public class ServiceInfo implements Validable, Cloneable { @XmlTransient private File checksFolder; + /** + * Stores the path to the server actions folder which contains server actions jars for the given service. + */ + @XmlTransient + private File serverActionsFolder; + public boolean isDeleted() { return isDeleted; } @@ -833,6 +839,14 @@ public class ServiceInfo implements Validable, Cloneable { this.checksFolder = checksFolder; } + public File getServerActionsFolder() { + return serverActionsFolder; + } + + public void setServerActionsFolder(File serverActionsFolder) { + this.serverActionsFolder = serverActionsFolder; + } + /** * Exposes (and initializes on first use) map of os-specific details. * @return map of OS specific details keyed by family http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java index 025015a..4f50a01 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java @@ -37,8 +37,8 @@ import org.apache.ambari.server.ClusterNotFoundException; import org.apache.ambari.server.agent.ActionQueue; import org.apache.ambari.server.agent.AgentCommand.AgentCommandType; import org.apache.ambari.server.agent.AlertDefinitionCommand; -import org.apache.ambari.server.controller.RootServiceResponseFactory.Components; -import org.apache.ambari.server.controller.RootServiceResponseFactory.Services; +import org.apache.ambari.server.controller.RootComponent; +import org.apache.ambari.server.controller.RootService; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.state.Cluster; @@ -375,8 +375,8 @@ public class AlertDefinitionHash { return affectedHosts; } - String ambariServiceName = Services.AMBARI.name(); - String agentComponentName = Components.AMBARI_AGENT.name(); + String ambariServiceName = RootService.AMBARI.name(); + String agentComponentName = RootComponent.AMBARI_AGENT.name(); // intercept host agent alerts; they affect all hosts if (ambariServiceName.equals(definitionServiceName) http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java index e3b5d6e..0b38b36 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java @@ -60,7 +60,7 @@ import org.apache.ambari.server.controller.AmbariSessionManager; import org.apache.ambari.server.controller.ClusterResponse; import org.apache.ambari.server.controller.ConfigurationResponse; import org.apache.ambari.server.controller.MaintenanceStateHelper; -import org.apache.ambari.server.controller.RootServiceResponseFactory.Services; +import org.apache.ambari.server.controller.RootService; import org.apache.ambari.server.controller.ServiceComponentHostResponse; import org.apache.ambari.server.controller.ServiceConfigVersionResponse; import org.apache.ambari.server.events.AmbariEvent.AmbariEventType; @@ -2568,7 +2568,7 @@ public class ClusterImpl implements Cluster { // server-side events either don't have a service name or are AMBARI; // either way they are not handled by this method since it expects a // real service and component - if (StringUtils.isBlank(serviceName) || Services.AMBARI.name().equals(serviceName)) { + if (StringUtils.isBlank(serviceName) || RootService.AMBARI.name().equals(serviceName)) { continue; } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ClusterVersionSummary.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ClusterVersionSummary.java b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ClusterVersionSummary.java index e9d9920..5486ecd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ClusterVersionSummary.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ClusterVersionSummary.java @@ -24,11 +24,14 @@ import java.util.Set; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.annotate.JsonProperty; +import com.google.gson.annotations.SerializedName; + /** * For a version, collects summary information for a cluster. */ public class ClusterVersionSummary { + @SerializedName("services") @JsonProperty("services") private Map<String, ServiceVersionSummary> m_services; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ServiceVersionSummary.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ServiceVersionSummary.java b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ServiceVersionSummary.java index 29505c8..d87caef 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ServiceVersionSummary.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ServiceVersionSummary.java @@ -20,25 +20,26 @@ package org.apache.ambari.server.state.repository; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.annotate.JsonProperty; +import com.google.gson.annotations.SerializedName; + /** * Used to hold information about Service's ability to upgrade for a repository version. */ public class ServiceVersionSummary { - @JsonProperty("display_name") - private String m_displayName; - + @SerializedName("version") @JsonProperty("version") private String m_version; + @SerializedName("release_version") @JsonProperty("release_version") private String m_releaseVersion; + @SerializedName("upgrade") @JsonProperty("upgrade") private boolean m_upgrade = false; - ServiceVersionSummary(String displayName) { - m_displayName = displayName; + ServiceVersionSummary() { } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java index 099215e..7680ee1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java @@ -314,7 +314,7 @@ public class VersionDefinitionXml { continue; } - ServiceVersionSummary summary = new ServiceVersionSummary(service.getDisplayName()); + ServiceVersionSummary summary = new ServiceVersionSummary(); summaries.put(service.getName(), summary); String serviceVersion = service.getDesiredRepositoryVersion().getVersion(); @@ -322,13 +322,26 @@ public class VersionDefinitionXml { // !!! currently only one version is supported (unique service names) ManifestService manifest = manifests.get(serviceName); - summary.setVersions(manifest.version, StringUtils.isEmpty(manifest.releaseVersion) ? - release.version : manifest.releaseVersion); + final String versionToCompare; + final String summaryReleaseVersion; + if (StringUtils.isEmpty(manifest.releaseVersion)) { + versionToCompare = release.getFullVersion(); + summaryReleaseVersion = release.version; + } else { + versionToCompare = manifest.releaseVersion; + summaryReleaseVersion = manifest.releaseVersion; + } + + summary.setVersions(manifest.version, summaryReleaseVersion); - // !!! installed service already meets the release version, then nothing to upgrade - // !!! TODO should this be using the release compatible-with field? - if (VersionUtils.compareVersions(summary.getReleaseVersion(), serviceVersion, 4) > 0) { + if (RepositoryType.STANDARD == release.repositoryType) { summary.setUpgrade(true); + } else { + // !!! installed service already meets the release version, then nothing to upgrade + // !!! TODO should this be using the release compatible-with field? + if (VersionUtils.compareVersionsWithBuild(versionToCompare, serviceVersion, 4) > 0) { + summary.setUpgrade(true); + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/services/AmbariServerAlertService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/services/AmbariServerAlertService.java b/ambari-server/src/main/java/org/apache/ambari/server/state/services/AmbariServerAlertService.java index d3237a9..305f693 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/services/AmbariServerAlertService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/services/AmbariServerAlertService.java @@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit; import org.apache.ambari.server.AmbariService; import org.apache.ambari.server.alerts.AlertRunnable; -import org.apache.ambari.server.controller.RootServiceResponseFactory.Components; +import org.apache.ambari.server.controller.RootComponent; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.state.Cluster; @@ -133,7 +133,7 @@ public class AmbariServerAlertService extends AbstractScheduledService { /** * {@inheritDoc} * <p/> - * Compares all known {@link Components#AMBARI_SERVER} alerts with those that + * Compares all known {@link RootComponent#AMBARI_SERVER} alerts with those that * are scheduled. If any are not scheduled or have their intervals changed, * then reschedule those. */ http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/services/MetricsRetrievalService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/services/MetricsRetrievalService.java b/ambari-server/src/main/java/org/apache/ambari/server/state/services/MetricsRetrievalService.java index 510e706..7e5aad1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/services/MetricsRetrievalService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/services/MetricsRetrievalService.java @@ -101,7 +101,7 @@ public class MetricsRetrievalService extends AbstractService { /** * Logger. */ - protected final static Logger LOG = LoggerFactory.getLogger(MetricsRetrievalService.class); + private static final Logger LOG = LoggerFactory.getLogger(MetricsRetrievalService.class); /** * The timeout for exceptions which are caught and then cached to prevent log http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/stack/OsFamily.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/OsFamily.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/OsFamily.java index c0483e8..b84de01 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/OsFamily.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/OsFamily.java @@ -53,7 +53,7 @@ public class OsFamily { private final String OS_VERSION = "versions"; private final String LOAD_CONFIG_MSG = "Could not load OS family definition from %s file"; private final String FILE_NAME = "os_family.json"; - private final Logger LOG = LoggerFactory.getLogger(OsFamily.class); + private static final Logger LOG = LoggerFactory.getLogger(OsFamily.class); private Map<String, JsonOsFamilyEntry> osMap = null; private JsonOsFamilyRoot jsonOsFamily = null; http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java new file mode 100644 index 0000000..08a2635 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.state.stack; + +import javax.xml.bind.annotation.XmlEnum; + +/** + * A Repo tag is a way to allow Ambari to place logic surrounding repository details. + * This is used instead of random strings to tightly control how tags are used. + */ +@XmlEnum +public enum RepoTag { + + /** + * The repository may contain GPL-Licensed software + */ + GPL + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java index c2209bb..ccb25e8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java @@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; @@ -150,6 +151,10 @@ public class RepositoryXml implements Validable{ private String components = null; private boolean unique = false; + @XmlElementWrapper(name="tags") + @XmlElement(name="tag") + private Set<RepoTag> tags = new HashSet<>(); + private Repo() { } @@ -201,6 +206,13 @@ public class RepositoryXml implements Validable{ public void setUnique(boolean unique) { this.unique = unique; } + + /** + * @return the repo tags + */ + public Set<RepoTag> getTags() { + return tags; + } } /** @@ -224,6 +236,7 @@ public class RepositoryXml implements Validable{ ri.setDistribution(r.getDistribution()); ri.setComponents(r.getComponents()); ri.setUnique(r.isUnique()); + ri.setTags(r.tags); repos.add(ri); } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java index 7c32f37..7fb04f5 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/UpgradePack.java @@ -38,6 +38,7 @@ import javax.xml.bind.annotation.XmlValue; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.state.stack.upgrade.ClusterGrouping; import org.apache.ambari.server.state.stack.upgrade.ConfigureTask; +import org.apache.ambari.server.state.stack.upgrade.CreateAndConfigureTask; import org.apache.ambari.server.state.stack.upgrade.Direction; import org.apache.ambari.server.state.stack.upgrade.Grouping; import org.apache.ambari.server.state.stack.upgrade.ServiceCheckGrouping; @@ -600,6 +601,8 @@ public class UpgradePack { for (Task task : tasks) { if (Task.Type.CONFIGURE == task.getType()) { ((ConfigureTask) task).associatedService = service; + } else if (Task.Type.CREATE_AND_CONFIGURE == task.getType()) { + ((CreateAndConfigureTask) task).associatedService = service; } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java index 5bc3d8f..c9219d3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/ClusterGrouping.java @@ -135,6 +135,8 @@ public class ClusterGrouping extends Grouping { void afterUnmarshal(Unmarshaller unmarshaller, Object parent) { if (task.getType().equals(Task.Type.CONFIGURE) && StringUtils.isNotEmpty(service)) { ((ConfigureTask) task).associatedService = service; + } else if (task.getType().equals(Task.Type.CREATE_AND_CONFIGURE) && StringUtils.isNotEmpty(service)) { + ((CreateAndConfigureTask) task).associatedService = service; } }
