Skip to content

Commit

Permalink
add functional test using plugin group
Browse files Browse the repository at this point in the history
  • Loading branch information
ltamaster committed Apr 1, 2024
1 parent 1f4080c commit f6da910
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
package functional

import functional.util.TestUtil
import org.rundeck.client.api.RundeckApi
import org.rundeck.client.api.model.ExecLog
import org.rundeck.client.api.model.ExecOutput
import org.rundeck.client.api.model.ExecutionStateResponse
import org.rundeck.client.api.model.JobRun
import org.rundeck.client.util.Client
import spock.lang.Shared
import spock.lang.Specification
import org.testcontainers.spock.Testcontainers


@Testcontainers
class BasicIntegrationSpec extends Specification {
class BasicIntegrationSpec extends TestConfiguration {

@Shared
public static RundeckCompose rundeckEnvironment = new RundeckCompose(new File("src/test/resources/docker/docker-compose.yml").toURI())

@Shared
Client<RundeckApi> client

static String PROJ_NAME = 'ansible-test'

Expand Down Expand Up @@ -270,55 +262,4 @@ class BasicIntegrationSpec extends Specification {
logs.findAll {it.log.contains("\"token\": 13231232312321321321321")}.size() == 1
}

ExecutionStateResponse waitForJob(String executionId){
def finalStatus = [
'aborted',
'failed',
'succeeded',
'timedout',
'other'
]

while(true) {
ExecutionStateResponse result=client.apiCall { api-> api.getExecutionState(executionId)}
if (finalStatus.contains(result?.getExecutionState()?.toLowerCase())) {
return result
} else {
sleep (10000)
}
}

}


List<ExecLog> getLogs(String executionId){
def offset = 0
def maxLines = 1000
def lastmod = 0
boolean isCompleted = false

List<ExecLog> logs = []

while (!isCompleted){
ExecOutput result = client.apiCall { api -> api.getOutput(executionId, offset,lastmod, maxLines)}
isCompleted = result.completed
offset = result.offset
lastmod = result.lastModified

logs.addAll(result.entries)

if(result.unmodified){
sleep(5000)
}else{
sleep(2000)
}
}

return logs
}





}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package functional

import functional.util.TestUtil
import org.rundeck.client.api.RundeckApi
import org.rundeck.client.api.model.JobRun
import org.rundeck.client.util.Client
import org.testcontainers.spock.Testcontainers
import spock.lang.Shared


@Testcontainers
class PluginGroupIntegrationSpec extends TestConfiguration {

@Shared
public static RundeckCompose rundeckEnvironment = new RundeckCompose(new File("src/test/resources/docker/docker-compose.yml").toURI())

@Shared
Client<RundeckApi> client

static String PROJ_NAME = 'ansible-plugin-group-test'

def setupSpec() {
rundeckEnvironment.startCompose()
client = rundeckEnvironment.configureRundeck(PROJ_NAME)
}

def "test simple inline playbook"(){
when:

def jobId = "fa0e401b-b5a8-436a-b13b-0e8092858021"

JobRun request = new JobRun()
request.loglevel = 'DEBUG'

def result = client.apiCall {api-> api.runJob(jobId, request)}
def executionId = result.id

def executionState = waitForJob(executionId)

def logs = getLogs(executionId)
Map<String, Integer> ansibleNodeExecutionStatus = TestUtil.getAnsibleNodeResult(logs)

then:
executionState!=null
executionState.getExecutionState()=="SUCCEEDED"
ansibleNodeExecutionStatus.get("ok")!=0
ansibleNodeExecutionStatus.get("unreachable")==0
ansibleNodeExecutionStatus.get("failed")==0
ansibleNodeExecutionStatus.get("skipped")==0
ansibleNodeExecutionStatus.get("ignored")==0

logs.findAll {it.log.contains("plugin group set getAnsibleConfigFilePath: /home/rundeck/ansible")}.size() == 1
logs.findAll {it.log.contains("ANSIBLE_CONFIG: /home/rundeck/ansible")}.size() == 1

}

def "test simple inline playbook with env vars"(){
when:

def jobId = "572367d2-e41a-4fdb-b6fc-effa32185b61"

JobRun request = new JobRun()
request.loglevel = 'DEBUG'

def result = client.apiCall {api-> api.runJob(jobId, request)}
def executionId = result.id

def executionState = waitForJob(executionId)

def logs = getLogs(executionId)
Map<String, Integer> ansibleNodeExecutionStatus = TestUtil.getAnsibleNodeResult(logs)

then:
executionState!=null
executionState.getExecutionState()=="SUCCEEDED"
ansibleNodeExecutionStatus.get("ok")!=0
ansibleNodeExecutionStatus.get("unreachable")==0
ansibleNodeExecutionStatus.get("failed")==0
ansibleNodeExecutionStatus.get("skipped")==0
ansibleNodeExecutionStatus.get("ignored")==0
logs.findAll {it.log.contains("plugin group set getAnsibleConfigFilePath: /home/rundeck/ansible")}.size() == 1
logs.findAll {it.log.contains("plugin group set getEncryptExtraVars: true")}.size() == 1
logs.findAll {it.log.contains("ANSIBLE_CONFIG: /home/rundeck/ansible")}.size() == 1
logs.findAll {it.log.contains("encryptVariable password")}.size() == 1
logs.findAll {it.log.contains("encryptVariable username")}.size() == 1
logs.findAll {it.log.contains("\"msg\": \"rundeck\"")}.size() == 1
logs.findAll {it.log.contains("\"msg\": \"demo\"")}.size() == 1

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class RundeckCompose extends DockerComposeContainer<RundeckCompose> {
}

//import project
File projectFile = TestUtil.createArchiveJarFile(projectName, new File("src/test/resources/project-import/ansible-test"))
File projectFile = TestUtil.createArchiveJarFile(projectName, new File("src/test/resources/project-import/" + projectName))
RequestBody body = RequestBody.create(projectFile, Client.MEDIA_TYPE_ZIP)
client.apiCall(api ->
api.importProjectArchive(projectName, "preserve", true, true, true, true, true, true, true, [:], body)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package functional

import org.rundeck.client.api.RundeckApi
import org.rundeck.client.api.model.ExecLog
import org.rundeck.client.api.model.ExecOutput
import org.rundeck.client.api.model.ExecutionStateResponse
import org.rundeck.client.util.Client
import spock.lang.Shared
import spock.lang.Specification

class TestConfiguration extends Specification{

@Shared
Client<RundeckApi> client

ExecutionStateResponse waitForJob(String executionId){
def finalStatus = [
'aborted',
'failed',
'succeeded',
'timedout',
'other'
]

while(true) {
ExecutionStateResponse result=client.apiCall { api-> api.getExecutionState(executionId)}
if (finalStatus.contains(result?.getExecutionState()?.toLowerCase())) {
return result
} else {
sleep (10000)
}
}

}


List<ExecLog> getLogs(String executionId){
def offset = 0
def maxLines = 1000
def lastmod = 0
boolean isCompleted = false

List<ExecLog> logs = []

while (!isCompleted){
ExecOutput result = client.apiCall { api -> api.getOutput(executionId, offset,lastmod, maxLines)}
isCompleted = result.completed
offset = result.offset
lastmod = result.lastModified

logs.addAll(result.entries)

if(result.unmodified){
sleep(5000)
}else{
sleep(2000)
}
}

return logs
}
}
3 changes: 3 additions & 0 deletions functional-test/src/test/resources/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ services:
RUNDECK_GRAILS_URL: http://localhost:4440
RUNDECK_MULTIURL_ENABLED: "true"
RUNDECK_SERVER_FORWARDED: "true"
RUNDECK_FEATURE_PLUGINGROUPS_ENABLED: "true"
RUNDECK_FEATURE_PLUGINGROUPS_NAME: "pluginGroups"

networks:
- rundeck
ports:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
by:
urn: project:ansible-plugin-group-test
for:
storage:
- match:
path: 'keys/.*'
allow: [read]
description: Allow access to key storage
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#Exported configuration
project.PluginGroup.AnsiblePluginGroup.enabled=true
project.description=
project.disable.executions=false
project.disable.schedule=false
project.execution.history.cleanup.batch=500
project.execution.history.cleanup.enabled=false
project.execution.history.cleanup.retention.days=60
project.execution.history.cleanup.retention.minimum=50
project.execution.history.cleanup.schedule=0 0 0 1/1 * ? *
project.jobs.gui.groupExpandLevel=1
project.label=
project.later.executions.disable=false
project.later.executions.enable=false
project.later.schedule.disable=false
project.later.schedule.enable=false
project.name=ansible-plugin-group-test
project.nodeCache.enabled=true
project.nodeCache.firstLoadSynch=true
project.output.allowUnsanitized=false
project.plugin.PluginGroup.AnsiblePluginGroup.ansibleConfigFilePath=/home/rundeck/ansible
project.plugin.PluginGroup.AnsiblePluginGroup.encryptExtraVars=true
project.retry-counter=3
project.ssh-authentication=privateKey
resources.source.1.type=local
resources.source.2.config.ansible-config-file-path=/home/rundeck/ansible
resources.source.2.config.ansible-gather-facts=true
resources.source.2.config.ansible-ignore-errors=true
resources.source.2.config.ansible-ssh-auth-type=privateKey
resources.source.2.config.ansible-ssh-key-storage-path=keys/project/ansible-plugin-group-test/ssh-node.key
resources.source.2.config.ansible-ssh-user=rundeck
resources.source.2.type=com.batix.rundeck.plugins.AnsibleResourceModelSourceFactory
service.FileCopier.default.provider=sshj-scp
service.NodeExecutor.default.provider=sshj-ssh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='password' secure='true' storagePath='keys/project/ansible-plugin-group-test/ssh-node.pass' valueExposed='true' />
<option name='username' value='rundeck' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<dispatch>
<excludePrecedence>true</excludePrecedence>
<keepgoing>false</keepgoing>
<rankOrder>ascending</rankOrder>
<successOnEmptyNodeFilter>false</successOnEmptyNodeFilter>
<threadcount>1</threadcount>
</dispatch>
<executionEnabled>true</executionEnabled>
<id>572367d2-e41a-4fdb-b6fc-effa32185b61</id>
<loglevel>INFO</loglevel>
<name>simple-inline-playbook-env-vars</name>
<nodeFilterEditable>false</nodeFilterEditable>
<nodefilters>
<filter>name: ssh-node </filter>
</nodefilters>
<nodesSelectedByDefault>true</nodesSelectedByDefault>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<node-step-plugin type='com.batix.rundeck.plugins.AnsiblePlaybookInlineWorkflowNodeStep'>
<configuration>
<entry key='ansible-become' value='false' />
<entry key='ansible-encrypt-extra-vars' value='false' />
<entry key='ansible-extra-vars' value='password: ${option.password}&#10;username: ${option.username}&#10;test: "demo"' />
<entry key='ansible-playbook-inline' value='- hosts: all&#10; gather_facts: false&#10; tasks:&#10;&#10; - name: Hello World!&#10; debug:&#10; msg: "Hello World!"&#10; - name: Get Disk Space&#10; shell: "df -h"&#10; register: sh_output&#10;&#10; - debug: var=sh_output.stdout_lines&#10; - debug: msg="{{ username }}"&#10; - debug: msg="{{ test }}"&#10; ' />
<entry key='ansible-ssh-auth-type' value='privateKey' />
<entry key='ansible-ssh-key-storage-path' value='keys/project/ansible-plugin-group-test/ssh-node.key' />
<entry key='ansible-ssh-passphrase-option' value='option.password' />
<entry key='ansible-ssh-use-agent' value='false' />
<entry key='ansible-ssh-user' value='rundeck' />
</configuration>
</node-step-plugin>
</command>
</sequence>
<uuid>572367d2-e41a-4fdb-b6fc-effa32185b61</uuid>
</job>
</joblist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<joblist>
<job>
<defaultTab>nodes</defaultTab>
<description></description>
<dispatch>
<excludePrecedence>true</excludePrecedence>
<keepgoing>false</keepgoing>
<rankOrder>ascending</rankOrder>
<successOnEmptyNodeFilter>false</successOnEmptyNodeFilter>
<threadcount>1</threadcount>
</dispatch>
<executionEnabled>true</executionEnabled>
<id>fa0e401b-b5a8-436a-b13b-0e8092858021</id>
<loglevel>INFO</loglevel>
<name>simple-inline-playbook</name>
<nodeFilterEditable>false</nodeFilterEditable>
<nodefilters>
<filter>name: ssh-node </filter>
</nodefilters>
<nodesSelectedByDefault>true</nodesSelectedByDefault>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<node-step-plugin type='com.batix.rundeck.plugins.AnsiblePlaybookInlineWorkflowNodeStep'>
<configuration>
<entry key='ansible-become' value='false' />
<entry key='ansible-encrypt-extra-vars' value='false' />
<entry key='ansible-playbook-inline' value='- hosts: all&#10; gather_facts: false&#10; tasks:&#10;&#10; - name: Hello World!&#10; debug:&#10; msg: "Hello World!"&#10; - name: Get Disk Space&#10; shell: "df -h"&#10; register: sh_output&#10;&#10; - debug: var=sh_output.stdout_lines' />
<entry key='ansible-ssh-auth-type' value='privateKey' />
<entry key='ansible-ssh-key-storage-path' value='keys/project/ansible-plugin-group-test/ssh-node.key' />
<entry key='ansible-ssh-passphrase-option' value='option.password' />
<entry key='ansible-ssh-use-agent' value='false' />
<entry key='ansible-ssh-user' value='rundeck' />
</configuration>
</node-step-plugin>
</command>
</sequence>
<uuid>fa0e401b-b5a8-436a-b13b-0e8092858021</uuid>
</job>
</joblist>
Loading

0 comments on commit f6da910

Please sign in to comment.