Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 429CF200BFA for ; Thu, 12 Jan 2017 15:26:12 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 416CD160B2D; Thu, 12 Jan 2017 14:26:12 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 0972A160B4C for ; Thu, 12 Jan 2017 15:26:10 +0100 (CET) Received: (qmail 53272 invoked by uid 500); 12 Jan 2017 14:26:10 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 53210 invoked by uid 99); 12 Jan 2017 14:26:10 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Jan 2017 14:26:10 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E57AADFDC7; Thu, 12 Jan 2017 14:26:09 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: dmitriusan@apache.org To: commits@ambari.apache.org Date: Thu, 12 Jan 2017 14:26:11 -0000 Message-Id: <98da4c90f9fb4fce81bb34f93db28183@git.apache.org> In-Reply-To: <99c076fc944745429e770a8b26261826@git.apache.org> References: <99c076fc944745429e770a8b26261826@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/4] ambari git commit: AMBARI-19464. Stack Downgrading Potentially Corrupts Kerberos Descriptor (echekanskiy via dlysnichenko) archived-at: Thu, 12 Jan 2017 14:26:12 -0000 AMBARI-19464. Stack Downgrading Potentially Corrupts Kerberos Descriptor (echekanskiy via dlysnichenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/59a770f2 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/59a770f2 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/59a770f2 Branch: refs/heads/trunk Commit: 59a770f2edd5e2e40cff3221d9b972e97ba4afa5 Parents: 384a7f0 Author: Lisnichenko Dmitro Authored: Thu Jan 12 16:24:30 2017 +0200 Committer: Lisnichenko Dmitro Committed: Thu Jan 12 16:24:30 2017 +0200 ---------------------------------------------------------------------- .../server/orm/entities/ArtifactEntity.java | 4 +- .../upgrades/UpgradeUserKerberosDescriptor.java | 130 +++++++++--- .../UpgradeUserKerberosDescriptorTest.java | 201 +++++++++++++++++++ 3 files changed, 302 insertions(+), 33 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/59a770f2/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ArtifactEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ArtifactEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ArtifactEntity.java index 367c093..d06d985 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ArtifactEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ArtifactEntity.java @@ -113,7 +113,7 @@ public class ArtifactEntity { * * @param foreignKeys ordered map of foreign key property names to values */ - public void setForeignKeys(TreeMap foreignKeys) { + public void setForeignKeys(Map foreignKeys) { this.foreignKeys = serializeForeignKeys(foreignKeys); } @@ -135,7 +135,7 @@ public class ArtifactEntity { * * @return string representation of the foreign keys map */ - public static String serializeForeignKeys(TreeMap foreignKeys) { + public static String serializeForeignKeys(Map foreignKeys) { return jsonSerializer.toJson(foreignKeys); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/59a770f2/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java index 6f79670..ac1e86d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java @@ -76,6 +76,9 @@ public class UpgradeUserKerberosDescriptor extends AbstractServerAction { */ private static final String TARGET_STACK_KEY = "target_stack"; + private final static String KERBEROS_DESCRIPTOR_NAME = "kerberos_descriptor"; + private final static String KERBEROS_DESCRIPTOR_BACKUP_NAME = "kerberos_descriptor_backup"; + @Inject private ArtifactDAO artifactDAO; @@ -117,49 +120,52 @@ public class UpgradeUserKerberosDescriptor extends AbstractServerAction { if (userDescriptor != null) { StackId originalStackId = getStackIdFromCommandParams(ORIGINAL_STACK_KEY); StackId targetStackId = getStackIdFromCommandParams(TARGET_STACK_KEY); - boolean isDowngrade = isDowngrade(); - - StackId newVersion = (isDowngrade) ? originalStackId : targetStackId; - StackId previousVersion = (isDowngrade) ? targetStackId : originalStackId; - KerberosDescriptor newDescriptor = null; - KerberosDescriptor previousDescriptor = null; - if (newVersion == null) { - logErrorMessage(messages, errorMessages, "The new stack version information was not found."); + if (isDowngrade()) { + restoreDescriptor(foreignKeys, messages, errorMessages); } else { - logMessage(messages, String.format("Obtaining new stack Kerberos descriptor for %s.", newVersion.toString())); - newDescriptor = ambariMetaInfo.getKerberosDescriptor(newVersion.getStackName(), newVersion.getStackVersion()); + backupDescriptor(foreignKeys, messages, errorMessages); + + KerberosDescriptor newDescriptor = null; + KerberosDescriptor previousDescriptor = null; + + if (targetStackId == null) { + logErrorMessage(messages, errorMessages, "The new stack version information was not found."); + } else { + logMessage(messages, String.format("Obtaining new stack Kerberos descriptor for %s.", targetStackId.toString())); + newDescriptor = ambariMetaInfo.getKerberosDescriptor(targetStackId.getStackName(), targetStackId.getStackVersion()); - if (newDescriptor == null) { - logErrorMessage(messages, errorMessages, String.format("The Kerberos descriptor for the new stack version, %s, was not found.", newVersion.toString())); + if (newDescriptor == null) { + logErrorMessage(messages, errorMessages, String.format("The Kerberos descriptor for the new stack version, %s, was not found.", targetStackId.toString())); + } } - } - if (previousVersion == null) { - logErrorMessage(messages, errorMessages, "The previous stack version information was not found."); - } else { - logMessage(messages, String.format("Obtaining previous stack Kerberos descriptor for %s.", previousVersion.toString())); - previousDescriptor = ambariMetaInfo.getKerberosDescriptor(previousVersion.getStackName(), previousVersion.getStackVersion()); + if (originalStackId == null) { + logErrorMessage(messages, errorMessages, "The previous stack version information was not found."); + } else { + logMessage(messages, String.format("Obtaining previous stack Kerberos descriptor for %s.", originalStackId.toString())); + previousDescriptor = ambariMetaInfo.getKerberosDescriptor(originalStackId.getStackName(), originalStackId.getStackVersion()); - if (newDescriptor == null) { - logErrorMessage(messages, errorMessages, String.format("The Kerberos descriptor for the previous stack version, %s, was not found.", previousVersion.toString())); + if (newDescriptor == null) { + logErrorMessage(messages, errorMessages, String.format("The Kerberos descriptor for the previous stack version, %s, was not found.", originalStackId.toString())); + } } - } - if (errorMessages.isEmpty()) { - logMessage(messages, "Updating the user-specified Kerberos descriptor."); + if (errorMessages.isEmpty()) { + logMessage(messages, "Updating the user-specified Kerberos descriptor."); - KerberosDescriptor updatedDescriptor = KerberosDescriptorUpdateHelper.updateUserKerberosDescriptor( - previousDescriptor, - newDescriptor, - userDescriptor); + KerberosDescriptor updatedDescriptor = KerberosDescriptorUpdateHelper.updateUserKerberosDescriptor( + previousDescriptor, + newDescriptor, + userDescriptor); - logMessage(messages, "Storing updated user-specified Kerberos descriptor."); + logMessage(messages, "Storing updated user-specified Kerberos descriptor."); - entity.setArtifactData(updatedDescriptor.toMap()); - artifactDAO.merge(entity); + entity.setArtifactData(updatedDescriptor.toMap()); + artifactDAO.merge(entity); - logMessage(messages, "Successfully updated the user-specified Kerberos descriptor."); + logMessage(messages, "Successfully updated the user-specified Kerberos descriptor."); + } } } else { logMessage(messages, "A user-specified Kerberos descriptor was not found. No updates are necessary."); @@ -203,4 +209,66 @@ public class UpgradeUserKerberosDescriptor extends AbstractServerAction { messages.add(message); errorMessages.add(message); } + + /** + * Create copy of user defined kerberos descriptor and stores it with name {@code kerberos_descriptor_backup}. + * + * @param foreignKeys keys specific for cluster + * @param messages list of log messages + * @param errorMessages list of error log messages + */ + private void backupDescriptor(TreeMap foreignKeys, List messages, List errorMessages) { + ArtifactEntity backupEntity = artifactDAO.findByNameAndForeignKeys(KERBEROS_DESCRIPTOR_BACKUP_NAME, foreignKeys); + if (backupEntity != null) { + artifactDAO.remove(backupEntity); + } + + ArtifactEntity entity = artifactDAO.findByNameAndForeignKeys(KERBEROS_DESCRIPTOR_NAME, foreignKeys); + if (entity != null) { + backupEntity = new ArtifactEntity(); + backupEntity.setArtifactName(KERBEROS_DESCRIPTOR_BACKUP_NAME); + backupEntity.setForeignKeys(entity.getForeignKeys()); + backupEntity.setArtifactData(entity.getArtifactData()); + + artifactDAO.create(backupEntity); + logMessage(messages, "Created backup of kerberos descriptor"); + } else { + logErrorMessage( + messages, + errorMessages, + "No backup of kerberos descriptor created due to missing original kerberos descriptor" + ); + } + + + } + + /** + * Restores user defined kerberos descriptor from artifact with name {@code kerberos_descriptor_backup}. + * + * @param foreignKeys keys specific for cluster + * @param messages list of log messages + * @param errorMessages list of error log messages + */ + private void restoreDescriptor(TreeMap foreignKeys, List messages, List errorMessages) { + ArtifactEntity backupEntity = artifactDAO.findByNameAndForeignKeys(KERBEROS_DESCRIPTOR_BACKUP_NAME, foreignKeys); + + if (backupEntity != null) { + ArtifactEntity entity = artifactDAO.findByNameAndForeignKeys(KERBEROS_DESCRIPTOR_NAME, foreignKeys); + if (entity != null) { + artifactDAO.remove(entity); + } + + entity = new ArtifactEntity(); + entity.setArtifactName(KERBEROS_DESCRIPTOR_NAME); + entity.setForeignKeys(backupEntity.getForeignKeys()); + entity.setArtifactData(backupEntity.getArtifactData()); + + artifactDAO.create(entity); + logMessage(messages, "Restored kerberos descriptor from backup"); + } else { + logErrorMessage(messages, errorMessages, "No backup of kerberos descriptor found"); + } + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/59a770f2/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptorTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptorTest.java new file mode 100644 index 0000000..9e2080b --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptorTest.java @@ -0,0 +1,201 @@ +/** + * 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 static org.easymock.EasyMock.*; +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper; +import org.apache.ambari.server.actionmanager.HostRoleCommand; +import org.apache.ambari.server.agent.ExecutionCommand; +import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.orm.dao.ArtifactDAO; +import org.apache.ambari.server.orm.entities.ArtifactEntity; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.kerberos.KerberosDescriptor; +import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory; +import org.apache.ambari.server.state.kerberos.KerberosDescriptorUpdateHelper; +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.Test; + +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +/** + * Tests OozieConfigCalculation logic + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(KerberosDescriptorUpdateHelper.class) +public class UpgradeUserKerberosDescriptorTest { + private Clusters clusters; + private Cluster cluster; + private AmbariMetaInfo ambariMetaInfo; + private KerberosDescriptorFactory kerberosDescriptorFactory; + private ArtifactDAO artifactDAO; + + private TreeMap fields = new TreeMap<>(); + + @Before + public void setup() throws Exception { + clusters = EasyMock.createMock(Clusters.class); + cluster = EasyMock.createMock(Cluster.class); + kerberosDescriptorFactory = EasyMock.createNiceMock(KerberosDescriptorFactory.class); + ambariMetaInfo = EasyMock.createMock(AmbariMetaInfo.class); + artifactDAO = EasyMock.createNiceMock(ArtifactDAO.class); + + expect(clusters.getCluster((String) anyObject())).andReturn(cluster).anyTimes(); + expect(cluster.getClusterId()).andReturn(1l).atLeastOnce(); + replay(clusters, cluster); + + prepareFields(); + + } + + @Test + public void testUpgrade() throws Exception { + + Map commandParams = new HashMap(); + commandParams.put("clusterName", "c1"); + commandParams.put("upgrade_direction", "UPGRADE"); + commandParams.put("original_stack", "HDP-2.4"); + commandParams.put("target_stack", "HDP-2.5"); + + ExecutionCommand executionCommand = new ExecutionCommand(); + executionCommand.setCommandParams(commandParams); + executionCommand.setClusterName("c1"); + + HostRoleCommand hrc = EasyMock.createMock(HostRoleCommand.class); + expect(hrc.getRequestId()).andReturn(1L).anyTimes(); + expect(hrc.getStageId()).andReturn(2L).anyTimes(); + expect(hrc.getExecutionCommandWrapper()).andReturn(new ExecutionCommandWrapper(executionCommand)).anyTimes(); + replay(hrc); + + UpgradeUserKerberosDescriptor action = new UpgradeUserKerberosDescriptor(); + injectFields(action); + + action.setExecutionCommand(executionCommand); + action.setHostRoleCommand(hrc); + + ArtifactEntity entity = EasyMock.createNiceMock(ArtifactEntity.class); + expect(entity.getArtifactData()).andReturn(null).anyTimes(); + expect(entity.getForeignKeys()).andReturn(null).anyTimes(); + expect(artifactDAO.findByNameAndForeignKeys(anyString(), (TreeMap) anyObject())).andReturn(entity).atLeastOnce(); + + KerberosDescriptor userDescriptor = EasyMock.createMock(KerberosDescriptor.class); + KerberosDescriptor newDescriptor = EasyMock.createMock(KerberosDescriptor.class); + KerberosDescriptor previousDescriptor = EasyMock.createMock(KerberosDescriptor.class); + KerberosDescriptor updatedKerberosDescriptor = EasyMock.createMock(KerberosDescriptor.class); + + PowerMockito.mockStatic(KerberosDescriptorUpdateHelper.class); + PowerMockito.when(KerberosDescriptorUpdateHelper.updateUserKerberosDescriptor(previousDescriptor, newDescriptor, userDescriptor)).thenReturn(updatedKerberosDescriptor); + expect(kerberosDescriptorFactory.createInstance((Map)null)).andReturn(userDescriptor).atLeastOnce(); + expect(ambariMetaInfo.getKerberosDescriptor("HDP","2.5")).andReturn(newDescriptor).atLeastOnce(); + expect(ambariMetaInfo.getKerberosDescriptor("HDP","2.4")).andReturn(previousDescriptor).atLeastOnce(); + + + expect(updatedKerberosDescriptor.toMap()).andReturn(null).once(); + + + expect(artifactDAO.merge(entity)).andReturn(entity).once(); + Capture createCapture = Capture.newInstance(); + artifactDAO.create(capture(createCapture)); + EasyMock.expectLastCall().once(); + + replay(artifactDAO, entity, ambariMetaInfo, kerberosDescriptorFactory, updatedKerberosDescriptor); + + action.execute(null); + + verify(artifactDAO, updatedKerberosDescriptor); + assertEquals(createCapture.getValue().getArtifactName(), "kerberos_descriptor_backup"); + } + + @Test + public void testDowngrade() throws Exception { + + Map commandParams = new HashMap(); + commandParams.put("clusterName", "c1"); + commandParams.put("upgrade_direction", "DOWNGRADE"); + commandParams.put("original_stack", "HDP-2.4"); + commandParams.put("target_stack", "HDP-2.5"); + + ExecutionCommand executionCommand = new ExecutionCommand(); + executionCommand.setCommandParams(commandParams); + executionCommand.setClusterName("c1"); + + HostRoleCommand hrc = EasyMock.createMock(HostRoleCommand.class); + expect(hrc.getRequestId()).andReturn(1L).anyTimes(); + expect(hrc.getStageId()).andReturn(2L).anyTimes(); + expect(hrc.getExecutionCommandWrapper()).andReturn(new ExecutionCommandWrapper(executionCommand)).anyTimes(); + replay(hrc); + + UpgradeUserKerberosDescriptor action = new UpgradeUserKerberosDescriptor(); + injectFields(action); + + action.setExecutionCommand(executionCommand); + action.setHostRoleCommand(hrc); + + ArtifactEntity entity = EasyMock.createNiceMock(ArtifactEntity.class); + expect(entity.getArtifactData()).andReturn(null).anyTimes(); + expect(entity.getForeignKeys()).andReturn(null).anyTimes(); + expect(artifactDAO.findByNameAndForeignKeys(anyString(), (TreeMap) anyObject())).andReturn(entity).atLeastOnce(); + + KerberosDescriptor userDescriptor = EasyMock.createMock(KerberosDescriptor.class); + + expect(kerberosDescriptorFactory.createInstance((Map)null)).andReturn(userDescriptor).atLeastOnce(); + + Capture createCapture = Capture.newInstance(); + artifactDAO.create(capture(createCapture)); + EasyMock.expectLastCall().once(); + + artifactDAO.remove(entity); + EasyMock.expectLastCall().atLeastOnce(); + + replay(artifactDAO, entity, ambariMetaInfo, kerberosDescriptorFactory); + + action.execute(null); + + verify(artifactDAO); + assertEquals(createCapture.getValue().getArtifactName(), "kerberos_descriptor"); + } + + private void prepareFields() throws NoSuchFieldException { + String[] fieldsNames = {"artifactDAO","clusters","ambariMetaInfo","kerberosDescriptorFactory"}; + for(String fieldName : fieldsNames) + { + Field clustersField = UpgradeUserKerberosDescriptor.class.getDeclaredField(fieldName); + clustersField.setAccessible(true); + fields.put(fieldName, clustersField); + } + } + private void injectFields(UpgradeUserKerberosDescriptor action) throws IllegalAccessException { + fields.get("artifactDAO").set(action, artifactDAO); + fields.get("clusters").set(action, clusters); + fields.get("ambariMetaInfo").set(action, ambariMetaInfo); + fields.get("kerberosDescriptorFactory").set(action, kerberosDescriptorFactory); + } +}