SLIDER-907 AgentWebPagesIT#testAgentWeb fails on wire encrypted clusters
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/ab2193c8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/ab2193c8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/ab2193c8 Branch: refs/heads/develop Commit: ab2193c811a9b5f225a0c89d0e16c08f7a094129 Parents: 5cee238 Author: Steve Loughran <[email protected]> Authored: Tue Jun 30 16:11:27 2015 +0100 Committer: Steve Loughran <[email protected]> Committed: Tue Jun 30 16:11:27 2015 +0100 ---------------------------------------------------------------------- .../restclient/UrlConnectionOperations.java | 5 +- .../agent/rest/JerseyTestDelegates.groovy | 28 ++++++++++ .../funtest/framework/CommandTestBase.groovy | 51 ++++++++++++++++- .../funtest/lifecycle/AgentWebPagesIT.groovy | 59 ++++++++++++-------- 4 files changed, 117 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/ab2193c8/slider-core/src/main/java/org/apache/slider/core/restclient/UrlConnectionOperations.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/core/restclient/UrlConnectionOperations.java b/slider-core/src/main/java/org/apache/slider/core/restclient/UrlConnectionOperations.java index e0d2315..20ef198 100644 --- a/slider-core/src/main/java/org/apache/slider/core/restclient/UrlConnectionOperations.java +++ b/slider-core/src/main/java/org/apache/slider/core/restclient/UrlConnectionOperations.java @@ -30,6 +30,7 @@ import org.apache.hadoop.yarn.webapp.NotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -142,12 +143,14 @@ public class UrlConnectionOperations extends Configured { log.debug("No body in response"); } + } catch (SSLException e) { + throw e; } catch (IOException e) { throw NetUtils.wrapException(url.toString(), url.getPort(), "localhost", 0, e); } catch (AuthenticationException e) { - throw new IOException("From " + url + ": " + e, e); + throw new AuthenticationException("From " + url + ": " + e, e); } finally { if (conn != null) { http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/ab2193c8/slider-core/src/test/groovy/org/apache/slider/agent/rest/JerseyTestDelegates.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/rest/JerseyTestDelegates.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/rest/JerseyTestDelegates.groovy index 5eb14e3..857d15c 100644 --- a/slider-core/src/test/groovy/org/apache/slider/agent/rest/JerseyTestDelegates.groovy +++ b/slider-core/src/test/groovy/org/apache/slider/agent/rest/JerseyTestDelegates.groovy @@ -36,7 +36,9 @@ import org.apache.slider.core.conf.ConfTreeOperations import org.apache.slider.core.restclient.HttpVerb import org.apache.slider.server.appmaster.web.rest.application.ApplicationResource import org.apache.slider.api.types.PingInformation +import org.apache.slider.test.Outcome +import javax.net.ssl.SSLException import javax.ws.rs.core.MediaType import static org.apache.slider.api.ResourceKeys.COMPONENT_INSTANCES @@ -479,4 +481,30 @@ class JerseyTestDelegates extends AbstractRestTestDelegate { testPing(); } + /** + * Probe callback for is the web service live; currently + * checks the "/system/health" path. + * Raising an SSL exception is considered a sign of liveness. + * @param args args: ignored + * @return the outcome + */ + Outcome probeServiceLive(Map<String, String> args) { + try { + jerseyGet(SYSTEM_HEALTHCHECK) + return Outcome.Success + } catch (SSLException e) { + // SSL exception => success + return Outcome.Success + } catch (IOException e) { + def cause = e.getCause() + if (cause && cause instanceof SSLException) { + // nested SSL exception => success + return Outcome.Success + } + // any other IOE is a retry + return Outcome.Retry + } + } + + } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/ab2193c8/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy ---------------------------------------------------------------------- diff --git a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy index edc4826..4c02289 100644 --- a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy +++ b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy @@ -48,6 +48,9 @@ import org.junit.Rule import org.junit.rules.Timeout import org.slf4j.Logger import org.slf4j.LoggerFactory + +import javax.net.ssl.SSLException + import static org.apache.slider.common.SliderExitCodes.* import static org.apache.slider.core.main.LauncherExitCodes.* import static org.apache.slider.funtest.framework.FuntestProperties.* @@ -1463,7 +1466,8 @@ abstract class CommandTestBase extends SliderTestUtils { } /** - * Probe callback for is the the app root web page up + * Probe callback for is the the app root web page up. + * Having a securty exception is in fact legit. * @param args map where 'applicationId' must be set * @return the outcome */ @@ -1480,6 +1484,12 @@ abstract class CommandTestBase extends SliderTestUtils { try { getWebPage(sar.url) return Outcome.Success + } catch (SSLException e) { + // SSL exception -implies negotiation failure. At this point there is clearly something + // at the far end -we just don't have the credentials to trust it. + return Outcome.Success; + } catch (IOException e) { + return Outcome.Retry; } catch (Exception e) { return Outcome.Retry; } @@ -1511,4 +1521,43 @@ abstract class CommandTestBase extends SliderTestUtils { getWebPage(sar.url) } } + + /** + * Probe callback for the the app root web page up. + * Raising an SSL exception is considered a sign of liveness. + * @param args map where 'applicationId' must be set + * @return the outcome + */ + protected static Outcome isApplicationURLPublished( + Map<String, String> args) { + + assert args['applicationId'] != null + String applicationId = args['applicationId']; + def sar = lookupApplication(applicationId) + assert sar != null; + return sar.url? Outcome.Success : Outcome.Retry + } + + /** + * Await for the URL of an app to be listed in the application report + * @param applicationId app ID + * @param launch_timeout launch timeout + */ + void awaitApplicationURLPublished(String applicationId, int launch_timeout) { + repeatUntilSuccess( + "await application URL published", + this.&isApplicationURLPublished, + launch_timeout, + PROBE_SLEEP_TIME, + [ + applicationId: applicationId + ], + true, + "application URL not published") { + + def sar = lookupApplication(applicationId) + log.error("$applicationId => $sar") + } + } + } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/ab2193c8/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy ---------------------------------------------------------------------- diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy index 0bce63e..5e234a4 100644 --- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy +++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy @@ -48,6 +48,8 @@ import org.junit.After import org.junit.Before import org.junit.Test +import static org.apache.slider.server.appmaster.web.rest.RestPaths.SYSTEM_HEALTHCHECK + @CompileStatic @Slf4j public class AgentWebPagesIT extends AgentCommandTestBase @@ -105,53 +107,45 @@ public class AgentWebPagesIT extends AgentCommandTestBase def appId = ensureYarnApplicationIsUp(launchReportFile) assert appId - expectRootWebPageUp(appId, instanceLaunchTime) + awaitApplicationURLPublished(appId, instanceLaunchTime) File liveReportFile = createTempJsonFile(); - lookup(appId,liveReportFile) + lookup(appId, liveReportFile) def report = loadAppReport(liveReportFile) assert report.url def proxyAM = report.url - // get the root page, - getWebPage(proxyAM) - - def directAM = report.origTrackingUrl; -/* - // now attempt direct-to-AM pings - LowLevelRestTestDelegates direct = new LowLevelRestTestDelegates(directAM, - directComplexVerbs) - - direct.testSuiteAll() + // here the URL has been published, but it may not be live yet, due to the time + // it takes the AM to build app state and boostrap the Web UI - // and via the proxy - LowLevelRestTestDelegates proxied = new LowLevelRestTestDelegates(proxyAM, - proxyComplexVerbs) - proxied.testSuiteAll() - proxied.logCodahaleMetrics(); -*/ + def directAM = report.origTrackingUrl; describe "Proxy Jersey Tests" - Client ugiClient = createUGIJerseyClient() + Client jerseyClient = createUGIJerseyClient() + JerseyTestDelegates proxyJerseyTests = - new JerseyTestDelegates(proxyAM, ugiClient, proxyComplexVerbs) + new JerseyTestDelegates(proxyAM, jerseyClient, proxyComplexVerbs) + + // wait it coming up + awaitRestEndpointLive(proxyJerseyTests, instanceLaunchTime) + proxyJerseyTests.testSuiteGetOperations() describe "Direct Jersey Tests" JerseyTestDelegates directJerseyTests = - new JerseyTestDelegates(directAM, ugiClient, directComplexVerbs) + new JerseyTestDelegates(directAM, jerseyClient, directComplexVerbs) directJerseyTests.testSuiteAll() describe "Proxy SliderRestClient Tests" RestAPIClientTestDelegates proxySliderRestAPI = - new RestAPIClientTestDelegates(proxyAM, ugiClient, proxyComplexVerbs) + new RestAPIClientTestDelegates(proxyAM, jerseyClient, proxyComplexVerbs) proxySliderRestAPI.testSuiteAll() describe "Direct SliderRestClient Tests" RestAPIClientTestDelegates directSliderRestAPI = - new RestAPIClientTestDelegates(directAM, ugiClient, directComplexVerbs) + new RestAPIClientTestDelegates(directAM, jerseyClient, directComplexVerbs) directSliderRestAPI.testSuiteAll() if (UserGroupInformation.securityEnabled) { @@ -171,7 +165,7 @@ public class AgentWebPagesIT extends AgentCommandTestBase SliderClient sliderClient = bondToCluster(SLIDER_CONFIG, CLUSTER) RegistryOperations operations = sliderClient.registryOperations; def restClientFactory = new RestClientFactory( - operations, ugiClient, + operations, jerseyClient, "~", SliderKeys.APP_TYPE, CLUSTER) def sliderApplicationApi = restClientFactory.createSliderAppApiClient(); sliderApplicationApi.desiredModel @@ -209,4 +203,21 @@ public class AgentWebPagesIT extends AgentCommandTestBase } } + /** + * Await for the URL of an app to be listed in the application report + * @param applicationId app ID + * @param launch_timeout launch timeout + */ + void awaitRestEndpointLive(JerseyTestDelegates jersey, int launch_timeout) { + repeatUntilSuccess( + "await application URL published", + jersey.&probeServiceLive, + launch_timeout, + PROBE_SLEEP_TIME, + [:], + false, + "GET of $SYSTEM_HEALTHCHECK failed") { + jersey.jerseyGet(SYSTEM_HEALTHCHECK) + } + } }
