You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/10/20 14:38:49 UTC
[sling-org-apache-sling-hc-support] 01/30: SLING-3127 - prepare
Health Check tools release
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-hc-support.git
commit 1cffc3b369990f2c6ea9226f78b550d55b620be7
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Thu Sep 26 13:17:13 2013 +0000
SLING-3127 - prepare Health Check tools release
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1526476 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 115 ++++++++
.../hc/support/impl/DefaultLoginsHealthCheck.java | 119 ++++++++
.../sling/hc/support/impl/InternalRequest.java | 319 +++++++++++++++++++++
.../sling/hc/support/impl/InternalResponse.java | 185 ++++++++++++
.../impl/SlingRequestStatusHealthCheck.java | 139 +++++++++
.../OSGI-INF/metatype/metatype.properties | 52 ++++
src/test/java/org/apache/sling/hc/healthcheck | 44 +++
.../healthchecks/DefaultLoginsHealthCheckTest.java | 70 +++++
.../org/apache/sling/hc/healthchecks/SetField.java | 30 ++
.../SlingRequestStatusHealthCheckTest.java | 96 +++++++
10 files changed, 1169 insertions(+)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ce31b77
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>17</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.hc.support</artifactId>
+ <packaging>bundle</packaging>
+ <version>0.0.2-SNAPSHOT</version>
+
+ <name>Sling Health Check Support Components</name>
+ <inceptionYear>2013</inceptionYear>
+
+ <description>
+ Default Sling Health Check Support Components
+ </description>
+
+ <properties>
+ <sling.java.version>6</sling.java.version>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.hc.core</artifactId>
+ <version>0.0.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.osgi</artifactId>
+ <version>2.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.api</artifactId>
+ <version>2.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.api</artifactId>
+ <version>2.0.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.engine</artifactId>
+ <version>2.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.2</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.6.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java b/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
new file mode 100644
index 0000000..adb2b23
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
@@ -0,0 +1,119 @@
+/*
+ * 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 SF 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.sling.hc.support.impl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.util.FormattingResultLog;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** {@link HealthCheck} that checks that Sling default logins fail.
+ * Used to verify that those logins are disabled on production systems */
+@Component(
+ name="org.apache.sling.hc.support.DefaultLoginsHealthCheck",
+ configurationFactory=true,
+ policy=ConfigurationPolicy.REQUIRE,
+ metatype=true)
+@Properties({
+ @Property(name=HealthCheck.NAME),
+ @Property(name=HealthCheck.TAGS, unbounded=PropertyUnbounded.ARRAY),
+ @Property(name=HealthCheck.MBEAN_NAME)
+})
+@Service(value=HealthCheck.class)
+public class DefaultLoginsHealthCheck implements HealthCheck {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Property(unbounded=PropertyUnbounded.ARRAY)
+ private static final String PROP_LOGINS = "logins";
+
+ private List<String> logins;
+
+ @Reference
+ private SlingRepository repository;
+
+ @Activate
+ public void activate(ComponentContext ctx) {
+ logins = Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get(PROP_LOGINS), new String[] {}));
+ log.info("Activated, logins={}", logins);
+ }
+
+ @Override
+ public Result execute() {
+ final FormattingResultLog resultLog = new FormattingResultLog();
+ int checked=0;
+ int failures=0;
+
+ for(String login : logins) {
+ final String [] parts = login.split(":");
+ if(parts.length != 2) {
+ resultLog.warn("Expected login in the form username:password, got [{}]", login);
+ continue;
+ }
+ checked++;
+ final String username = parts[0].trim();
+ final String password = parts[1].trim();
+ final Credentials creds = new SimpleCredentials(username, password.toCharArray());
+ Session s = null;
+ try {
+ s = repository.login(creds);
+ if(s != null) {
+ failures++;
+ resultLog.warn("Login as [{}] succeeded, was expecting it to fail", username);
+ } else {
+ resultLog.debug("Login as [{}] didn't throw an Exception but returned null Session", username);
+ }
+ } catch(RepositoryException re) {
+ resultLog.debug("Login as [{}] failed, as expected", username);
+ } finally {
+ if(s != null) {
+ s.logout();
+ }
+ }
+ }
+
+ if(checked==0) {
+ resultLog.warn("Did not check any logins, configured logins={}", logins);
+ } else if(failures != 0){
+ resultLog.warn("Checked {} logins, {} failures", checked, failures);
+ } else {
+ resultLog.debug("Checked {} logins, all successful", checked, failures);
+ }
+ return new Result(resultLog);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java b/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java
new file mode 100644
index 0000000..b79fdfe
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java
@@ -0,0 +1,319 @@
+/*
+ * 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 SF 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.sling.hc.support.impl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+public class InternalRequest implements HttpServletRequest {
+
+ private final String path;
+ private final Map<String, Object> attributes = new HashMap<String, Object>();
+
+ public InternalRequest(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public Object getAttribute(String key) {
+ return attributes.get(key);
+ }
+
+ @Override
+ public Enumeration<?> getAttributeNames() {
+ return new Vector<String>(attributes.keySet()).elements();
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return "UTF-8";
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/plain";
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return new ServletInputStream() {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+ };
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return "127.0.0.1";
+ }
+
+ @Override
+ public String getLocalName() {
+ return "localhost";
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return Locale.getDefault();
+ }
+
+ @Override
+ public Enumeration<?> getLocales() {
+ return new Vector<Locale>().elements();
+ }
+
+ @Override
+ public String getParameter(String arg0) {
+ return null;
+ }
+
+ @Override
+ public Map<?,?> getParameterMap() {
+ return new HashMap<String, Object>();
+ }
+
+ @Override
+ public Enumeration<?> getParameterNames() {
+ return new Vector<String>().elements();
+ }
+
+ @Override
+ public String[] getParameterValues(String arg0) {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return "http";
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return new BufferedReader(new StringReader(""));
+ }
+
+ @Override
+ public String getRealPath(String arg0) {
+ return path;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return "127.0.0.1";
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return "localhost";
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 1234;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String arg0) {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return "http";
+ }
+
+ @Override
+ public String getServerName() {
+ return "localhost";
+ }
+
+ @Override
+ public int getServerPort() {
+ return 80;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public void removeAttribute(String arg0) {
+ }
+
+ @Override
+ public void setAttribute(String key, Object value) {
+ attributes.put(key, value);
+ }
+
+ @Override
+ public void setCharacterEncoding(String arg0)
+ throws UnsupportedEncodingException {
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return "";
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return null;
+ }
+
+ @Override
+ public long getDateHeader(String arg0) {
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String arg0) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<?> getHeaderNames() {
+ return new Vector<String>().elements();
+ }
+
+ @Override
+ public Enumeration<?> getHeaders(String arg0) {
+ return new Vector<String>().elements();
+ }
+
+ @Override
+ public int getIntHeader(String arg0) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return "GET";
+ }
+
+ @Override
+ public String getPathInfo() {
+ return path;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return path;
+ }
+
+ @Override
+ public String getQueryString() {
+ return "";
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return "remoteuser";
+ }
+
+ @Override
+ public String getRequestURI() {
+ return "http://localhost" + path;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return new StringBuffer(getRequestURI());
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return "";
+ }
+
+ @Override
+ public String getServletPath() {
+ return "";
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean arg0) {
+ return null;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isUserInRole(String arg0) {
+ return false;
+ }
+}
diff --git a/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java b/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java
new file mode 100644
index 0000000..8752628
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java
@@ -0,0 +1,185 @@
+/*
+ * 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 SF 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.sling.hc.support.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+public class InternalResponse implements HttpServletResponse {
+
+ private int status = 200;
+
+ private static class DevNullOutputStream extends ServletOutputStream {
+ @Override
+ public void write(int b) {
+ }
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {
+ }
+
+ @Override
+ public int getBufferSize() {
+ return 0;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return "UTF-8";
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/plain";
+ }
+
+ @Override
+ public Locale getLocale() {
+ return Locale.getDefault();
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return new DevNullOutputStream();
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return new PrintWriter(new DevNullOutputStream());
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return false;
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void resetBuffer() {
+ }
+
+ @Override
+ public void setBufferSize(int arg0) {
+ }
+
+ @Override
+ public void setCharacterEncoding(String arg0) {
+ }
+
+ @Override
+ public void setContentLength(int arg0) {
+ }
+
+ @Override
+ public void setContentType(String arg0) {
+ }
+
+ @Override
+ public void setLocale(Locale arg0) {
+ }
+
+ @Override
+ public void addCookie(Cookie arg0) {
+ }
+
+ @Override
+ public void addDateHeader(String arg0, long arg1) {
+ }
+
+ @Override
+ public void addHeader(String arg0, String arg1) {
+ }
+
+ @Override
+ public void addIntHeader(String arg0, int arg1) {
+ }
+
+ @Override
+ public boolean containsHeader(String arg0) {
+ return false;
+ }
+
+ @Override
+ public String encodeRedirectURL(String url) {
+ return url;
+ }
+
+ @Override
+ public String encodeRedirectUrl(String url) {
+ return url;
+ }
+
+ @Override
+ public String encodeURL(String url) {
+ return url;
+ }
+
+ @Override
+ public String encodeUrl(String url) {
+ return url;
+ }
+
+ @Override
+ public void sendError(int s, String arg1) throws IOException {
+ status = s;
+ }
+
+ @Override
+ public void sendError(int s) throws IOException {
+ status = s;
+ }
+
+ @Override
+ public void sendRedirect(String arg0) throws IOException {
+ }
+
+ @Override
+ public void setDateHeader(String arg0, long arg1) {
+ }
+
+ @Override
+ public void setHeader(String arg0, String arg1) {
+ }
+
+ @Override
+ public void setIntHeader(String arg0, int arg1) {
+ }
+
+ @Override
+ public void setStatus(int s, String arg1) {
+ status = s;
+ }
+
+ @Override
+ public void setStatus(int s) {
+ status = s;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+}
diff --git a/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java b/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
new file mode 100644
index 0000000..968174e
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
@@ -0,0 +1,139 @@
+/*
+ * 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 SF 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.sling.hc.support.impl;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.util.FormattingResultLog;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** {@link HealthCheck} that checks the HTTP status of Sling requests.
+ * Typically used to check that a freshly installed Sling-based system
+ * is in good shape, contains all required content etc. */
+@Component(
+ name="org.apache.sling.hc.support.SlingRequestStatusHealthCheck",
+ configurationFactory=true,
+ policy=ConfigurationPolicy.REQUIRE,
+ metatype=true)
+@Properties({
+ @Property(name=HealthCheck.NAME),
+ @Property(name=HealthCheck.TAGS, unbounded=PropertyUnbounded.ARRAY),
+ @Property(name=HealthCheck.MBEAN_NAME)
+})
+@Service(value=HealthCheck.class)
+public class SlingRequestStatusHealthCheck implements HealthCheck {
+
+ private static final Logger log = LoggerFactory.getLogger(SlingRequestStatusHealthCheck.class);
+ private String [] paths;
+
+ static class PathSpec {
+ int status;
+ String path;
+
+ PathSpec(String configuredPath, FormattingResultLog resultLog) {
+ path = configuredPath;
+ status = 200;
+
+ final String [] parts = configuredPath.split(":");
+ if(parts.length == 2) {
+ try {
+ status = Integer.valueOf(parts[1].trim());
+ path = parts[0].trim();
+ } catch(NumberFormatException nfe) {
+ resultLog.healthCheckError("NumberFormatException while parsing [{}], invalid status value?", configuredPath);
+ }
+ }
+ }
+ }
+
+ @Property(unbounded=PropertyUnbounded.ARRAY)
+ private static final String PROP_PATH = "path";
+
+ @Reference
+ private SlingRequestProcessor requestProcessor;
+
+ @Reference
+ private ResourceResolverFactory resolverFactory;
+
+ @Activate
+ public void activate(final Map<String, Object> properties) {
+ paths = PropertiesUtil.toStringArray(properties.get(PROP_PATH), new String [] {});
+ log.info("Activated, paths={}", Arrays.asList(paths));
+ }
+
+ @Override
+ public Result execute() {
+ final FormattingResultLog resultLog = new FormattingResultLog();
+
+ ResourceResolver resolver = null;
+ int checked = 0;
+ int failed = 0;
+ String lastPath = null;
+
+ try {
+ resolver = resolverFactory.getAdministrativeResourceResolver(null);
+ for(String p : paths) {
+ lastPath = p;
+ final PathSpec ps = new PathSpec(p, resultLog);
+ final HttpServletRequest request = new InternalRequest(ps.path);
+ final InternalResponse response = new InternalResponse();
+ requestProcessor.processRequest(request, response, resolver);
+ final int status = response.getStatus();
+ if(status != ps.status) {
+ failed++;
+ resultLog.warn("[{}] returns status {}, expected {}", new Object[] { ps.path, status, ps.status });
+ } else {
+ resultLog.debug("[{}] returns status {} as expected", ps.path, status);
+ }
+ checked++;
+ }
+ } catch(Exception e) {
+ resultLog.warn("Exception while executing request [{}]: {}", lastPath, e);
+ } finally {
+ if(resolver != null) {
+ resolver.close();
+ }
+ }
+
+ if(checked == 0) {
+ resultLog.warn("No paths checked, empty paths list?");
+ } else {
+ resultLog.debug("{} paths checked, {} failures", checked, failed);
+ }
+
+ return new Result(resultLog);
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..193b63b
--- /dev/null
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor generated by the
+# the Sling SCR plugin
+
+org.apache.sling.hc.DefaultLoginsHealthCheck.name = Apache Sling Default Logins Health Check
+org.apache.sling.hc.DefaultLoginsHealthCheck.description = Expects default logins to fail, used to verify \
+ that they are disabled on production systems
+
+org.apache.sling.hc.SlingRequestStatusHealthCheck.name = Apache Sling Sling Request Status Health Check
+org.apache.sling.hc.SlingRequestStatusHealthCheck.description = Checks the HTTP status of Sling requests.
+
+hc.mbean.name.name = MBean name
+hc.mbean.name.description = Name of the MBean to create for this Health Check.
+
+hc.tags.name = Health Check tags
+hc.tags.description = List of tags for this Health Check service, used to select \
+ subsets of Health Check services for execution.
+
+hc.name.name = Health Check Name
+hc.name.description = Name of this Health Check service. Used for the MBean that's created \
+ for this Health Check as well, unless a specific MBean name is configured.
+
+logins.name = Login credentials
+logins.description = Which credentials to check. Each one is in the format "user:password" \
+ like "admin:admin" for example. Do *not* put any confidential passwords here, the goal \
+ is just to check that the default/demo logins, which passwords are known anyway, are \
+ disabled.
+
+path.name = Paths to check
+path.description = The list of paths to check, optionally with expected HTTP status responses. \
+ An entry like "/tmp/test.txt:301", for example, checks that /tmp/test.txt returns a \
+ 301 response.
diff --git a/src/test/java/org/apache/sling/hc/healthcheck b/src/test/java/org/apache/sling/hc/healthcheck
new file mode 100644
index 0000000..954f535
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/healthcheck
@@ -0,0 +1,44 @@
+package org.apache.sling.hc.impl.healthchecks;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class PathSpecTest {
+ private final String pathSpec;
+ private final String expectedPath;
+ private final int expectedStatus;
+
+ @Parameters(name="{1}")
+ public static List<Object[]> data() {
+ final List<Object[]> result = new ArrayList<Object[]>();
+
+ result.add(new Object[] { "/one.html", "/one.html", 200 } );
+ result.add(new Object[] { "/two.html:404", "/two.html", 404 } );
+ result.add(new Object[] { "three.html : 404 ", "three.html", 404 } );
+ result.add(new Object[] { "four.html:not an integer", "four.html:not an integer", 200 } );
+ result.add(new Object[] { "", "", 200 } );
+
+ return result;
+ }
+
+ public PathSpecTest(String pathSpec, String expectedPath, int expectedStatus) {
+ this.pathSpec = pathSpec;
+ this.expectedPath = expectedPath;
+ this.expectedStatus = expectedStatus;
+ }
+
+ @Test
+ public void testParsing() {
+ final SlingRequestStatusHealthCheck.PathSpec ps = new SlingRequestStatusHealthCheck.PathSpec(pathSpec);
+ assertEquals(expectedPath, ps.path);
+ assertEquals(expectedStatus, ps.status);
+ }
+}
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java b/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
new file mode 100644
index 0000000..862b6f8
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 SF 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.sling.hc.healthchecks;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import javax.jcr.Credentials;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.support.impl.DefaultLoginsHealthCheck;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class DefaultLoginsHealthCheckTest {
+
+ private Result getTestResult(String login) throws Exception {
+ final DefaultLoginsHealthCheck c = new DefaultLoginsHealthCheck();
+ SetField.set(c, "logins", Arrays.asList(new String[] { login }));
+
+ final SlingRepository repo = Mockito.mock(SlingRepository.class);
+ SetField.set(c, "repository", repo);
+ final Session s = Mockito.mock(Session.class);
+ Mockito.when(repo.login(Matchers.any(Credentials.class))).thenAnswer(new Answer<Session>() {
+ @Override
+ public Session answer(InvocationOnMock invocation) {
+ final SimpleCredentials c = (SimpleCredentials)invocation.getArguments()[0];
+ if("admin".equals(c.getUserID())) {
+ return s;
+ }
+ return null;
+ }
+ });
+
+ return c.execute();
+ }
+
+ @Test
+ public void testHealthCheckFails() throws Exception {
+ assertFalse("Expecting failed check", getTestResult("admin:admin").isOk());
+ }
+
+ @Test
+ public void testHealthCheckSucceeds() throws Exception {
+ assertTrue("Expecting successful check", getTestResult("FOO:bar").isOk());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/SetField.java b/src/test/java/org/apache/sling/hc/healthchecks/SetField.java
new file mode 100644
index 0000000..c4577a3
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/healthchecks/SetField.java
@@ -0,0 +1,30 @@
+/*
+ * 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 SF 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.sling.hc.healthchecks;
+
+import java.lang.reflect.Field;
+
+public class SetField {
+
+ public static void set(Object o, String name, Object value) throws Exception {
+ final Field f = o.getClass().getDeclaredField(name);
+ f.setAccessible(true);
+ f.set(o, value);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java b/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
new file mode 100644
index 0000000..6731465
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
@@ -0,0 +1,96 @@
+package org.apache.sling.hc.healthchecks;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.support.impl.SlingRequestStatusHealthCheck;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@RunWith(Parameterized.class)
+public class SlingRequestStatusHealthCheckTest {
+ private SlingRequestStatusHealthCheck hc;
+ private final Result.Status expectedStatus;
+ private final String [] paths;
+
+ @Parameters(name="{0}")
+ public static List<Object[]> data() {
+ final List<Object[]> result = new ArrayList<Object[]>();
+ result.add(new Object[] { "200.html:200,502.html:1234,436.json:436", Result.Status.WARN });
+
+ result.add(new Object[] { "", Result.Status.OK });
+ result.add(new Object[] { "200.x", Result.Status.OK });
+ result.add(new Object[] { "404.html:404", Result.Status.OK });
+ result.add(new Object[] { "200.html:200,502.html:502,436.json:436" , Result.Status.OK });
+ result.add(new Object[] { "200.html:1234,502.html:502,436.json:436" , Result.Status.WARN });
+ result.add(new Object[] { "200.html:200,502.html:1234,436.json:436" , Result.Status.WARN });
+ result.add(new Object[] { "200.html:200,502.html:502,436.json:1234" , Result.Status.WARN });
+ result.add(new Object[] { "200.html:1234,502.html:1234,436.json:1234" , Result.Status.WARN });
+ return result;
+ }
+
+ @Before
+ public void setup() throws Exception {
+ hc = new SlingRequestStatusHealthCheck();
+
+ final ResourceResolverFactory rrf = Mockito.mock(ResourceResolverFactory.class);
+ SetField.set(hc, "resolverFactory", rrf);
+
+ final Answer<Void> a = new Answer<Void> () {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ final HttpServletRequest request = (HttpServletRequest)invocation.getArguments()[0];
+ final HttpServletResponse response = (HttpServletResponse)invocation.getArguments()[1];
+ final String path = request.getPathInfo();
+ if(path.length() > 0) {
+ final String status = path.substring(0, path.indexOf('.'));
+ response.setStatus(Integer.valueOf(status));
+ }
+ return null;
+ }
+
+ };
+
+ final SlingRequestProcessor srp = Mockito.mock(SlingRequestProcessor.class);
+ SetField.set(hc, "requestProcessor", srp);
+ Mockito.doAnswer(a).when(srp).processRequest(
+ Matchers.any(HttpServletRequest.class),
+ Matchers.any(HttpServletResponse.class),
+ Matchers.any(ResourceResolver.class));
+
+
+ final Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put("path", paths);
+ hc.activate(properties);
+ }
+
+ public SlingRequestStatusHealthCheckTest(String paths, Result.Status expectedStatus) {
+ this.paths = paths.split(",");
+ this.expectedStatus = expectedStatus;
+
+ }
+
+ @Test
+ public void testResult() {
+ assertEquals("Expecting result " + expectedStatus + " for paths=" + paths,
+ expectedStatus, hc.execute().getStatus());
+ }
+}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.