Quellcode durchsuchen

AMBARI-9045. Capture security state from components for use in enabling or disabling Kerberos (rlevas)

Robert Levas vor 10 Jahren
Ursprung
Commit
a6df75fd61

+ 29 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/ComponentStatus.java

@@ -27,6 +27,14 @@ public class ComponentStatus {
   private String componentName;
   private String msg;
   private String status;
+
+  /**
+   * A String declaring the component's security state
+   *
+   * @see org.apache.ambari.server.state.SecurityState
+   */
+  private String securityState;
+
   private String serviceName;
   private String clusterName;
   private String stackVersion;
@@ -57,6 +65,26 @@ public class ComponentStatus {
     this.status = status;
   }
 
+  /**
+   * Gets the relevant component's security state.
+   *
+   * @return a String declaring this component's security state
+   * @see org.apache.ambari.server.state.SecurityState
+   */
+  public String getSecurityState() {
+    return securityState;
+  }
+
+  /**
+   * Sets the relevant component's security state.
+   *
+   * @param securityState a String declaring this component's security state
+   * @see org.apache.ambari.server.state.SecurityState
+   */
+  public void setSecurityState(String securityState) {
+    this.securityState = securityState;
+  }
+
   public String getStackVersion() {
     return stackVersion;
   }
@@ -124,6 +152,7 @@ public class ComponentStatus {
             "componentName='" + componentName + '\'' +
             ", msg='" + msg + '\'' +
             ", status='" + status + '\'' +
+            ", securityState='" + securityState + '\'' +
             ", serviceName='" + serviceName + '\'' +
             ", clusterName='" + clusterName + '\'' +
             ", stackVersion='" + stackVersion + '\'' +

+ 20 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java

@@ -73,6 +73,7 @@ import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostHealthStatus.HealthStatus;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.SecurityState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
@@ -595,6 +596,25 @@ public class HeartBeatHandler {
                 }
               }
 
+              SecurityState prevSecurityState = scHost.getSecurityState();
+              SecurityState currentSecurityState = SecurityState.valueOf(status.getSecurityState());
+              if((prevSecurityState != currentSecurityState)) {
+                if(prevSecurityState.isEndpoint()) {
+                  scHost.setSecurityState(currentSecurityState);
+                  LOG.info(String.format("Security of service component %s of service %s of cluster %s " +
+                          "has changed from %s to %s on host %s",
+                      componentName, status.getServiceName(), status.getClusterName(), prevSecurityState,
+                      currentSecurityState, hostname));
+                }
+                else {
+                  LOG.debug(String.format("Security of service component %s of service %s of cluster %s " +
+                          "has changed from %s to %s on host %s but will be ignored since %s is a " +
+                          "transitional state",
+                      componentName, status.getServiceName(), status.getClusterName(),
+                      prevSecurityState, currentSecurityState, hostname, prevSecurityState));
+                }
+              }
+
               if (null != status.getStackVersion() && !status.getStackVersion().isEmpty()) {
                 scHost.setStackVersion(gson.fromJson(status.getStackVersion(), StackId.class));
               }

+ 2 - 8
ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java

@@ -1046,10 +1046,7 @@ public class KerberosHelper {
 
     @Override
     public SecurityState getNewSCHSecurityState() {
-      // TODO (rlevas): Set this to SecurityState.SECURING
-      // when the required infrastructure is in place
-      // See AMBARI-8343 and associated JIRAs (like AMBARI-8477)
-      return SecurityState.SECURED_KERBEROS;
+      return SecurityState.SECURING;
     }
 
     @Override
@@ -1248,10 +1245,7 @@ public class KerberosHelper {
 
     @Override
     public SecurityState getNewSCHSecurityState() {
-      // TODO (rlevas): Set this to SecurityState.UNSECURING
-      // when the required infrastructure is in place
-      // See AMBARI-8343 and associated JIRAs (like AMBARI-8477)
-      return SecurityState.UNSECURED;
+      return SecurityState.UNSECURING;
     }
 
     @Override

+ 23 - 2
ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java

@@ -21,12 +21,17 @@ package org.apache.ambari.server.serveraction.kerberos;
 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.state.Cluster;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.SecurityState;
+import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 
@@ -58,7 +63,6 @@ public class FinalizeKerberosServerAction extends KerberosServerAction {
   }
 
   /**
-   *
    * @param requestSharedDataContext a Map to be used a shared data among all ServerActions related
    *                                 to a given request
    * @return
@@ -69,6 +73,22 @@ public class FinalizeKerberosServerAction extends KerberosServerAction {
   public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException {
     String dataDirectoryPath = getCommandParameterValue(DATA_DIRECTORY);
 
+    // Set the ServiceComponentHost from a transitional state to the desired endpoint state
+    Map<String, Host> hosts = getClusters().getHostsForCluster(getClusterName());
+    if ((hosts != null) && !hosts.isEmpty()) {
+      Cluster cluster = getCluster();
+      for (String hostname : hosts.keySet()) {
+        List<ServiceComponentHost> serviceComponentHosts = cluster.getServiceComponentHosts(hostname);
+
+        for (ServiceComponentHost sch : serviceComponentHosts) {
+          SecurityState securityState = sch.getSecurityState();
+          if (securityState.isTransitional()) {
+            sch.setSecurityState(sch.getDesiredSecurityState());
+          }
+        }
+      }
+    }
+
     // Make sure this is a relevant directory. We don't want to accidentally allow _ANY_ directory
     // to be deleted.
     if ((dataDirectoryPath != null) && dataDirectoryPath.contains("/" + DATA_DIRECTORY_PREFIX)) {
@@ -90,5 +110,6 @@ public class FinalizeKerberosServerAction extends KerberosServerAction {
       }
     }
 
-    return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", null, null);  }
+    return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", null, null);
+  }
 }

+ 47 - 5
ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java

@@ -22,6 +22,7 @@ import com.google.inject.Inject;
 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.agent.ExecutionCommand;
 import org.apache.ambari.server.serveraction.AbstractServerAction;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -221,6 +222,51 @@ public abstract class KerberosServerAction extends AbstractServerAction {
     }
   }
 
+  /**
+   * Returns the relevant cluster's name
+   * <p/>
+   * Using the data from the execution command, retrieve the relevant cluster's name.
+   *
+   * @return a String declaring the relevant cluster's name
+   * @throws AmbariException if the cluster's name is not available
+   */
+  protected String getClusterName() throws AmbariException {
+    ExecutionCommand executionCommand = getExecutionCommand();
+    String clusterName = (executionCommand == null) ? null : executionCommand.getClusterName();
+
+    if ((clusterName == null) || clusterName.isEmpty()) {
+      throw new AmbariException("Failed to retrieve the cluster name from the execution command");
+    }
+
+    return clusterName;
+  }
+
+  /**
+   * Returns the relevant Cluster object
+   *
+   * @return the relevant Cluster
+   * @throws AmbariException if the Cluster object cannot be retrieved
+   */
+  protected Cluster getCluster() throws AmbariException {
+    Cluster cluster = clusters.getCluster(getClusterName());
+
+    if (cluster == null) {
+      throw new AmbariException(String.format("Failed to retrieve cluster for %s", getClusterName()));
+    }
+
+    return cluster;
+  }
+
+  /**
+   * The Clusters object for this KerberosServerAction
+   *
+   * @return a Clusters object
+   */
+  protected Clusters getClusters() {
+    return clusters;
+  }
+
+
   /**
    * Given a (command parameter) Map, attempts to safely retrieve the "data_directory" property.
    *
@@ -228,11 +274,7 @@ public abstract class KerberosServerAction extends AbstractServerAction {
    * @return a String indicating the data directory or null (if not found or set)
    */
   protected KerberosCredential getAdministratorCredential(Map<String, String> commandParameters) throws AmbariException {
-    Cluster cluster = clusters.getCluster(getExecutionCommand().getClusterName());
-
-    if (cluster == null) {
-      throw new AmbariException("Failed get the Cluster object");
-    }
+    Cluster cluster = getCluster();
 
     // Create the key like we did when we encrypted the data, based on the Cluster objects hashcode.
     byte[] key = Integer.toHexString(cluster.hashCode()).getBytes();

+ 29 - 9
ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java

@@ -32,12 +32,8 @@ import static org.apache.ambari.server.agent.DummyHeartbeatConstants.HDFS;
 import static org.apache.ambari.server.agent.DummyHeartbeatConstants.HDFS_CLIENT;
 import static org.apache.ambari.server.agent.DummyHeartbeatConstants.NAMENODE;
 import static org.apache.ambari.server.agent.DummyHeartbeatConstants.SECONDARY_NAMENODE;
-import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.*;
 import static org.easymock.EasyMock.createMockBuilder;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -87,6 +83,7 @@ import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostHealthStatus;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.SecurityState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.StackId;
@@ -537,7 +534,9 @@ public class TestHeartbeatHandler {
     ServiceComponentHost serviceComponentHost3 = clusters.getCluster(DummyCluster).getService(HDFS).
         getServiceComponent(SECONDARY_NAMENODE).getServiceComponentHost(DummyHostname1);
     serviceComponentHost1.setState(State.INSTALLED);
+    serviceComponentHost1.setSecurityState(SecurityState.UNSECURED);
     serviceComponentHost2.setState(State.INSTALLED);
+    serviceComponentHost2.setSecurityState(SecurityState.SECURING);
     serviceComponentHost3.setState(State.STARTING);
 
     HeartBeat hb = new HeartBeat();
@@ -552,6 +551,7 @@ public class TestHeartbeatHandler {
     componentStatus1.setServiceName(HDFS);
     componentStatus1.setMessage(DummyHostStatus);
     componentStatus1.setStatus(State.STARTED.name());
+    componentStatus1.setSecurityState(SecurityState.SECURED_KERBEROS.name());
     componentStatus1.setComponentName(DATANODE);
     componentStatuses.add(componentStatus1);
     ComponentStatus componentStatus2 = new ComponentStatus();
@@ -559,6 +559,7 @@ public class TestHeartbeatHandler {
     componentStatus2.setServiceName(HDFS);
     componentStatus2.setMessage(DummyHostStatus);
     componentStatus2.setStatus(State.STARTED.name());
+    componentStatus2.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus2.setComponentName(SECONDARY_NAMENODE);
     componentStatuses.add(componentStatus2);
     hb.setComponentStatus(componentStatuses);
@@ -580,8 +581,11 @@ public class TestHeartbeatHandler {
     State componentState2 = serviceComponentHost2.getState();
     State componentState3 = serviceComponentHost3.getState();
     assertEquals(State.STARTED, componentState1);
+    assertEquals(SecurityState.SECURED_KERBEROS, serviceComponentHost1.getSecurityState());
     assertEquals(State.INSTALLED, componentState2);
+    assertEquals(SecurityState.SECURING, serviceComponentHost2.getSecurityState());
     assertEquals(State.STARTED, componentState3);
+    assertEquals(SecurityState.UNSECURED, serviceComponentHost3.getSecurityState());
   }
 
   @Test
@@ -687,6 +691,7 @@ public class TestHeartbeatHandler {
     componentStatus1.setServiceName(HDFS);
     componentStatus1.setMessage(DummyHostStatus);
     componentStatus1.setStatus(State.STARTED.name());
+    componentStatus1.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus1.setComponentName(DATANODE);
     componentStatuses.add(componentStatus1);
 
@@ -695,6 +700,7 @@ public class TestHeartbeatHandler {
     componentStatus2.setServiceName(HDFS);
     componentStatus2.setMessage(DummyHostStatus);
     componentStatus2.setStatus(State.INSTALLED.name());
+    componentStatus2.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus2.setComponentName(NAMENODE);
     componentStatuses.add(componentStatus2);
 
@@ -1479,11 +1485,11 @@ public class TestHeartbeatHandler {
 
     ArrayList<ComponentStatus> componentStatuses = new ArrayList<ComponentStatus>();
     ComponentStatus componentStatus1 = createComponentStatus(DummyCluster, HDFS, DummyHostStatus, State.STARTED,
-        DATANODE, "{\"stackName\":\"HDP\",\"stackVersion\":\"1.3.0\"}");
+        SecurityState.UNSECURED, DATANODE, "{\"stackName\":\"HDP\",\"stackVersion\":\"1.3.0\"}");
     ComponentStatus componentStatus2 =
-        createComponentStatus(DummyCluster, HDFS, DummyHostStatus, State.STARTED, NAMENODE, "");
+        createComponentStatus(DummyCluster, HDFS, DummyHostStatus, State.STARTED, SecurityState.UNSECURED, NAMENODE, "");
     ComponentStatus componentStatus3 = createComponentStatus(DummyCluster, HDFS, DummyHostStatus, State.INSTALLED,
-        HDFS_CLIENT, "{\"stackName\":\"HDP\",\"stackVersion\":\"1.3.0\"}");
+        SecurityState.UNSECURED, HDFS_CLIENT, "{\"stackName\":\"HDP\",\"stackVersion\":\"1.3.0\"}");
 
     componentStatuses.add(componentStatus1);
     componentStatuses.add(componentStatus2);
@@ -1870,12 +1876,14 @@ public class TestHeartbeatHandler {
     dataNodeStatus.setServiceName(HDFS);
     dataNodeStatus.setComponentName(DATANODE);
     dataNodeStatus.setStatus("STARTED");
+    dataNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(dataNodeStatus);
     ComponentStatus nameNodeStatus = new ComponentStatus();
     nameNodeStatus.setClusterName(cluster.getClusterName());
     nameNodeStatus.setServiceName(HDFS);
     nameNodeStatus.setComponentName(NAMENODE);
     nameNodeStatus.setStatus("STARTED");
+    nameNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(nameNodeStatus);
     hb1.setComponentStatus(componentStatus);
     handler.handleHeartBeat(hb1);
@@ -1892,12 +1900,14 @@ public class TestHeartbeatHandler {
     dataNodeStatus.setServiceName(HDFS);
     dataNodeStatus.setComponentName(DATANODE);
     dataNodeStatus.setStatus("INSTALLED");
+    dataNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(dataNodeStatus);
     nameNodeStatus = new ComponentStatus();
     nameNodeStatus.setClusterName(cluster.getClusterName());
     nameNodeStatus.setServiceName(HDFS);
     nameNodeStatus.setComponentName(NAMENODE);
     nameNodeStatus.setStatus("STARTED");
+    nameNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(nameNodeStatus);
     hb2.setComponentStatus(componentStatus);
     handler.handleHeartBeat(hb2);
@@ -1916,12 +1926,14 @@ public class TestHeartbeatHandler {
     dataNodeStatus.setServiceName(HDFS);
     dataNodeStatus.setComponentName(DATANODE);
     dataNodeStatus.setStatus("INSTALLED");
+    dataNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(dataNodeStatus);
     nameNodeStatus = new ComponentStatus();
     nameNodeStatus.setClusterName(cluster.getClusterName());
     nameNodeStatus.setServiceName(HDFS);
     nameNodeStatus.setComponentName(NAMENODE);
     nameNodeStatus.setStatus("STARTED");
+    nameNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(nameNodeStatus);
     hb2a.setComponentStatus(componentStatus);
     handler.handleHeartBeat(hb2a);
@@ -1941,12 +1953,14 @@ public class TestHeartbeatHandler {
     dataNodeStatus.setServiceName(HDFS);
     dataNodeStatus.setComponentName(DATANODE);
     dataNodeStatus.setStatus("INSTALLED");
+    dataNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(dataNodeStatus);
     nameNodeStatus = new ComponentStatus();
     nameNodeStatus.setClusterName(cluster.getClusterName());
     nameNodeStatus.setServiceName(HDFS);
     nameNodeStatus.setComponentName(NAMENODE);
     nameNodeStatus.setStatus("INSTALLED");
+    nameNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(nameNodeStatus);
     hb3.setComponentStatus(componentStatus);
     handler.handleHeartBeat(hb3);
@@ -1976,6 +1990,7 @@ public class TestHeartbeatHandler {
     dataNodeStatus.setServiceName(HDFS);
     dataNodeStatus.setComponentName(DATANODE);
     dataNodeStatus.setStatus("STARTED");
+    dataNodeStatus.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus.add(dataNodeStatus);
     hb4.setComponentStatus(componentStatus);
     handler.handleHeartBeat(hb4);
@@ -2133,12 +2148,14 @@ public class TestHeartbeatHandler {
 
 
   private ComponentStatus createComponentStatus(String clusterName, String serviceName, String message,
-                                                State state, String componentName, String stackVersion) {
+                                                State state, SecurityState securityState,
+                                                String componentName, String stackVersion) {
     ComponentStatus componentStatus1 = new ComponentStatus();
     componentStatus1.setClusterName(clusterName);
     componentStatus1.setServiceName(serviceName);
     componentStatus1.setMessage(message);
     componentStatus1.setStatus(state.name());
+    componentStatus1.setSecurityState(securityState.name());
     componentStatus1.setComponentName(componentName);
     componentStatus1.setStackVersion(stackVersion);
     return componentStatus1;
@@ -2223,6 +2240,7 @@ public class TestHeartbeatHandler {
     componentStatus1.setServiceName(HDFS);
     componentStatus1.setMessage(DummyHostStatus);
     componentStatus1.setStatus(State.STARTED.name());
+    componentStatus1.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus1.setComponentName(DATANODE);
 
     componentStatus1.setExtra(extra);
@@ -2257,6 +2275,7 @@ public class TestHeartbeatHandler {
     componentStatus1.setServiceName(HDFS);
     componentStatus1.setMessage(DummyHostStatus);
     componentStatus1.setStatus(State.STARTED.name());
+    componentStatus1.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus1.setComponentName(DATANODE);
     hb.setComponentStatus(Collections.singletonList(componentStatus1));
 
@@ -2289,6 +2308,7 @@ public class TestHeartbeatHandler {
     componentStatus1.setServiceName(HDFS);
     componentStatus1.setMessage(DummyHostStatus);
     componentStatus1.setStatus(State.STARTED.name());
+    componentStatus1.setSecurityState(SecurityState.UNSECURED.name());
     componentStatus1.setComponentName(DATANODE);
 
     componentStatuses.add(componentStatus1);

+ 1 - 0
ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java

@@ -117,6 +117,7 @@ public class KerberosServerActionTest {
             .encrypt(Integer.toHexString(cluster.hashCode()).getBytes()));
 
     when(mockExecutionCommand.getCommandParams()).thenReturn(commandParams);
+    when(mockExecutionCommand.getClusterName()).thenReturn("c1");
 
     action = injector.getInstance(KerberosServerAction.class);