Skip to content

Commit

Permalink
Merge pull request #2617 from variacode/dev/search-executions-state
Browse files Browse the repository at this point in the history
Search executions and retry jobs for plugins
  • Loading branch information
gschueler committed Jul 18, 2017
2 parents fecc681 + 883be13 commit a983d0a
Show file tree
Hide file tree
Showing 9 changed files with 381 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.dtolabs.rundeck.core.execution;


public class ExecutionNotFound extends Exception{

private String executionId;
private String project;


public ExecutionNotFound(String message, String executionId, String project){
super(message);
this.executionId = executionId;
this.project = project;
}

public String getExecutionId() {
return executionId;
}

public String getProject() {
return project;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.dtolabs.rundeck.core.execution;


import com.dtolabs.rundeck.core.jobs.JobReference;

import java.util.Date;

public interface ExecutionReference {
String getId();
String getFilter();
String getOptions();
JobReference getJob();
Date getDateStarted();
String getStatus();
String getSucceededNodeList();
String getFailedNodeList();
String getTargetNodes();


}
39 changes: 39 additions & 0 deletions core/src/main/java/com/dtolabs/rundeck/core/jobs/JobService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

package com.dtolabs.rundeck.core.jobs;

import com.dtolabs.rundeck.core.execution.ExecutionNotFound;
import com.dtolabs.rundeck.core.execution.ExecutionReference;

import java.util.Date;
import java.util.List;

/**
* Service for interacting with Jobs
*/
Expand Down Expand Up @@ -58,4 +64,37 @@ public interface JobService {
* @return state of the job
*/
JobState getJobState(JobReference jobReference) throws JobNotFound;


/**
* @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
*
* @return a list of references to executions using the input parameters
*
*/
List<ExecutionReference> searchExecutions(String state, String project, String jobUuid, String excludeJobUuid, String since);

/**
* @param id execution id
* @param project the project
*
* @return a execution reference for the id
*
* @throws com.dtolabs.rundeck.core.execution.ExecutionNotFound if the execution was not found
*/
ExecutionReference executionForId(String id, String project) throws ExecutionNotFound;


/**
* @param jobReference reference to a job
* @param jobArgString argString for the execution
* @param jobFilter filter for the execution
* @param asUser user to execute the job(null for the same user)
* @return Id of the result execution
*/
String startJob(JobReference jobReference, String jobArgString, String jobFilter, String asUser)throws JobNotFound;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1044,4 +1044,13 @@ class FrameworkService implements ApplicationContextAware {
}
return charsetname
}

/**
* non transactional interface to run a job from plugins
* {@link ExecutionService#executeJob executeJob}
* @return Map of the execution result.
*/
Map kickJob(ScheduledExecution scheduledExecution, UserAndRolesAuthContext authContext, String user, Map input){
executionService.executeJob(scheduledExecution, authContext, user, input)
}
}
154 changes: 154 additions & 0 deletions rundeckapp/grails-app/services/rundeck/services/JobStateService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,33 @@

package rundeck.services

import com.dtolabs.rundeck.app.support.BaseNodeFilters
import com.dtolabs.rundeck.core.authorization.AuthContext
import com.dtolabs.rundeck.core.authorization.UserAndRolesAuthContext
import com.dtolabs.rundeck.core.common.Framework
import com.dtolabs.rundeck.core.common.INodeEntry
import com.dtolabs.rundeck.core.common.INodeSet
import com.dtolabs.rundeck.core.common.NodeFilter
import com.dtolabs.rundeck.core.common.NodeSetImpl
import com.dtolabs.rundeck.core.dispatcher.ExecutionState
import com.dtolabs.rundeck.core.execution.ExecutionNotFound
import com.dtolabs.rundeck.core.execution.ExecutionReference
import com.dtolabs.rundeck.core.jobs.JobNotFound
import com.dtolabs.rundeck.core.jobs.JobReference
import com.dtolabs.rundeck.core.jobs.JobService
import com.dtolabs.rundeck.core.jobs.JobState
import com.dtolabs.rundeck.core.utils.NodeSet
import com.dtolabs.rundeck.server.authorization.AuthConstants
import grails.transaction.Transactional
import org.rundeck.util.Sizes
import rundeck.Execution
import rundeck.ScheduledExecution
import rundeck.services.execution.ExecutionReferenceImpl
import rundeck.services.jobs.AuthorizingJobService
import rundeck.services.jobs.ResolvedAuthJobService

import java.util.concurrent.TimeUnit

@Transactional
class JobStateService implements AuthorizingJobService {
def frameworkService
Expand Down Expand Up @@ -104,4 +118,144 @@ class JobStateService implements AuthorizingJobService {
JobService jobServiceWithAuthContext(AuthContext auth) {
return new ResolvedAuthJobService(authContext: auth, authJobService: this)
}

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


def executions = Execution.createCriteria().list {
eq('project',project)
eq('status', state)
createAlias('scheduledExecution', 'se')
if(jobUuid){
isNotNull 'scheduledExecution'
eq 'se.uuid',jobUuid
}
if(excludeJobUuid){
or{
isNull('scheduledExecution')
ne 'se.uuid',excludeJobUuid
}
}
if(since){
long timeAgo = Sizes.parseTimeDuration(since,TimeUnit.MILLISECONDS)
Date sinceDt = new Date()
sinceDt.setTime(sinceDt.getTime()-timeAgo)
ge 'dateStarted',sinceDt
}

}
executions = frameworkService.filterAuthorizedProjectExecutionsAll(auth,executions,[AuthConstants.ACTION_READ])

ArrayList<ExecutionReference> list = new ArrayList<>()
Framework framework = frameworkService.getRundeckFramework()
def frameworkProject = framework.getFrameworkProjectMgr().getFrameworkProject(project)
INodeSet allNodes = frameworkProject.getNodeSet()

executions.each { exec ->
ScheduledExecution job = exec.scheduledExecution
JobReferenceImpl jobRef = null
if(job) {
jobRef = new JobReferenceImpl(id: job.extid, jobName: job.jobName,
groupPath: job.groupPath, project: job.project)
}
StringBuilder targetNode = new StringBuilder()
if(!exec.filter){
targetNode.append(framework.getFrameworkNodeName())
}else{
NodeSet filterNodeSet = filtersAsNodeSet([
filter:exec.filter,
nodeExcludePrecedence:exec.nodeExcludePrecedence,
nodeThreadcount: exec.nodeThreadcount,
nodeKeepgoing: exec.nodeKeepgoing
])
INodeSet nodeSet = NodeFilter.filterNodes(filterNodeSet, allNodes)
Iterator<INodeEntry> it = nodeSet.getNodes().iterator()
while(it.hasNext()){
INodeEntry node = it.next()
targetNode.append(node.nodename)
if(it.hasNext()){
targetNode.append(',')
}
}
}
ExecutionReferenceImpl execRef = 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,
targetNodes: targetNode.toString())
list.add(execRef)
}
return list
}

NodeSet filtersAsNodeSet(Map econtext) {
final NodeSet nodeset = new NodeSet();
nodeset.createExclude(BaseNodeFilters.asExcludeMap(econtext)).setDominant(econtext.nodeExcludePrecedence?true:false);
nodeset.createInclude(BaseNodeFilters.asIncludeMap(econtext)).setDominant(!econtext.nodeExcludePrecedence?true:false);
nodeset.setKeepgoing(econtext.nodeKeepgoing?true:false)
nodeset.setThreadCount(econtext.nodeThreadcount?econtext.nodeThreadcount:1)
return nodeset
}

@Override
ExecutionReference executionForId(AuthContext auth, String id, String project) throws ExecutionNotFound{
long exid = Long.valueOf(id)
def exec = Execution.findByIdAndProject(exid,project)
if(!exec){
throw new ExecutionNotFound("Execution not found", id, project)
}
ScheduledExecution se = exec.scheduledExecution
def isAuth = null
if(se){
isAuth=frameworkService.authorizeProjectJobAll(auth, se, [AuthConstants.ACTION_READ], se.project)
}else if(!se){
isAuth=frameworkService.authorizeProjectResourceAll(auth, AuthConstants.RESOURCE_ADHOC, [AuthConstants.ACTION_READ],
exec.project)
}
if(!isAuth){
throw new ExecutionNotFound("Execution not found", id, project)
}

JobReferenceImpl 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)

}


@Override
String startJob(AuthContext auth, JobReference jobReference, String jobArgString, String jobFilter, String asUser) throws JobNotFound {
def inputOpts = [:]
inputOpts["argString"] = jobArgString
if (jobFilter) {
def filters = [filter:jobFilter]
inputOpts['_replaceNodeFilters']='true'
inputOpts['doNodedispatch']=true
filters.each {k, v ->
inputOpts[k] = v
}
if(null== inputOpts['nodeExcludePrecedence']){
inputOpts['nodeExcludePrecedence'] = true
}
}

inputOpts['executionType'] = 'user'
String resultExecution = "";

def se = ScheduledExecution.findByUuidAndProject(jobReference.id, jobReference.project)
if (!se || !frameworkService.authorizeProjectJobAll(auth, se, [AuthConstants.ACTION_READ], se.project)) {
throw new JobNotFound("Not found", jobReference.id, jobReference.project)
}
if(auth instanceof UserAndRolesAuthContext) {
def result = frameworkService.kickJob(se,
auth, asUser, inputOpts)
if(result && result.executionId){
resultExecution += result.executionId
}
}
return resultExecution
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package rundeck.services.execution

import com.dtolabs.rundeck.core.execution.ExecutionReference
import rundeck.services.JobReferenceImpl


class ExecutionReferenceImpl implements ExecutionReference {
String options
String filter
String id
JobReferenceImpl job
Date dateStarted
String status
String succeededNodeList
String failedNodeList
String targetNodes

@Override
String toString() {
return "ExecutionReference{" +
"id='" + id + '\'' +
", status='" + status + '\'' +
", filter='" + filter + '\'' +
", options='" + options + '\'' +
", job='" + job + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package rundeck.services.jobs

import com.dtolabs.rundeck.core.authorization.AuthContext
import com.dtolabs.rundeck.core.execution.ExecutionNotFound
import com.dtolabs.rundeck.core.execution.ExecutionReference
import com.dtolabs.rundeck.core.jobs.JobNotFound
import com.dtolabs.rundeck.core.jobs.JobReference
import com.dtolabs.rundeck.core.jobs.JobState
Expand All @@ -33,4 +35,11 @@ interface AuthorizingJobService {
JobReference jobForName(AuthContext auth, String group, String name, String project) throws JobNotFound;

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

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

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

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package rundeck.services.jobs

import com.dtolabs.rundeck.core.authorization.AuthContext
import com.dtolabs.rundeck.core.execution.ExecutionReference
import com.dtolabs.rundeck.core.execution.ExecutionNotFound
import com.dtolabs.rundeck.core.jobs.JobNotFound
import com.dtolabs.rundeck.core.jobs.JobReference
import com.dtolabs.rundeck.core.jobs.JobService
Expand Down Expand Up @@ -48,4 +50,18 @@ class ResolvedAuthJobService implements JobService {
JobState getJobState(JobReference jobReference) throws JobNotFound {
authJobService.getJobState(authContext, jobReference)
}

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

ExecutionReference executionForId(String id, String project) throws ExecutionNotFound{
authJobService.executionForId(authContext, id, project)
}


String startJob(JobReference jobReference, String jobArgString, String jobFilter, String asUser) throws JobNotFound{
authJobService.startJob(authContext, jobReference, jobArgString, jobFilter, asUser)
}

}
Loading

0 comments on commit a983d0a

Please sign in to comment.