allow rerun of healthchecks

This commit is contained in:
Sebastian Sdorra
2014-01-25 15:00:04 +01:00
parent 9e9351fe86
commit 08dede40fe
8 changed files with 226 additions and 82 deletions

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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
*

View File

@@ -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
});
}

View File

@@ -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
});
}
});