diff --git a/README.md b/README.md index 2193cbb..ed20f97 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Java Plugins: * Notification * WorkflowStep * WorkflowNodeStep +* LogFilter Script Plugins: * ResourceModelSource diff --git a/src/main/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGenerator.groovy b/src/main/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGenerator.groovy index e9f3cb2..e672886 100644 --- a/src/main/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGenerator.groovy +++ b/src/main/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGenerator.groovy @@ -24,7 +24,7 @@ class JavaPluginTemplateGenerator extends AbstractTemplateGenerator { private static final String TEMPLATE_BASE = "templates/java-plugin/" private static final String JAVA_STRUCTURE = "java-plugin.structure" - private static final List ALLOWED_TEMPLATES = ["ResourceModelSource","Notification","WorkflowStep","WorkflowNodeStep"] + private static final List ALLOWED_TEMPLATES = ["ResourceModelSource","Notification","WorkflowStep","WorkflowNodeStep","LogFilter"] @Override Map makeTemplateProperties(final String pluginName, final String providedService) { diff --git a/src/main/resources/templates/java-plugin/logfilter/Plugin.java.template b/src/main/resources/templates/java-plugin/logfilter/Plugin.java.template new file mode 100644 index 0000000..3fbb49f --- /dev/null +++ b/src/main/resources/templates/java-plugin/logfilter/Plugin.java.template @@ -0,0 +1,83 @@ +package com.plugin.${javaPluginClass.toLowerCase()}; + +import com.dtolabs.rundeck.core.logging.LogEventControl; +import com.dtolabs.rundeck.core.logging.LogLevel; +import com.dtolabs.rundeck.core.logging.PluginLoggingContext; +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.descriptions.SelectLabels; +import com.dtolabs.rundeck.plugins.descriptions.SelectValues; +import com.dtolabs.rundeck.plugins.logging.LogFilterPlugin; +import java.util.HashMap; +import java.util.Map; + +@Plugin(service="LogFilter",name="${sanitizedPluginName}") +@PluginDescription(title="${pluginName}", description="My plugin description") +public class ${javaPluginClass} implements LogFilterPlugin{ + + @PluginProperty(name = "example header",title = "Example String",description = "Example description") + private String header; + + @PluginProperty( + title = "Data type", + description = "Select datatype output", + required = false + ) + @SelectValues( + values = {"text/plain", "text/html"}, + freeSelect = true + ) + @SelectLabels(values = {"TEXT", "HTML"}) + String datatype = null; + + + private boolean started = false; + private StringBuilder buffer; + + @Override + public void init(final PluginLoggingContext context) { + started = true; + buffer = new StringBuilder(); + + if(datatype.equals("text/html")){ + buffer.append(""); + buffer.append(""); + } + } + + @Override + public void handleEvent(final PluginLoggingContext context, final LogEventControl event) { + if(event.getEventType().equals("log") && event.getLoglevel().equals(LogLevel.NORMAL) ){ + + if(datatype.equals("text/html")){ + buffer.append(""); + }else{ + buffer.append("[").append(header).append("] ").append(event.getMessage()).append("\\n"); + } + + event.setLoglevel(LogLevel.DEBUG); + } + } + + @Override + public void complete(final PluginLoggingContext context) { + if (started && datatype!=null && buffer.length()>0) { + + if(datatype.equals("text/html")){ + buffer.append("
Log Output
").append("[").append(header).append("] ").append(event.getMessage()).append("
"); + } + + Map type = new HashMap<>(); + type.put("content-data-type", datatype); + + + context.log( + 2, + buffer.toString(), + type + ); + + } + } +} \ No newline at end of file diff --git a/src/main/resources/templates/java-plugin/logfilter/PluginSpec.groovy.template b/src/main/resources/templates/java-plugin/logfilter/PluginSpec.groovy.template new file mode 100644 index 0000000..cb2e5f5 --- /dev/null +++ b/src/main/resources/templates/java-plugin/logfilter/PluginSpec.groovy.template @@ -0,0 +1,45 @@ +package com.plugin.${javaPluginClass.toLowerCase()} + +import com.dtolabs.rundeck.core.dispatcher.ContextView +import com.dtolabs.rundeck.core.execution.workflow.DataOutput +import com.dtolabs.rundeck.core.logging.LogEventControl +import com.dtolabs.rundeck.core.logging.LogLevel +import com.dtolabs.rundeck.core.logging.PluginLoggingContext +import spock.lang.Specification + +class ${javaPluginClass}Spec extends Specification { + + def "test preset type "() { + given: + def plugin = new ${javaPluginClass}() + plugin.datatype = datatype + plugin.header = "test" + def sharedoutput = new DataOutput(ContextView.global()) + def context = Mock(PluginLoggingContext) { + getOutputContext() >> sharedoutput + } + def events = [] + lines.each { line -> + events << Mock(LogEventControl) { + getMessage() >> line + getEventType() >> 'log' + getLoglevel() >> LogLevel.NORMAL + } + } + when: + plugin.init(context) + events.each { + plugin.handleEvent(context, it) + } + plugin.complete(context) + + then: + 1 * context.log(2, output, meta) + + where: + datatype | lines | output | meta + 'text/plain' | ['1,2,3', '---', 'a,b,c'] | '[test] 1,2,3\\n[test] ---\\n[test] a,b,c\\n' | ['content-data-type': 'text/plain'] + 'text/html' | ['1,2,3', '---', 'a,b,c'] | "
Log Output
[test] 1,2,3
[test] ---
[test] a,b,c
" | ['content-data-type': 'text/html'] + } + +} \ No newline at end of file diff --git a/src/main/resources/templates/java-plugin/logfilter/README.md.template b/src/main/resources/templates/java-plugin/logfilter/README.md.template new file mode 100644 index 0000000..a03f19d --- /dev/null +++ b/src/main/resources/templates/java-plugin/logfilter/README.md.template @@ -0,0 +1,4 @@ +# ${pluginName} Rundeck Plugin + +This is a log filter plugin. + diff --git a/src/main/resources/templates/java-plugin/logfilter/build.gradle.template b/src/main/resources/templates/java-plugin/logfilter/build.gradle.template new file mode 100644 index 0000000..b304aa9 --- /dev/null +++ b/src/main/resources/templates/java-plugin/logfilter/build.gradle.template @@ -0,0 +1,42 @@ +version = '0.1.0' +defaultTasks 'clean','build' +apply plugin: 'java' +apply plugin: 'groovy' +apply plugin: 'idea' +sourceCompatibility = 1.8 +ext.rundeckPluginVersion= '2.0' +ext.rundeckVersion= '${rundeckVersion}' + + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + compile 'org.rundeck:rundeck-core:3.0.1+' + + testCompile 'junit:junit:4.12' + testCompile "org.codehaus.groovy:groovy-all:2.4.15" + testCompile "org.spockframework:spock-core:1.0-groovy-2.4" +} + +ext.pluginClassNames='com.plugin.${sanitizedPluginName}.${javaPluginClass}' +jar { + manifest { + attributes 'Rundeck-Plugin-Classnames': pluginClassNames + attributes 'Rundeck-Plugin-File-Version': version + attributes 'Rundeck-Plugin-Name': '${pluginName}' + attributes 'Rundeck-Plugin-Description': 'Provide a short description of your plugin here.' + attributes 'Rundeck-Plugin-Rundeck-Compatibility-Version': '3.x' + attributes 'Rundeck-Plugin-Tags': 'java,notification' + attributes 'Rundeck-Plugin-Version': rundeckPluginVersion, 'Rundeck-Plugin-Archive': 'true' + } + from("rundeck-verb-artifact.yaml") { + into("") + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '4.4.1' +} diff --git a/src/main/resources/templates/java-plugin/logfilter/icon.png b/src/main/resources/templates/java-plugin/logfilter/icon.png new file mode 100644 index 0000000..7aaf7e8 Binary files /dev/null and b/src/main/resources/templates/java-plugin/logfilter/icon.png differ diff --git a/src/main/resources/templates/java-plugin/logfilter/java-plugin.structure b/src/main/resources/templates/java-plugin/logfilter/java-plugin.structure new file mode 100644 index 0000000..d0ce03e --- /dev/null +++ b/src/main/resources/templates/java-plugin/logfilter/java-plugin.structure @@ -0,0 +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 + diff --git a/src/main/resources/templates/script-plugin/filecopier/plugin.yaml.template b/src/main/resources/templates/script-plugin/filecopier/plugin.yaml.template index 58e31ac..86d3cb1 100644 --- a/src/main/resources/templates/script-plugin/filecopier/plugin.yaml.template +++ b/src/main/resources/templates/script-plugin/filecopier/plugin.yaml.template @@ -40,4 +40,22 @@ providers: description: 'Just echo what would be done' default: true renderingOptions: - groupName: 'Config' \ No newline at end of file + groupName: 'Config' + - type: String + name: storageprivatekey + title: Storage Private Key + description: Access to storage private key example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-key-type=private" + - type: String + name: storagepassword + title: Storage Password + description: Access to storage password example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-data-type=password" \ No newline at end of file diff --git a/src/main/resources/templates/script-plugin/nodeexecutor-filecopier/plugin.yaml.template b/src/main/resources/templates/script-plugin/nodeexecutor-filecopier/plugin.yaml.template index 82e8b18..92ecd48 100644 --- a/src/main/resources/templates/script-plugin/nodeexecutor-filecopier/plugin.yaml.template +++ b/src/main/resources/templates/script-plugin/nodeexecutor-filecopier/plugin.yaml.template @@ -41,6 +41,24 @@ providers: default: true renderingOptions: groupName: 'Config' + - type: String + name: storageprivatekey + title: Storage Private Key + description: Access to storage private key example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-key-type=private" + - type: String + name: storagepassword + title: Storage Password + description: Access to storage password example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-data-type=password" - name: ${sanitizedPluginName}-FileCopier service: FileCopier title: ${pluginName} @@ -70,4 +88,22 @@ providers: description: 'Just echo what would be done' default: true renderingOptions: - groupName: 'Config' \ No newline at end of file + groupName: 'Config' + - type: String + name: storageprivatekey + title: Storage Private Key + description: Access to storage private key example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-key-type=private" + - type: String + name: storagepassword + title: Storage Password + description: Access to storage password example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-data-type=password" \ No newline at end of file diff --git a/src/main/resources/templates/script-plugin/nodeexecutor/plugin.yaml.template b/src/main/resources/templates/script-plugin/nodeexecutor/plugin.yaml.template index b383b93..7e85361 100644 --- a/src/main/resources/templates/script-plugin/nodeexecutor/plugin.yaml.template +++ b/src/main/resources/templates/script-plugin/nodeexecutor/plugin.yaml.template @@ -40,4 +40,22 @@ providers: description: 'Just echo what would be done' default: true renderingOptions: - groupName: 'Config' \ No newline at end of file + groupName: 'Config' + - type: String + name: storageprivatekey + title: Storage Private Key + description: Access to storage private key example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-key-type=private" + - type: String + name: storagepassword + title: Storage Password + description: Access to storage password example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-data-type=password" \ No newline at end of file diff --git a/src/main/resources/templates/script-plugin/workflow/plugin.yaml.template b/src/main/resources/templates/script-plugin/workflow/plugin.yaml.template index a24545e..462c299 100644 --- a/src/main/resources/templates/script-plugin/workflow/plugin.yaml.template +++ b/src/main/resources/templates/script-plugin/workflow/plugin.yaml.template @@ -44,4 +44,22 @@ providers: title: Debug? description: 'Write debug messages to stderr' renderingOptions: - groupName: 'Config' \ No newline at end of file + groupName: 'Config' + - type: String + name: storageprivatekey + title: Storage Private Key + description: Access to storage private key example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-key-type=private" + - type: String + name: storagepassword + title: Storage Password + description: Access to storage password example + renderingOptions: + selectionAccessor: "STORAGE_PATH" + valueConversion: "STORAGE_PATH_AUTOMATIC_READ" + storage-path-root: "keys" + storage-file-meta-filter: "Rundeck-data-type=password" \ No newline at end of file diff --git a/src/test/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGeneratorTest.groovy b/src/test/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGeneratorTest.groovy index fcaa77a..f169c6d 100644 --- a/src/test/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGeneratorTest.groovy +++ b/src/test/groovy/com/rundeck/plugin/generator/JavaPluginTemplateGeneratorTest.groovy @@ -85,4 +85,20 @@ class JavaPluginTemplateGeneratorTest extends Specification { new File(tmpDir,"/my-workflownodestep-plugin/src/test/groovy/com/plugin/myworkflownodestepplugin/MyWorkflownodestepPluginSpec.groovy").exists() } + def "Create Logfilter Template"() { + when: + File tmpDir = File.createTempDir() + JavaPluginTemplateGenerator generator = new JavaPluginTemplateGenerator() + generator.createTemplate("My LogFilter Plugin","LogFilter",tmpDir.absolutePath) + int compileResult = TestUtils.buildGradle(new File(tmpDir,"my-logfilter-plugin")) + + then: + compileResult == 0 + new File(tmpDir,"/my-logfilter-plugin/build.gradle").exists() + new File(tmpDir,"/my-logfilter-plugin/src/main/resources/resources/icon.png").exists() + new File(tmpDir,"/my-logfilter-plugin/README.md").exists() + new File(tmpDir,"/my-logfilter-plugin/src/main/java/com/plugin/mylogfilterplugin/MyLogfilterPlugin.java").exists() + new File(tmpDir,"/my-logfilter-plugin/src/test/groovy/com/plugin/mylogfilterplugin/MyLogfilterPluginSpec.groovy").exists() + } + }