diff --git a/gradle.properties b/gradle.properties index 3ad0aea..19cb58c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version = 0.2 +version = 0.3 rundeckPluginVersion = 1.1 mavenCentralUrl = http://repo1.maven.org/maven2 diff --git a/src/main/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin.java b/src/main/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin.java index 07e82c8..c892405 100644 --- a/src/main/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin.java +++ b/src/main/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin.java @@ -110,8 +110,6 @@ public enum SaltApiNodeStepFailureReason implements FailureReason { protected static final String SECURE_OPTION_VALUE = "****"; - protected static final String[] VALID_SALT_API_END_POINT_SCHEMES = { "http", "https" }; - protected static final String LOGIN_RESOURCE = "/login"; protected static final String MINION_RESOURCE = "/minions"; protected static final String JOBS_RESOURCE = "/jobs"; @@ -191,6 +189,9 @@ public enum SaltApiNodeStepFailureReason implements FailureReason { @Value("${saltApi.http.numRetries}") protected int numRetries; + // Supported API protocols + protected String[] endPointSchemes; + @Autowired protected ExponentialBackoffTimer.Factory timerFactory; @@ -198,6 +199,11 @@ public SaltApiNodeStepPlugin() { new DependencyInjectionUtil().inject(this); } + @Autowired + public void setEndPointSchemes(@Value("${saltApi.endPointSchemes}") String epSchemes) throws IllegalArgumentException { + endPointSchemes = epSchemes.split(","); + } + @Override public void executeNodeStep(PluginStepContext context, Map configuration, INodeEntry entry) throws NodeStepException { @@ -353,7 +359,7 @@ protected void validate(String user, String password, INodeEntry entry) throws S checkNotEmpty(SALT_USER_OPTION_NAME, user, SaltApiNodeStepFailureReason.ARGUMENTS_MISSING, entry); checkNotEmpty(SALT_PASSWORD_OPTION_NAME, password, SaltApiNodeStepFailureReason.ARGUMENTS_MISSING, entry); - UrlValidator urlValidator = new UrlValidator(VALID_SALT_API_END_POINT_SCHEMES, UrlValidator.ALLOW_LOCAL_URLS); + UrlValidator urlValidator = new UrlValidator(endPointSchemes, UrlValidator.ALLOW_LOCAL_URLS); if (!urlValidator.isValid(saltEndpoint)) { throw new SaltStepValidationException(SALT_API_END_POINT_OPTION_NAME, String.format( "%s is not a valid endpoint.", saltEndpoint), SaltApiNodeStepFailureReason.ARGUMENTS_INVALID, @@ -364,12 +370,13 @@ protected void validate(String user, String password, INodeEntry entry) throws S protected String waitForJidResponse(HttpClient client, String authToken, String jid, String minionId) throws IOException, InterruptedException, SaltApiException { ExponentialBackoffTimer timer = timerFactory.newTimer(delayStep, maximumRetryDelay); + String jidResource = String.format("%s%s/%s", saltEndpoint, JOBS_RESOURCE, jid); + logWrapper.info("Polling for job status with salt-api endpoint: [%s]", jidResource); do { String response = extractOutputForJid(client, authToken, jid, minionId); if (response != null) { return response; } - logWrapper.debug("No response received, waiting..."); timer.waitForNext(); } while (true); } @@ -390,14 +397,12 @@ protected String extractOutputForJid(HttpClient client, String authToken, String get.setHeader(SALT_AUTH_TOKEN_HEADER, authToken); get.setHeader(REQUEST_ACCEPT_HEADER_NAME, JSON_RESPONSE_ACCEPT_TYPE); - logWrapper.info("Polling for job status with salt-api endpoint: [%s]", get.getURI()); HttpResponse response = retryExecutor.execute(logWrapper, client, get, numRetries); try { if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); String entityResponse = extractBodyFromEntity(entity); - logWrapper.debug("Received response for jobs/%s = %s", jid, response); Gson gson = new Gson(); Map>> result = gson.fromJson(entityResponse, JOB_RESPONSE_TYPE); List> responses = result.get(SALT_OUTPUT_RETURN_KEY); @@ -406,6 +411,7 @@ protected String extractOutputForJid(HttpClient client, String authToken, String } else if (responses.size() == 1) { Map minionResponse = responses.get(0); if (minionResponse.containsKey(minionId)) { + logWrapper.debug("Received response for jobs/%s = %s", jid, response); Object responseObj = minionResponse.get(minionId); return gson.toJson(responseObj); } diff --git a/src/main/resources/defaultReturners.yaml b/src/main/resources/defaultReturners.yaml index 5d993df..2ffeaa6 100644 --- a/src/main/resources/defaultReturners.yaml +++ b/src/main/resources/defaultReturners.yaml @@ -5,5 +5,6 @@ alwaysSuccessful: &alwaysSuccessful !!org.rundeck.plugin.salt.output.DefaultSalt handlerMappings: cmd.run_all: *defaultCommandParser + file.touch: *alwaysSuccessful file.append: *alwaysSuccessful file.remove: *alwaysSuccessful diff --git a/src/main/resources/salt-api-plugin.properties b/src/main/resources/salt-api-plugin.properties index 414b78b..fef47f2 100644 --- a/src/main/resources/salt-api-plugin.properties +++ b/src/main/resources/salt-api-plugin.properties @@ -5,4 +5,5 @@ retryingHttpClientExecutor.maximumRetryDelay=15000 retryingHttpClientExecutor.delayStep=500 saltJobPolling.maximumRetryDelay=15000 saltJobPolling.delayStep=500 -saltApi.http.numRetries=5 \ No newline at end of file +saltApi.http.numRetries=5 +saltApi.endPointSchemes=https \ No newline at end of file diff --git a/src/test/java/org/rundeck/plugin/salt/AbstractSaltApiNodeStepPluginTest.java b/src/test/java/org/rundeck/plugin/salt/AbstractSaltApiNodeStepPluginTest.java index 51c2655..d83c29e 100644 --- a/src/test/java/org/rundeck/plugin/salt/AbstractSaltApiNodeStepPluginTest.java +++ b/src/test/java/org/rundeck/plugin/salt/AbstractSaltApiNodeStepPluginTest.java @@ -26,10 +26,11 @@ package org.rundeck.plugin.salt; -import java.net.URI; -import java.net.URLEncoder; -import java.util.Map; - +import com.dtolabs.rundeck.core.common.INodeEntry; +import com.dtolabs.rundeck.plugins.PluginLogger; +import com.dtolabs.rundeck.plugins.step.PluginStepContext; +import com.google.common.base.Predicate; +import com.google.common.collect.Maps; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -54,15 +55,13 @@ import org.rundeck.plugin.salt.util.RetryingHttpClientExecutor; import org.rundeck.plugin.salt.version.SaltApiCapability; -import com.dtolabs.rundeck.core.common.INodeEntry; -import com.dtolabs.rundeck.plugins.PluginLogger; -import com.dtolabs.rundeck.plugins.step.PluginStepContext; -import com.google.common.base.Predicate; -import com.google.common.collect.Maps; +import java.net.URI; +import java.net.URLEncoder; +import java.util.Map; public abstract class AbstractSaltApiNodeStepPluginTest { - protected static final String PARAM_ENDPOINT = "http://localhost"; + protected static final String PARAM_ENDPOINT = "https://localhost"; protected static final String PARAM_EAUTH = "pam"; protected static final String PARAM_MINION_NAME = "minion"; protected static final String PARAM_FUNCTION = "some.function"; @@ -107,6 +106,7 @@ public void setUp() { plugin.saltEndpoint = PARAM_ENDPOINT; plugin.eAuth = PARAM_EAUTH; plugin.function = PARAM_FUNCTION; + plugin.setEndPointSchemes("https"); latestCapability = plugin.capabilityRegistry.getLatest(); client = Mockito.mock(HttpClient.class); post = Mockito.mock(HttpPost.class); diff --git a/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ExecuteTest.java b/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ExecuteTest.java index fa81646..2b3d4cd 100644 --- a/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ExecuteTest.java +++ b/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ExecuteTest.java @@ -26,8 +26,8 @@ package org.rundeck.plugin.salt; -import java.util.Set; - +import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepException; +import com.google.common.collect.ImmutableSet; import org.apache.http.HttpException; import org.apache.http.client.HttpClient; import org.junit.Assert; @@ -39,10 +39,8 @@ import org.rundeck.plugin.salt.output.SaltReturnResponse; import org.rundeck.plugin.salt.output.SaltReturnResponseParseException; import org.rundeck.plugin.salt.validation.SaltStepValidationException; -import org.rundeck.plugin.salt.version.SaltApiCapability; -import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepException; -import com.google.common.collect.ImmutableSet; +import java.util.Set; public class SaltApiNodeStepPlugin_ExecuteTest extends AbstractSaltApiNodeStepPluginTest { @@ -54,6 +52,9 @@ public void setup() throws Exception { @Test public void testExecuteWithAuthenticationFailure() { setupAuthenticate(null); + setupDoReturnJidWhenSubmitJob(); + setupDoReturnHostResponseWhenWaitForResponse(); + setupDoReturnSaltResponseWhenExtractResponse(0, new String[0], new String[0]); try { plugin.executeNodeStep(pluginContext, configuration, node); @@ -81,6 +82,10 @@ public void testExecuteWithValidationFailure() throws Exception { @Test public void testExecuteWithDataContextMissing() { + setupAuthenticate(); + setupDoReturnJidWhenSubmitJob(); + setupDoReturnHostResponseWhenWaitForResponse(); + setupDoReturnSaltResponseWhenExtractResponse(0, new String[0], new String[0]); dataContext.clear(); try { plugin.executeNodeStep(pluginContext, configuration, node); @@ -273,6 +278,24 @@ public void testExecuteWithHttpException() { } } + @Test + public void testExecuteWithUnsupportedEndPointScheme() { + setupAuthenticate(); + setupDoReturnJidWhenSubmitJob(); + setupDoReturnHostResponseWhenWaitForResponse(); + setupDoReturnSaltResponseWhenExtractResponse(0, new String[0], new String[0]); + + plugin.setEndPointSchemes("http"); + + try { + plugin.executeNodeStep(pluginContext, configuration, node); + Assert.fail("Expected node step failure."); + } catch (NodeStepException e) { + Assert.assertEquals("Expected failure reason to be set based on exception type", + SaltApiNodeStepFailureReason.ARGUMENTS_INVALID, e.getFailureReason()); + } + } + @Test public void testExecuteWithInterruptedException() throws Exception { setupAuthenticate(); diff --git a/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ValidationTest.java b/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ValidationTest.java index ae2c467..4f7a19b 100644 --- a/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ValidationTest.java +++ b/src/test/java/org/rundeck/plugin/salt/SaltApiNodeStepPlugin_ValidationTest.java @@ -89,7 +89,7 @@ public void testValidateThrowsIfValidatorThrows() throws SaltStepValidationExcep @Test public void testValidateChecksValidEndpointHttpUrl() throws NodeStepException { - plugin.saltEndpoint = "http://some.machine.com"; + plugin.saltEndpoint = "https://some.machine.com"; plugin.validate(PARAM_USER, PARAM_PASSWORD, node); }