-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from rundeck/update-java-plugins-standards
Updated Java plugins standards
- Loading branch information
Showing
37 changed files
with
1,310 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
src/main/resources/templates/java-plugin/nodeexecutor/Plugin.groovy.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package com.plugin.${javaPluginClass.toLowerCase()}; | ||
|
||
import com.dtolabs.rundeck.core.common.INodeEntry | ||
import com.dtolabs.rundeck.core.execution.ExecutionContext | ||
import com.dtolabs.rundeck.core.execution.ExecutionLogger | ||
import com.dtolabs.rundeck.core.execution.service.NodeExecutor | ||
import com.dtolabs.rundeck.core.execution.service.NodeExecutorResult | ||
import com.dtolabs.rundeck.core.execution.service.NodeExecutorResultImpl | ||
import com.dtolabs.rundeck.core.execution.utils.ResolverUtil | ||
import com.dtolabs.rundeck.core.plugins.Plugin | ||
import com.dtolabs.rundeck.core.plugins.configuration.Describable | ||
import com.dtolabs.rundeck.core.plugins.configuration.Description; | ||
import com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants; | ||
import com.dtolabs.rundeck.plugins.ServiceNameConstants; | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginDescription; | ||
import com.dtolabs.rundeck.plugins.util.DescriptionBuilder | ||
import com.dtolabs.rundeck.plugins.util.PropertyBuilder; | ||
|
||
@Plugin(name = "${sanitizedPluginName}", service = ServiceNameConstants.NodeExecutor) | ||
@PluginDescription(title = "${pluginName}", description = "A node executor plugin that can execute commands on remote nodes") | ||
public class ${javaPluginClass} implements NodeExecutor, Describable { | ||
|
||
public static final String SERVICE_PROVIDER_NAME = "${sanitizedPluginName}" | ||
|
||
public static final String PROJ_PROP_PREFIX = "project." | ||
public static final String FRAMEWORK_PROP_PREFIX = "framework." | ||
|
||
public static final String MOCK_FAILURE = "mockFailure" | ||
public static final String USERNAME = "username" | ||
public static final String PASSWORD = "password" | ||
|
||
@Override | ||
Description getDescription() { | ||
DescriptionBuilder builder = DescriptionBuilder.builder() | ||
.name(SERVICE_PROVIDER_NAME) | ||
.title("${pluginName}") | ||
.description("A node executor plugin that can execute commands on remote nodes") | ||
.property(PropertyBuilder.builder() | ||
.title("Username") | ||
.string(USERNAME) | ||
.description("The username to use for the connection") | ||
.required(true) | ||
.renderingOption(StringRenderingConstants.INSTANCE_SCOPE_NODE_ATTRIBUTE_KEY, "username-key-path") | ||
.build() | ||
) | ||
.property( | ||
PropertyBuilder.builder() | ||
.title("Password") | ||
.string(PASSWORD) | ||
.description("The password to use for the connection") | ||
.required(true) | ||
.renderingOption(StringRenderingConstants.SELECTION_ACCESSOR_KEY, StringRenderingConstants.SelectionAccessor.STORAGE_PATH) | ||
.renderingOption(StringRenderingConstants.STORAGE_PATH_ROOT_KEY, "keys") | ||
.renderingOption(StringRenderingConstants.STORAGE_FILE_META_FILTER_KEY, "Rundeck-data-type=password") | ||
.build() | ||
) | ||
.property( | ||
PropertyBuilder.builder() | ||
.title("Mock Failure") | ||
.booleanType(MOCK_FAILURE) | ||
.description("Optionally select to mock a failure") | ||
.required(false) | ||
.defaultValue("false") | ||
.build() | ||
) | ||
|
||
builder.mapping(USERNAME, PROJ_PROP_PREFIX + USERNAME) | ||
builder.frameworkMapping(USERNAME, FRAMEWORK_PROP_PREFIX + USERNAME) | ||
builder.mapping(PASSWORD, PROJ_PROP_PREFIX + PASSWORD) | ||
builder.frameworkMapping(PASSWORD, FRAMEWORK_PROP_PREFIX + PASSWORD) | ||
builder.mapping(MOCK_FAILURE, PROJ_PROP_PREFIX + MOCK_FAILURE) | ||
builder.frameworkMapping(MOCK_FAILURE, FRAMEWORK_PROP_PREFIX + MOCK_FAILURE) | ||
|
||
return builder.build() | ||
} | ||
|
||
@Override | ||
public NodeExecutorResult executeCommand(ExecutionContext context, String[] command, INodeEntry node) { | ||
|
||
String username = ResolverUtil.resolveProperty(USERNAME, null, node, | ||
context.getIFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()), | ||
context.framework) | ||
String passwordKeyPath = ResolverUtil.resolveProperty(PASSWORD, null, node, | ||
context.getIFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()), | ||
context.framework) | ||
boolean mockFailure = Boolean.parseBoolean(ResolverUtil.resolveProperty(MOCK_FAILURE, "false", node, | ||
context.getIFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()), | ||
context.framework)) | ||
|
||
ExecutionLogger logger= context.getExecutionLogger() | ||
|
||
//Here we can retrieve the password from key storage and use it to authenticate with the target node. | ||
String password = Util.getPasswordFromPath(passwordKeyPath, context) | ||
|
||
logger.log(2, "Executing command: " + Arrays.asList(command) + " on node: " + node.getNodename() + " with username: " + username) | ||
|
||
if(mockFailure) { | ||
return NodeExecutorResultImpl.createFailure(Util.PluginFailureReason.ConnectionError, "Failure due to mock failure", node) | ||
} else { | ||
return NodeExecutorResultImpl.createSuccess(node) | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/main/resources/templates/java-plugin/nodeexecutor/Util.groovy.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.plugin.${javaPluginClass.toLowerCase()} | ||
|
||
import com.dtolabs.rundeck.core.execution.ExecutionContext | ||
import com.dtolabs.rundeck.core.execution.workflow.steps.FailureReason | ||
import com.dtolabs.rundeck.core.storage.ResourceMeta | ||
|
||
class Util { | ||
|
||
static String getPasswordFromPath(String path, ExecutionContext context) throws IOException { | ||
ResourceMeta contents = context.getStorageTree().getResource(path).getContents(); | ||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | ||
contents.writeContent(byteArrayOutputStream); | ||
String password = new String(byteArrayOutputStream.toByteArray()); | ||
return password; | ||
} | ||
|
||
enum PluginFailureReason implements FailureReason { | ||
KeyStorageError, | ||
ConnectionError | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
src/main/resources/templates/java-plugin/nodeexecutor/java-plugin.structure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
build.gradle.template->build.gradle | ||
README.md.template->README.md | ||
icon.png->src/main/resources/resources/icon.png | ||
Plugin.java.template->src/main/java/com/plugin/${javaPluginClass.toLowerCase()}/${javaPluginClass}.java | ||
PluginSpec.groovy.template->src/test/groovy/com/plugin/${javaPluginClass.toLowerCase()}/${javaPluginClass}Spec.groovy | ||
|
||
Plugin.groovy.template->src/main/groovy/com/plugin/${javaPluginClass.toLowerCase()}/${javaPluginClass}.groovy | ||
Util.groovy.template->src/main/groovy/com/plugin/${javaPluginClass.toLowerCase()}/Util.groovy | ||
PluginSpec.groovy.template->src/test/groovy/com/plugin/${javaPluginClass.toLowerCase()}/${javaPluginClass}Spec.groovy |
52 changes: 52 additions & 0 deletions
52
src/main/resources/templates/java-plugin/notification/ExampleApis.groovy.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.plugin.${javaPluginClass.toLowerCase()}; | ||
|
||
import okhttp3.MediaType | ||
import okhttp3.OkHttpClient | ||
import okhttp3.Request | ||
import okhttp3.Response | ||
import okhttp3.RequestBody | ||
import okhttp3.Credentials; | ||
|
||
|
||
class ExampleApis { | ||
|
||
Properties configuration; | ||
|
||
//Set constructor to use configuration from plugin properties | ||
ExampleApis(Properties configuration) { | ||
this.configuration = configuration; | ||
} | ||
|
||
//Pass the customProperty from the plugin config to the JSON string that we'll pass to the API call | ||
private String json = '{"name":"' + configuration.getProperty("customProperty") + '"}'; | ||
|
||
//Set the media type for the API call request body | ||
public static final MediaType JSON = MediaType.get("application/json"); | ||
|
||
//Create a new OkHttpClient | ||
OkHttpClient client = new OkHttpClient(); | ||
|
||
//Post method that takes the API Key as an argument | ||
String post(String apiKey) throws IOException { | ||
|
||
//Create a basic authentication credential | ||
String credential = Credentials.basic("name", apiKey); | ||
|
||
RequestBody body = RequestBody.create(JSON, json); | ||
|
||
Request request = new Request.Builder() | ||
.url("https://httpbin.org/post") | ||
.post(body) | ||
.header("Authorization", credential) | ||
.build(); | ||
|
||
Response response = null | ||
|
||
try { | ||
response = client.newCall(request).execute() | ||
return response.body().string(); | ||
} finally { | ||
response.close(); | ||
} | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
src/main/resources/templates/java-plugin/notification/Plugin.groovy.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.plugin.${javaPluginClass.toLowerCase()}; | ||
|
||
import com.dtolabs.rundeck.core.plugins.Plugin | ||
import com.dtolabs.rundeck.core.plugins.configuration.AcceptsServices | ||
import com.dtolabs.rundeck.core.storage.StorageTree | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginDescription | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginProperty | ||
import com.dtolabs.rundeck.plugins.notification.NotificationPlugin | ||
import com.dtolabs.rundeck.plugins.descriptions.RenderingOption | ||
import com.dtolabs.rundeck.plugins.descriptions.RenderingOptions | ||
import com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants | ||
import com.dtolabs.rundeck.core.storage.keys.KeyStorageTree | ||
import org.rundeck.app.spi.Services | ||
import org.slf4j.Logger | ||
import org.slf4j.LoggerFactory | ||
|
||
@Plugin(service="Notification", name="${sanitizedPluginName}") | ||
@PluginDescription(title="${pluginName}", description="This is a notification plugin that integrated with ${pluginName}.") | ||
public class ${javaPluginClass} implements NotificationPlugin, AcceptsServices { | ||
|
||
static Logger logger = LoggerFactory.getLogger(${javaPluginClass}.class); | ||
|
||
@PluginProperty(name = "customProperty" ,title = "Custom Property", description = "A custom property to be passed to the API.") | ||
String customProperty; | ||
|
||
@PluginProperty( | ||
title = "API Key Path", | ||
description = 'REQUIRED: The path to the Key Storage entry for your API Key.\\n If an error of `Unauthorized` occurs, be sure to add the proper policy to ACLs.', | ||
required = true | ||
) | ||
@RenderingOptions([ | ||
@RenderingOption( | ||
key = StringRenderingConstants.SELECTION_ACCESSOR_KEY, | ||
value = "STORAGE_PATH" | ||
), | ||
@RenderingOption( | ||
key = StringRenderingConstants.STORAGE_PATH_ROOT_KEY, | ||
value = "keys" | ||
), | ||
@RenderingOption( | ||
key = StringRenderingConstants.STORAGE_FILE_META_FILTER_KEY, | ||
value = "Rundeck-data-type=password" | ||
), | ||
@RenderingOption( | ||
key = StringRenderingConstants.GROUP_NAME, | ||
value = "API Configuration" | ||
) | ||
]) | ||
String apiKeyPath | ||
|
||
|
||
//Implement services so that we can retrieve secret from key storage and pass to API call | ||
Services services | ||
@Override | ||
void setServices(Services services) { | ||
this.services = services | ||
} | ||
|
||
public boolean postNotification(String trigger, Map executionData, Map config) { | ||
|
||
//Get the secret from the key storage | ||
StorageTree keyStorage = services.getService(KeyStorageTree) | ||
String apiKeyPath = config.get("apiKeyPath") | ||
String apiKey = Util.getPasswordFromKeyStorage(apiKeyPath, keyStorage) | ||
|
||
//Pass in config properties to the API so that secret can be used in api call | ||
ExampleApis api = new ExampleApis(config as Properties); | ||
|
||
logger.warn(api.post(apiKey)) | ||
|
||
return true; | ||
} | ||
} |
30 changes: 16 additions & 14 deletions
30
src/main/resources/templates/java-plugin/notification/Plugin.java.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,25 @@ | ||
package com.plugin.${javaPluginClass.toLowerCase()}; | ||
|
||
import com.dtolabs.rundeck.plugins.notification.NotificationPlugin; | ||
import com.dtolabs.rundeck.core.plugins.Plugin; | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginDescription; | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginProperty; | ||
import java.util.*; | ||
import com.dtolabs.rundeck.core.plugins.Plugin | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginDescription | ||
import com.dtolabs.rundeck.plugins.descriptions.PluginProperty | ||
import com.dtolabs.rundeck.plugins.notification.NotificationPlugin | ||
import org.slf4j.Logger | ||
import org.slf4j.LoggerFactory | ||
|
||
@Plugin(service="Notification",name="${sanitizedPluginName}") | ||
@PluginDescription(title="${pluginName}", description="My plugin description") | ||
public class ${javaPluginClass} implements NotificationPlugin{ | ||
@Plugin(service="Notification", name="${sanitizedPluginName}") | ||
@PluginDescription(title="${pluginName}", description="This is a notification plugin that integrated with ${pluginName}.") | ||
public class ${javaPluginClass} implements NotificationPlugin { | ||
|
||
@PluginProperty(name = "example",title = "Example String",description = "Example description") | ||
private String example; | ||
static Logger logger = LoggerFactory.getLogger(Notificationplugin.class); | ||
|
||
@PluginProperty(name = "test" ,title = "Test String", description = "a description") | ||
String test; | ||
|
||
public boolean postNotification(String trigger, Map executionData, Map config) { | ||
System.err.printf("Trigger %s fired for %s, configuration: %s",trigger,executionData,config); | ||
System.err.println(); | ||
System.err.printf("Local field example is: %s",example); | ||
|
||
logger.info(new apiCall().post("{\"key\":\"value\"}")) | ||
|
||
return true; | ||
} | ||
|
||
} |
Oops, something went wrong.