mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 15:05:44 +01:00
allow rerun of healthchecks
This commit is contained in:
@@ -31,9 +31,13 @@
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.plugin.ExtensionPoint;
|
||||
|
||||
/**
|
||||
* Repository health check. Executes a check to verify the health
|
||||
* state of a repository.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.36
|
||||
@@ -43,12 +47,12 @@ public interface HealthCheck
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns the result of the repository health check.
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
* @param repository repository to check
|
||||
*
|
||||
* @return
|
||||
* @return result of the health check
|
||||
*/
|
||||
public HealthCheckResult check(Repository repository);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* Single failure of a {@link HealthCheck}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.36
|
||||
@@ -52,17 +53,18 @@ public final class HealthCheckFailure
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new {@link HealthCheckFailure}.
|
||||
* This constructor is only for JAXB.
|
||||
*
|
||||
*/
|
||||
HealthCheckFailure() {}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new {@link HealthCheckFailure}.
|
||||
*
|
||||
* @param id
|
||||
* @param summary
|
||||
* @param description
|
||||
* @param id id of the failure
|
||||
* @param summary summary of the failure
|
||||
* @param description description of the failure
|
||||
*/
|
||||
public HealthCheckFailure(String id, String summary, String description)
|
||||
{
|
||||
@@ -72,10 +74,10 @@ public final class HealthCheckFailure
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
* @param id
|
||||
* @param summary
|
||||
* @param url
|
||||
* @param description
|
||||
* @param id id of the failure
|
||||
* @param summary summary of the failure
|
||||
* @param url url of the failure
|
||||
* @param description description of the failure
|
||||
*/
|
||||
public HealthCheckFailure(String id, String summary, String url,
|
||||
String description)
|
||||
@@ -89,12 +91,7 @@ public final class HealthCheckFailure
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param obj
|
||||
*
|
||||
* @return
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
@@ -120,10 +117,7 @@ public final class HealthCheckFailure
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
@@ -132,10 +126,7 @@ public final class HealthCheckFailure
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
@@ -153,10 +144,9 @@ public final class HealthCheckFailure
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns the description of this failure.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return description of this failure
|
||||
*/
|
||||
public String getDescription()
|
||||
{
|
||||
@@ -164,10 +154,9 @@ public final class HealthCheckFailure
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns the id of this failure.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return id of this failure
|
||||
*/
|
||||
public String getId()
|
||||
{
|
||||
@@ -175,10 +164,9 @@ public final class HealthCheckFailure
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns the summary of the failure.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return summary of the failure
|
||||
*/
|
||||
public String getSummary()
|
||||
{
|
||||
@@ -186,10 +174,9 @@ public final class HealthCheckFailure
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Return the url of the failure.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return url of the failure
|
||||
*/
|
||||
public String getUrl()
|
||||
{
|
||||
@@ -198,15 +185,15 @@ public final class HealthCheckFailure
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
/** description of failure */
|
||||
private String description;
|
||||
|
||||
/** Field description */
|
||||
/** id of failure */
|
||||
private String id;
|
||||
|
||||
/** Field description */
|
||||
/** summary of failure */
|
||||
private String summary;
|
||||
|
||||
/** Field description */
|
||||
/** url of failure */
|
||||
private String url;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
@@ -40,6 +41,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Result of {@link HealthCheck}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.36
|
||||
@@ -47,7 +49,7 @@ import java.util.Set;
|
||||
public final class HealthCheckResult
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
/** healthy result */
|
||||
private static final HealthCheckResult HEALTHY =
|
||||
new HealthCheckResult(ImmutableSet.<HealthCheckFailure>of());
|
||||
|
||||
@@ -67,10 +69,9 @@ public final class HealthCheckResult
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns a {@link HealthCheckResult} for a healthy repository.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return {@link HealthCheckResult} for a healthy repository
|
||||
*/
|
||||
public static HealthCheckResult healthy()
|
||||
{
|
||||
@@ -78,12 +79,12 @@ public final class HealthCheckResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns a {@link HealthCheckResult} for a unhealthy repository.
|
||||
*
|
||||
*
|
||||
* @param failures
|
||||
* @param failures failures of failed {@link HealthCheck}s
|
||||
*
|
||||
* @return
|
||||
* @return {@link HealthCheckResult} for a unhealthy repository
|
||||
*/
|
||||
public static HealthCheckResult unhealthy(
|
||||
Iterable<HealthCheckFailure> failures)
|
||||
@@ -92,13 +93,13 @@ public final class HealthCheckResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns a {@link HealthCheckResult} for a unhealthy repository.
|
||||
*
|
||||
*
|
||||
* @param failure
|
||||
* @param otherFailures
|
||||
* @param failure failure of {@link HealthCheck}
|
||||
* @param otherFailures failures of failed {@link HealthCheck}s
|
||||
*
|
||||
* @return
|
||||
* @return {@link HealthCheckResult} for a unhealthy repository
|
||||
*/
|
||||
public static HealthCheckResult unhealthy(HealthCheckFailure failure,
|
||||
HealthCheckFailure... otherFailures)
|
||||
@@ -114,12 +115,43 @@ public final class HealthCheckResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final HealthCheckResult other = (HealthCheckResult) obj;
|
||||
|
||||
return Objects.equal(failures, other.failures);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(failures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge this {@link HealthCheckResult} with another
|
||||
* {@link HealthCheckResult}.
|
||||
*
|
||||
*
|
||||
* @param otherResult
|
||||
* @param otherResult result to merge with
|
||||
*
|
||||
* @return
|
||||
* @return merged {@link HealthCheckResult}
|
||||
*/
|
||||
public HealthCheckResult merge(HealthCheckResult otherResult)
|
||||
{
|
||||
@@ -144,13 +176,22 @@ public final class HealthCheckResult
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return Objects.toStringHelper(this).add("failures", failures).toString();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns a {@link Set} of {@link HealthCheckFailure}s. The set is empty if
|
||||
* the repository is healthy.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return {@link Set} of {@link HealthCheckFailure}s
|
||||
*/
|
||||
public Set<HealthCheckFailure> getFailures()
|
||||
{
|
||||
@@ -158,10 +199,9 @@ public final class HealthCheckResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns {@code true} if the result is healthy.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return {@code true} if the result is healthy
|
||||
*/
|
||||
public boolean isHealthy()
|
||||
{
|
||||
@@ -169,10 +209,9 @@ public final class HealthCheckResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns {@code true} if the result is unhealthy
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return {@code true} if the result is unhealthy.
|
||||
*/
|
||||
public boolean isUnhealthy()
|
||||
{
|
||||
@@ -181,6 +220,6 @@ public final class HealthCheckResult
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
/** set of failures */
|
||||
private final Set<HealthCheckFailure> failures;
|
||||
}
|
||||
|
||||
@@ -304,10 +304,11 @@ public class Repository extends BasicPropertiesAware implements ModelObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns a {@link List} of {@link HealthCheckFailure}s. The {@link List}
|
||||
* is empty if the repository is healthy.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return {@link List} of {@link HealthCheckFailure}s
|
||||
* @since 1.36
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -410,10 +411,10 @@ public class Repository extends BasicPropertiesAware implements ModelObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns {@code true} if the repository is healthy.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return {@code true} if the repository is healthy
|
||||
*
|
||||
* @since 1.36
|
||||
*/
|
||||
@@ -581,10 +582,10 @@ public class Repository extends BasicPropertiesAware implements ModelObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Sets {@link HealthCheckFailure} for a unhealthy repository.
|
||||
*
|
||||
*
|
||||
* @param healthCheckFailures
|
||||
* @param healthCheckFailures list of {@link HealthCheckFailure}s
|
||||
*
|
||||
* @since 1.36
|
||||
*/
|
||||
|
||||
@@ -54,6 +54,7 @@ import sonia.scm.repository.Branches;
|
||||
import sonia.scm.repository.BrowserResult;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.HealthChecker;
|
||||
import sonia.scm.repository.Permission;
|
||||
import sonia.scm.repository.PermissionType;
|
||||
import sonia.scm.repository.Repository;
|
||||
@@ -131,16 +132,18 @@ public class RepositoryResource
|
||||
* @param configuration
|
||||
* @param repositoryManager
|
||||
* @param servicefactory
|
||||
* @param healthChecker
|
||||
*/
|
||||
@Inject
|
||||
public RepositoryResource(ScmConfiguration configuration,
|
||||
RepositoryManager repositoryManager,
|
||||
RepositoryServiceFactory servicefactory)
|
||||
RepositoryServiceFactory servicefactory, HealthChecker healthChecker)
|
||||
{
|
||||
super(repositoryManager);
|
||||
this.configuration = configuration;
|
||||
this.repositoryManager = repositoryManager;
|
||||
this.servicefactory = servicefactory;
|
||||
this.healthChecker = healthChecker;
|
||||
setDisableCache(false);
|
||||
}
|
||||
|
||||
@@ -213,7 +216,7 @@ public class RepositoryResource
|
||||
}
|
||||
catch (ScmSecurityException ex)
|
||||
{
|
||||
logger.warn("delete not allowd", ex);
|
||||
logger.warn("delete not allowed", ex);
|
||||
response = Response.status(Response.Status.FORBIDDEN).build();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -231,6 +234,50 @@ public class RepositoryResource
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re run repository health checks.<br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 re run success</li>
|
||||
* <li>403 forbidden, the current user has no owner privileges</li>
|
||||
* <li>404 could not find repository</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param id id of the repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@Path("{id}/healthcheck")
|
||||
public Response runHealthChecks(@PathParam("id") String id)
|
||||
{
|
||||
Response response;
|
||||
|
||||
try
|
||||
{
|
||||
healthChecker.check(id);
|
||||
response = Response.ok().build();
|
||||
}
|
||||
catch (RepositoryNotFoundException ex)
|
||||
{
|
||||
logger.warn("could not find repository ".concat(id), ex);
|
||||
response = Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
catch (RepositoryException ex)
|
||||
{
|
||||
logger.error("error occured during health check", ex);
|
||||
response = Response.serverError().build();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("error occured during health check", ex);
|
||||
response = Response.serverError().build();
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the given repository.<br />
|
||||
* This method requires owner privileges.<br />
|
||||
@@ -1138,6 +1185,9 @@ public class RepositoryResource
|
||||
/** Field description */
|
||||
private final ScmConfiguration configuration;
|
||||
|
||||
/** Field description */
|
||||
private final HealthChecker healthChecker;
|
||||
|
||||
/** Field description */
|
||||
private final RepositoryManager repositoryManager;
|
||||
|
||||
|
||||
@@ -81,6 +81,33 @@ public final class HealthChecker
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
* @throws RepositoryNotFoundException
|
||||
*/
|
||||
public void check(String id)
|
||||
throws RepositoryNotFoundException, RepositoryException, IOException
|
||||
{
|
||||
SecurityUtils.getSubject().checkRole(Role.ADMIN);
|
||||
|
||||
Repository repository = repositoryManager.get(id);
|
||||
|
||||
if (repository == null)
|
||||
{
|
||||
throw new RepositoryNotFoundException(
|
||||
"could not find repository with id ".concat(id));
|
||||
}
|
||||
|
||||
check(repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -456,6 +456,8 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
|
||||
if (admin && item.healthCheckFailures && item.healthCheckFailures.length > 0){
|
||||
panels.push({
|
||||
xtype: 'repositoryHealthCheckFailurePanel',
|
||||
grid: this,
|
||||
repository: item,
|
||||
healthCheckFailures: item.healthCheckFailures
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,17 +35,24 @@ Sonia.repository.HealthCheckFailure = Ext.extend(Ext.Panel, {
|
||||
title: 'Health check',
|
||||
linkTemplate: '<a target="_blank" href="{0}">{0}</a>',
|
||||
|
||||
errorTitleText: 'Error',
|
||||
errorDescriptionText: 'Could not execute health check.',
|
||||
|
||||
initComponent: function(){
|
||||
var items = [];
|
||||
|
||||
if ( this.healthCheckFailures && this.healthCheckFailures.length > 0 ){
|
||||
for (var i=0; i<this.healthCheckFailures.length; i++){
|
||||
if (i>0){
|
||||
this.appendSpacer(items);
|
||||
}
|
||||
this.appendHealthCheckFailures(items,this.healthCheckFailures[i]);
|
||||
}
|
||||
}
|
||||
items.push({
|
||||
xtype: 'link',
|
||||
style: 'font-weight: bold',
|
||||
text: 'rerun health checks',
|
||||
handler: this.rerunHealthChecks,
|
||||
scope: this
|
||||
});
|
||||
|
||||
var config = {
|
||||
title: this.title,
|
||||
@@ -67,12 +74,34 @@ Sonia.repository.HealthCheckFailure = Ext.extend(Ext.Panel, {
|
||||
Sonia.repository.HealthCheckFailure.superclass.initComponent.apply(this, arguments);
|
||||
},
|
||||
|
||||
appendSpacer: function(items){
|
||||
items.push({
|
||||
xtype: 'box',
|
||||
height: 10,
|
||||
colspan: 2
|
||||
rerunHealthChecks: function(){
|
||||
var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck.json';
|
||||
var el = this.el;
|
||||
var tid = setTimeout( function(){el.mask('Loading ...');}, 100);
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: url,
|
||||
method: 'POST',
|
||||
scope: this,
|
||||
success: function(){
|
||||
clearTimeout(tid);
|
||||
this.grid.reload(function(){
|
||||
this.grid.selectById(this.repository.id);
|
||||
}, this);
|
||||
el.unmask();
|
||||
},
|
||||
failure: function(result){
|
||||
clearTimeout(tid);
|
||||
el.unmask();
|
||||
main.handleFailure(
|
||||
result.status,
|
||||
this.errorTitleText,
|
||||
this.errorDescriptionText
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
this.grid.reload();
|
||||
},
|
||||
|
||||
appendHealthCheckFailures: function(items, hcf){
|
||||
@@ -101,6 +130,11 @@ Sonia.repository.HealthCheckFailure = Ext.extend(Ext.Panel, {
|
||||
text: hcf.description
|
||||
});
|
||||
}
|
||||
items.push({
|
||||
xtype: 'box',
|
||||
height: 10,
|
||||
colspan: 2
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user