You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by dm...@apache.org on 2016/04/28 19:03:17 UTC

ambari git commit: AMBARI-16134. Force running service checks for services before upgrade (dlysnichenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 7cfcf6579 -> 1b49c6c97


AMBARI-16134. Force running service checks for services before upgrade (dlysnichenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1b49c6c9
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1b49c6c9
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1b49c6c9

Branch: refs/heads/trunk
Commit: 1b49c6c97f3a38652b9b8231b7c65cec2c2a0a2e
Parents: 7cfcf65
Author: Lisnichenko Dmitro <dl...@hortonworks.com>
Authored: Thu Apr 28 20:01:29 2016 +0300
Committer: Lisnichenko Dmitro <dl...@hortonworks.com>
Committed: Thu Apr 28 20:01:29 2016 +0300

----------------------------------------------------------------------
 .../ambari/server/checks/CheckDescription.java  |   7 +
 .../ambari/server/checks/HealthCheck.java       |   6 +-
 .../checks/ServiceCheckValidityCheck.java       | 147 +++++++++++++++++++
 .../checks/ServiceCheckValidityCheckTest.java   | 125 ++++++++++++++++
 4 files changed, 284 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1b49c6c9/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
index d701bdc..6b39082 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
@@ -54,6 +54,13 @@ public enum CheckDescription {
             "The following issues have been detected on this cluster and should be addressed before upgrading: %s");
       }}),
 
+  SERVICE_CHECK(PrereqCheckType.SERVICE,
+      "Last Service Check should be more recent than the last configuration change for the given service",
+      new HashMap<String, String>() {{
+        put(AbstractCheckDescriptor.DEFAULT,
+            "The following service configurations have been updated and their Service Checks should be run again: %s");
+      }}),
+
   HOSTS_MAINTENANCE_MODE(PrereqCheckType.HOST,
       "Hosts in Maintenance Mode will be excluded from the upgrade.",
       new HashMap<String, String>() {{

http://git-wip-us.apache.org/repos/asf/ambari/blob/1b49c6c9/ambari-server/src/main/java/org/apache/ambari/server/checks/HealthCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/HealthCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/HealthCheck.java
index a1ab1eb..b75e923 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/HealthCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/HealthCheck.java
@@ -83,7 +83,11 @@ public class HealthCheck extends AbstractCheckDescriptor {
         String label = alertHistory.getAlertDefinition().getLabel();
         String hostName = alertHistory.getHostName();
 
-        errorMessages.add(state + ": " + label + ": " + hostName);
+        if (hostName == null) {
+          errorMessages.add(state + ": " + label);
+        } else {
+          errorMessages.add(state + ": " + label + ": " + hostName);
+        }
         prerequisiteCheck.getFailedDetail().add(new AlertDetail(state, label, hostName));
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1b49c6c9/ambari-server/src/main/java/org/apache/ambari/server/checks/ServiceCheckValidityCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServiceCheckValidityCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServiceCheckValidityCheck.java
new file mode 100644
index 0000000..8b39863
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServiceCheckValidityCheck.java
@@ -0,0 +1,147 @@
+/*
+ * 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.checks;
+
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.controller.internal.PageRequestImpl;
+import org.apache.ambari.server.controller.internal.RequestImpl;
+import org.apache.ambari.server.controller.spi.PageRequest;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.dao.ServiceConfigDAO;
+import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
+import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * Checks that all Service Checks are less recent than last
+ * configuration update for given services.
+ * That is a potential problem when doing stack update.
+ */
+@Singleton
+@UpgradeCheck(group = UpgradeCheckGroup.DEFAULT, required = true)
+public class ServiceCheckValidityCheck extends AbstractCheckDescriptor {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ServiceCheckValidityCheck.class);
+
+  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
+  private static final PageRequestImpl PAGE_REQUEST = new PageRequestImpl(PageRequest.StartingPoint.End, 1000, 0, null, null);
+  private static final RequestImpl REQUEST = new RequestImpl(null, null, null, null, null, PAGE_REQUEST);
+
+
+  @Inject
+  Provider<ServiceConfigDAO> serviceConfigDAOProvider;
+
+  @Inject
+  Provider<HostRoleCommandDAO> hostRoleCommandDAOProvider;
+
+  /**
+   * Constructor.
+   */
+  public ServiceCheckValidityCheck() {
+    super(CheckDescription.SERVICE_CHECK);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request)
+      throws AmbariException {
+
+    ServiceConfigDAO serviceConfigDAO = serviceConfigDAOProvider.get();
+    HostRoleCommandDAO hostRoleCommandDAO = hostRoleCommandDAOProvider.get();
+
+    final String clusterName = request.getClusterName();
+    final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+    long clusterId = cluster.getClusterId();
+
+    Map<String, Long> lastServiceConfigUpdates = new HashMap<>();
+
+    for (Service service : cluster.getServices().values()) {
+      if (service.getMaintenanceState() != MaintenanceState.OFF || !hasAtLeastOneComponentVersionAdvertised(service)) {
+        continue;
+      }
+      ServiceConfigEntity lastServiceConfig = serviceConfigDAO.getLastServiceConfig(clusterId, service.getName());
+      lastServiceConfigUpdates.put(service.getName(), lastServiceConfig.getCreateTimestamp());
+    }
+
+    List<HostRoleCommandEntity> commands = hostRoleCommandDAO.findAll(REQUEST, null);
+    Collections.reverse(commands);
+
+    LinkedHashSet<String> failedServiceNames = new LinkedHashSet<>();
+    for (Map.Entry<String, Long> serviceEntry : lastServiceConfigUpdates.entrySet()) {
+      String serviceName = serviceEntry.getKey();
+      Long configTimestamp = serviceEntry.getValue();
+      for (HostRoleCommandEntity command : commands) {
+        if (RoleCommand.SERVICE_CHECK.equals(command.getRoleCommand()) && command.getCommandDetail().contains(serviceName)) {
+          Long serviceCheckTimestamp = command.getStartTime();
+          if (serviceCheckTimestamp < configTimestamp) {
+            failedServiceNames.add(serviceName);
+            LOG.info("Service {} latest config change is {}, latest service check executed at {}",
+                serviceName,
+                DATE_FORMAT.format(new Date(configTimestamp)),
+                DATE_FORMAT.format(new Date(serviceCheckTimestamp))
+            );
+          }
+        }
+      }
+    }
+
+    if (!failedServiceNames.isEmpty()) {
+      prerequisiteCheck.setFailedOn(failedServiceNames);
+      prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
+      String failReason = getFailReason(prerequisiteCheck, request);
+      prerequisiteCheck.setFailReason(String.format(failReason, StringUtils.join(failedServiceNames, ", ")));
+    }
+  }
+
+  private boolean hasAtLeastOneComponentVersionAdvertised(Service service) {
+    Collection<ServiceComponent> components = service.getServiceComponents().values();
+    for (ServiceComponent component : components) {
+      if (component.isVersionAdvertised()) {
+        return true;
+      }
+    }
+    return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/1b49c6c9/ambari-server/src/test/java/org/apache/ambari/server/checks/ServiceCheckValidityCheckTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/ServiceCheckValidityCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/ServiceCheckValidityCheckTest.java
new file mode 100644
index 0000000..4a3ae5c
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/ServiceCheckValidityCheckTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.checks;
+
+import static java.util.Collections.singletonList;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.dao.ServiceConfigDAO;
+import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
+import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Provider;
+
+public class ServiceCheckValidityCheckTest {
+  private static final String CLUSTER_NAME = "cluster1";
+  private static final long CLUSTER_ID = 1L;
+  private static final String SERVICE_NAME = "HDFS";
+  private static final long CONFIG_CREATE_TIMESTAMP = 1461518722202L;
+  private static final String COMMAND_DETAIL = "HDFS service check";
+  private static final long SERVICE_CHECK_START_TIME = CONFIG_CREATE_TIMESTAMP - 2000L;
+  private static final String SERVICE_COMPONENT_NAME = "service component";
+  private ServiceCheckValidityCheck serviceCheckValidityCheck;
+
+  private ServiceConfigDAO serviceConfigDAO;
+  private HostRoleCommandDAO hostRoleCommandDAO;
+  private Service service;
+
+
+  @Before
+  public void setUp() throws Exception {
+    final Clusters clusters = mock(Clusters.class);
+    service = mock(Service.class);
+    serviceConfigDAO = mock(ServiceConfigDAO.class);
+    hostRoleCommandDAO = mock(HostRoleCommandDAO.class);
+
+    serviceCheckValidityCheck = new ServiceCheckValidityCheck();
+    serviceCheckValidityCheck.hostRoleCommandDAOProvider = new Provider<HostRoleCommandDAO>() {
+      @Override
+      public HostRoleCommandDAO get() {
+        return hostRoleCommandDAO;
+      }
+    };
+    serviceCheckValidityCheck.serviceConfigDAOProvider = new Provider<ServiceConfigDAO>() {
+      @Override
+      public ServiceConfigDAO get() {
+        return serviceConfigDAO;
+      }
+    };
+    serviceCheckValidityCheck.clustersProvider = new Provider<Clusters>() {
+      @Override
+      public Clusters get() {
+        return clusters;
+      }
+    };
+
+    Cluster cluster = mock(Cluster.class);
+    when(clusters.getCluster(CLUSTER_NAME)).thenReturn(cluster);
+    when(cluster.getClusterId()).thenReturn(CLUSTER_ID);
+    when(cluster.getServices()).thenReturn(ImmutableMap.of(SERVICE_NAME, service));
+
+    when(service.getName()).thenReturn(SERVICE_NAME);
+
+  }
+
+  @Test
+  public void testFailWhenServiceWithOutdatedServiceCheckExists() throws AmbariException {
+    ServiceComponent serviceComponent = mock(ServiceComponent.class);
+    when(serviceComponent.isVersionAdvertised()).thenReturn(true);
+
+    when(service.getMaintenanceState()).thenReturn(MaintenanceState.OFF);
+    when(service.getServiceComponents()).thenReturn(ImmutableMap.of(SERVICE_COMPONENT_NAME, serviceComponent));
+
+    ServiceConfigEntity serviceConfigEntity = new ServiceConfigEntity();
+    serviceConfigEntity.setServiceName(SERVICE_NAME);
+    serviceConfigEntity.setCreateTimestamp(CONFIG_CREATE_TIMESTAMP);
+
+    HostRoleCommandEntity hostRoleCommandEntity = new HostRoleCommandEntity();
+    hostRoleCommandEntity.setRoleCommand(RoleCommand.SERVICE_CHECK);
+    hostRoleCommandEntity.setCommandDetail(COMMAND_DETAIL);
+    hostRoleCommandEntity.setStartTime(SERVICE_CHECK_START_TIME);
+
+    when(serviceConfigDAO.getLastServiceConfig(eq(CLUSTER_ID), eq(SERVICE_NAME))).thenReturn(serviceConfigEntity);
+    when(hostRoleCommandDAO.findAll(any(Request.class), isNull(Predicate.class))).thenReturn(singletonList(hostRoleCommandEntity));
+
+    PrerequisiteCheck check = new PrerequisiteCheck(null, CLUSTER_NAME);
+    serviceCheckValidityCheck.perform(check, new PrereqCheckRequest(CLUSTER_NAME));
+    Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
+  }
+}
\ No newline at end of file