Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose delete executions for plugins #2709

Merged
merged 3 commits into from Aug 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -11,10 +11,12 @@ public interface ExecutionReference {
String getOptions();
JobReference getJob();
Date getDateStarted();
Date getDateCompleted();
String getStatus();
String getSucceededNodeList();
String getFailedNodeList();
String getTargetNodes();
String getAdhocCommand();


}
34 changes: 33 additions & 1 deletion core/src/main/java/com/dtolabs/rundeck/core/jobs/JobService.java
Expand Up @@ -19,8 +19,10 @@
import com.dtolabs.rundeck.core.execution.ExecutionNotFound;
import com.dtolabs.rundeck.core.execution.ExecutionReference;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* Service for interacting with Jobs
Expand Down Expand Up @@ -76,7 +78,22 @@ public interface JobService {
* @return a list of references to executions using the input parameters
*
*/
List<ExecutionReference> searchExecutions(String state, String project, String jobUuid, String excludeJobUuid, String since);
List<ExecutionReference> searchExecutions(String state, String project, String jobUuid, String excludeJobUuid,
String since);

/**
* @param state to search
* @param project the project
* @param jobUuid to search or null
* @param excludeJobUuid to search or null
* @param since to search or null
* @param reverseSince if true search executions older than since parameter
*
* @return a list of references to executions using the input parameters
*
*/
List<ExecutionReference> searchExecutions(String state, String project, String jobUuid, String excludeJobUuid,
String since, boolean reverseSince);

/**
* @param id execution id
Expand All @@ -97,4 +114,19 @@ public interface JobService {
* @return Id of the result execution
*/
String startJob(JobReference jobReference, String jobArgString, String jobFilter, String asUser)throws JobNotFound;

/**
*
* @param ids collection of id to iterate
* @param asUser user to execute delete (null for the same user)
* @return [success:true/false, failures:[ [success:false, message: String, id: id],... ], successTotal:Integer]
*/
Map deleteBulkExecutionIds(Collection ids, String asUser);

/**
*
* @param filter for query executions
* @return map with results and total
*/
Map queryExecutions(Map filter);
}
Expand Up @@ -16,6 +16,7 @@

package rundeck.services

import com.dtolabs.rundeck.app.support.ExecutionQuery
import com.dtolabs.rundeck.core.authentication.Group
import com.dtolabs.rundeck.core.authentication.Username
import com.dtolabs.rundeck.core.authorization.Attribute
Expand Down Expand Up @@ -1056,4 +1057,22 @@ class FrameworkService implements ApplicationContextAware {
Map kickJob(ScheduledExecution scheduledExecution, UserAndRolesAuthContext authContext, String user, Map input){
executionService.executeJob(scheduledExecution, authContext, user, input)
}

/**
* non transactional interface to bulk delete executions
* {@link ExecutionService#deleteBulkExecutionIds deleteBulkExecutionIds}
* @return [success:true/false, failures:[ [success:false, message: String, id: id],... ], successTotal:Integer]
*/
Map deleteBulkExecutionIds(Collection ids, AuthContext authContext, String username) {
executionService.deleteBulkExecutionIds(ids,authContext,username)
}

/**
* non transactional interface to query executions
* {@link ExecutionService#queryExecutions queryExecutions}
* @return [result:result,total:total]
*/
Map queryExecutions(ExecutionQuery query, int offset=0, int max=-1) {
executionService.queryExecutions(query,offset,max)
}
}
124 changes: 118 additions & 6 deletions rundeckapp/grails-app/services/rundeck/services/JobStateService.groovy
Expand Up @@ -17,6 +17,7 @@
package rundeck.services

import com.dtolabs.rundeck.app.support.BaseNodeFilters
import com.dtolabs.rundeck.app.support.ExecutionQuery
import com.dtolabs.rundeck.core.authorization.AuthContext
import com.dtolabs.rundeck.core.authorization.UserAndRolesAuthContext
import com.dtolabs.rundeck.core.common.Framework
Expand Down Expand Up @@ -122,11 +123,17 @@ class JobStateService implements AuthorizingJobService {
@Override
List<ExecutionReference> searchExecutions(AuthContext auth, String state, String project, String jobUuid,
String excludeJobUuid, String since){
searchExecutions(auth,state,project,jobUuid,excludeJobUuid,since,false)
}

List<ExecutionReference> searchExecutions(AuthContext auth, String state, String project, String jobUuid,
String excludeJobUuid, String since, boolean reverseSince){

def executions = Execution.createCriteria().list {
eq('project',project)
eq('status', state)
if(state){
eq('status', state)
}
createAlias('scheduledExecution', 'se')
if(jobUuid){
isNotNull 'scheduledExecution'
Expand All @@ -142,7 +149,12 @@ class JobStateService implements AuthorizingJobService {
long timeAgo = Sizes.parseTimeDuration(since,TimeUnit.MILLISECONDS)
Date sinceDt = new Date()
sinceDt.setTime(sinceDt.getTime()-timeAgo)
ge 'dateStarted',sinceDt
if(reverseSince){
le 'dateStarted',sinceDt
}else{
ge 'dateStarted',sinceDt
}

}

}
Expand Down Expand Up @@ -217,11 +229,14 @@ class JobStateService implements AuthorizingJobService {
throw new ExecutionNotFound("Execution not found", id, project)
}

JobReferenceImpl jobRef = new JobReferenceImpl(id: se.extid, jobName: se.jobName, groupPath: se.groupPath,
project: se.project)
JobReferenceImpl jobRef
if(se) {
jobRef = new JobReferenceImpl(id: se.extid, jobName: se.jobName, groupPath: se.groupPath,
project: se.project)
}
new ExecutionReferenceImpl(id:exec.id, options: exec.argString, filter: exec.filter, job: jobRef,
dateStarted: exec.dateStarted, status: exec.status, succeededNodeList: exec.succeededNodeList,
failedNodeList: exec.failedNodeList)
dateStarted: exec.dateStarted, status: exec.status, succeededNodeList: exec.succeededNodeList,
dateCompleted:exec.dateCompleted, failedNodeList: exec.failedNodeList)

}

Expand Down Expand Up @@ -258,4 +273,101 @@ class JobStateService implements AuthorizingJobService {
}
return resultExecution
}


@Override
Map deleteBulkExecutionIds(AuthContext auth, Collection ids, String asUser){
frameworkService.deleteBulkExecutionIds(ids,auth, asUser)
}

@Override
Map queryExecutions(AuthContext auth,Map filter){
ExecutionQuery query = new ExecutionQuery()
query.projFilter = filter.project
int offset = filter.offset?:0
query.offset = offset
int max = filter.max?:0
query.max = max
if(filter.recentFilter){
query.recentFilter = filter.recentFilter
query.configureFilter()
}
if (filter.olderFilter) {
Date endDate=ExecutionQuery.parseRelativeDate(filter.olderFilter)
if(null!=endDate){
query.endbeforeFilter = endDate
query.doendbeforeFilter = true
}
}
if(filter.statusFilter){
query.statusFilter = filter.statusFilter
}
if(filter.userFilter){
query.userFilter = filter.userFilter
}
if(filter.adhoc){
query.adhoc = true
}else if(filter.jobonly){
query.adhoc = false
}
if(filter.groupPath){
query.groupPath = filter.groupPath
}
if(filter.groupPathExact){
query.groupPathExact = filter.groupPathExact
}
if(filter.excludeGroupPath){
query.excludeGroupPath = filter.excludeGroupPath
}
if(filter.excludeGroupPathExact){
query.excludeGroupPathExact = filter.excludeGroupPathExact
}
if(filter.jobFilter){
query.jobFilter = filter.jobFilter
}
if(filter.excludeJobFilter){
query.excludeJobFilter = filter.excludeJobFilter
}
if(filter.excludeJobExactFilter){
query.excludeJobExactFilter = filter.excludeJobExactFilter
}
if(filter.jobExactFilter){
query.jobExactFilter = filter.jobExactFilter
}
if(filter.excludeJobIdListFilter){
query.excludeJobIdListFilter = filter.excludeJobIdListFilter.tokenize(',')
}
if(filter.excludeJobListFilter){
query.excludeJobListFilter = filter.excludeJobListFilter.tokenize(',')
}
if(filter.jobListFilter){
query.jobListFilter = filter.jobListFilter.tokenize(',')
}
if(filter.jobIdListFilter){
query.jobIdListFilter = filter.jobIdListFilter.tokenize(',')
}
def results = frameworkService.queryExecutions(query, offset, max)
def result=results.result
def total=results.total
//filter query results to READ authorized executions
def filtered = frameworkService.filterAuthorizedProjectExecutionsAll(auth,result,[AuthConstants.ACTION_READ])
def idList = []
filtered.each { Execution exec->
ScheduledExecution se = exec.scheduledExecution
JobReferenceImpl jobRef
if(se){
jobRef = new JobReferenceImpl(id: se.extid, jobName: se.jobName, groupPath: se.groupPath,
project: se.project)
}
ExecutionReferenceImpl execRef = new ExecutionReferenceImpl(id:exec.id, options: exec.argString,
filter: exec.filter, job: jobRef, dateStarted: exec.dateStarted, dateCompleted:exec.dateCompleted,
status: exec.status, succeededNodeList: exec.succeededNodeList,
failedNodeList: exec.failedNodeList)
if(!se && exec.workflow && exec.workflow.commands && exec.workflow.commands[0]){
execRef.adhocCommand = exec.workflow.commands[0].summarize()
}
idList.push(execRef)
}
return [result:idList, total:idList.size()]
}
}
Expand Up @@ -10,10 +10,12 @@ class ExecutionReferenceImpl implements ExecutionReference {
String id
JobReferenceImpl job
Date dateStarted
Date dateCompleted
String status
String succeededNodeList
String failedNodeList
String targetNodes
String adhocCommand

@Override
String toString() {
Expand Down
Expand Up @@ -36,10 +36,18 @@ interface AuthorizingJobService {

JobState getJobState(AuthContext auth, JobReference jobReference) throws JobNotFound;

List<ExecutionReference> searchExecutions(AuthContext auth, String state, String project, String jobUuid, String excludeJobUuid, String since)
List<ExecutionReference> searchExecutions(AuthContext auth, String state, String project, String jobUuid,
String excludeJobUuid, String since)

List<ExecutionReference> searchExecutions(AuthContext auth, String state, String project, String jobUuid,
String excludeJobUuid, String since, boolean reverseSince)

ExecutionReference executionForId(AuthContext auth, String id, String project) throws ExecutionNotFound

String startJob(AuthContext auth, JobReference jobReference, String jobArgString, String jobFilter, String asUser) throws JobNotFound

Map deleteBulkExecutionIds(AuthContext auth, Collection ids, String asUser)

Map queryExecutions(AuthContext auth,Map filter)

}
Expand Up @@ -51,6 +51,11 @@ class ResolvedAuthJobService implements JobService {
authJobService.getJobState(authContext, jobReference)
}

List<ExecutionReference> searchExecutions(String state, String project, String job, String excludeJob,
String since, boolean reverseSince){
authJobService.searchExecutions(authContext, state, project, job, excludeJob, since, reverseSince)
}

List<ExecutionReference> searchExecutions(String state, String project, String job, String excludeJob, String since){
authJobService.searchExecutions(authContext, state, project, job, excludeJob, since)
}
Expand All @@ -64,4 +69,12 @@ class ResolvedAuthJobService implements JobService {
authJobService.startJob(authContext, jobReference, jobArgString, jobFilter, asUser)
}

Map deleteBulkExecutionIds(Collection ids, String asUser){
authJobService.deleteBulkExecutionIds(authContext, ids, asUser)
}

Map queryExecutions(Map filter){
authJobService.queryExecutions(authContext, filter)
}

}
33 changes: 32 additions & 1 deletion rundeckapp/test/unit/rundeck/services/JobStateServiceSpec.groovy
Expand Up @@ -16,6 +16,8 @@

package rundeck.services

import com.dtolabs.rundeck.app.support.ExecutionQuery
import com.dtolabs.rundeck.core.authorization.AuthContext
import com.dtolabs.rundeck.core.authorization.SubjectAuthContext
import com.dtolabs.rundeck.core.dispatcher.ExecutionState
import com.dtolabs.rundeck.core.execution.ExecutionNotFound
Expand Down Expand Up @@ -495,7 +497,36 @@ class JobStateServiceSpec extends Specification {
}



def "queryExecutions simple params"() {
setup:
def auth = Mock(AuthContext)
service.frameworkService = Mock(FrameworkService)
def mockExec = Mock(Execution)
when:
def result = service.queryExecutions(auth, filter)
then:
result
result.total == expTotal
1 * service.frameworkService.queryExecutions(_, 0, 0) >> {ExecutionQuery query,offset,max ->
if(query.adhoc){
return [result: [mockExec], total: 1]
}
if(query.jobIdListFilter){
return [result: [mockExec,mockExec], total: 2]
}
[result: [], total: 0]
}
1 * service.frameworkService.filterAuthorizedProjectExecutionsAll(_, _, [AuthConstants.ACTION_READ]) >>
{authcontext, inputArr, actions ->
return inputArr
}
where:
filter | expTotal
[:] | 0
[adhoc:true] | 1
[jobonly:true] | 0
[jobIdListFilter:'1,2'] | 2
}


def setTestExecutions(projectName, jobUuid){
Expand Down