Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SONAR-9741 check app nodes status in api/system/health
- Loading branch information
Showing
6 changed files
with
562 additions
and
41 deletions.
There are no files selected for viewing
112 changes: 112 additions & 0 deletions
112
server/sonar-server/src/main/java/org/sonar/server/health/AppNodeClusterCheck.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* SonarQube | ||
* Copyright (C) 2009-2017 SonarSource SA | ||
* mailto:info AT sonarsource DOT com | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License | ||
* along with this program; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
package org.sonar.server.health; | ||
|
||
import java.util.Arrays; | ||
import java.util.Set; | ||
import org.sonar.cluster.health.NodeDetails; | ||
import org.sonar.cluster.health.NodeHealth; | ||
|
||
import static org.sonar.cluster.health.NodeHealth.Status.GREEN; | ||
import static org.sonar.cluster.health.NodeHealth.Status.RED; | ||
import static org.sonar.cluster.health.NodeHealth.Status.YELLOW; | ||
import static org.sonar.core.util.stream.MoreCollectors.toSet; | ||
import static org.sonar.server.health.Health.newHealthCheckBuilder; | ||
|
||
public class AppNodeClusterCheck implements ClusterHealthCheck { | ||
|
||
@Override | ||
public Health check(Set<NodeHealth> nodeHealths) { | ||
Set<NodeHealth> appNodes = nodeHealths.stream() | ||
.filter(s -> s.getDetails().getType() == NodeDetails.Type.APPLICATION) | ||
.collect(toSet()); | ||
|
||
return Arrays.stream(AppNodeClusterHealthChecks.values()) | ||
.map(s -> s.check(appNodes)) | ||
.reduce(Health.GREEN, HealthReducer.INSTANCE); | ||
} | ||
|
||
private enum AppNodeClusterHealthChecks implements ClusterHealthCheck { | ||
NO_APPLICATION_NODE() { | ||
@Override | ||
public Health check(Set<NodeHealth> appNodes) { | ||
int appNodeCount = appNodes.size(); | ||
if (appNodeCount == 0) { | ||
return newHealthCheckBuilder() | ||
.setStatus(Health.Status.RED) | ||
.addCause("No application node") | ||
.build(); | ||
} | ||
return Health.GREEN; | ||
} | ||
}, | ||
MIN_APPLICATION_NODE_COUNT() { | ||
@Override | ||
public Health check(Set<NodeHealth> appNodes) { | ||
int appNodeCount = appNodes.size(); | ||
if (appNodeCount == 1) { | ||
return newHealthCheckBuilder() | ||
.setStatus(Health.Status.YELLOW) | ||
.addCause("There should be at least two application nodes") | ||
.build(); | ||
} | ||
return Health.GREEN; | ||
} | ||
}, | ||
REPORT_RED_OR_YELLOW_NODES() { | ||
@Override | ||
public Health check(Set<NodeHealth> appNodes) { | ||
int appNodeCount = appNodes.size(); | ||
if (appNodeCount == 0) { | ||
// skipping this check | ||
return Health.GREEN; | ||
} | ||
|
||
long redNodesCount = appNodes.stream().filter(s -> s.getStatus() == RED).count(); | ||
long yellowNodesCount = appNodes.stream().filter(s -> s.getStatus() == YELLOW).count(); | ||
if (redNodesCount == 0 && yellowNodesCount == 0) { | ||
return Health.GREEN; | ||
} | ||
|
||
Health.Builder builder = newHealthCheckBuilder(); | ||
if (redNodesCount == appNodeCount) { | ||
return builder | ||
.setStatus(Health.Status.RED) | ||
.addCause("Status of all application nodes is RED") | ||
.build(); | ||
} else if (redNodesCount > 0) { | ||
builder.addCause("At least one application node is RED"); | ||
} | ||
if (yellowNodesCount == appNodeCount) { | ||
return builder | ||
.setStatus(Health.Status.YELLOW) | ||
.addCause("Status of all application nodes is YELLOW") | ||
.build(); | ||
} else if (yellowNodesCount > 0) { | ||
builder.addCause("At least one application node is YELLOW"); | ||
} | ||
long greenNodesCount = appNodes.stream().filter(s -> s.getStatus() == GREEN).count(); | ||
builder.setStatus(greenNodesCount > 0 || yellowNodesCount > 0 ? Health.Status.YELLOW : Health.Status.RED); | ||
|
||
return builder.build(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
server/sonar-server/src/main/java/org/sonar/server/health/HealthReducer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* SonarQube | ||
* Copyright (C) 2009-2017 SonarSource SA | ||
* mailto:info AT sonarsource DOT com | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License | ||
* along with this program; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
package org.sonar.server.health; | ||
|
||
import java.util.function.BinaryOperator; | ||
import java.util.stream.Stream; | ||
|
||
import static org.sonar.server.health.Health.newHealthCheckBuilder; | ||
|
||
public enum HealthReducer implements BinaryOperator<Health> { | ||
INSTANCE; | ||
|
||
/** | ||
* According to Javadoc, {@link BinaryOperator} used in method | ||
* {@link java.util.stream.Stream#reduce(Object, BinaryOperator)} is supposed to be stateless. | ||
* | ||
* But as we are sure this {@link BinaryOperator} won't be used on a Stream with {@link Stream#parallel()} | ||
* feature on, we allow ourselves this optimisation. | ||
*/ | ||
private final Health.Builder builder = newHealthCheckBuilder(); | ||
|
||
@Override | ||
public Health apply(Health left, Health right) { | ||
builder.clear(); | ||
builder.setStatus(worseOf(left.getStatus(), right.getStatus())); | ||
left.getCauses().forEach(builder::addCause); | ||
right.getCauses().forEach(builder::addCause); | ||
return builder.build(); | ||
} | ||
|
||
private static Health.Status worseOf(Health.Status left, Health.Status right) { | ||
if (left == right) { | ||
return left; | ||
} | ||
if (left.ordinal() > right.ordinal()) { | ||
return left; | ||
} | ||
return right; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.