Skip to content

Commit

Permalink
Merge pull request #7856 from rundeck/RUN-1072-job-remote-option-url-…
Browse files Browse the repository at this point in the history
…retry-connection-parameter-not-honored

RSE-9-job-remote-option-url-retry-connection-parameter-not-honored
  • Loading branch information
Jesus-Osuna-M committed Aug 18, 2022
2 parents 9808767 + 4b71672 commit 95cb59f
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 49 deletions.
Expand Up @@ -58,6 +58,18 @@ public class RundeckConfigBase {
RundeckApiConfig api;
ScmLoader scmLoader;
RundeckHealthIndicatorConfig health;
RundeckJobsConfig jobs;

@Data public static class RundeckJobsConfig{
JobOptionsConfig options;
}

@Data
public static class JobOptionsConfig{
int remoteUrlTimeout;
int remoteUrlConnectionTimeout;
int remoteUrlRetry;
}

@Data
public static class UserSessionProjectsCache {
Expand Down
Expand Up @@ -842,9 +842,6 @@ class ScheduledExecutionController extends ControllerBase{
client.setFollowRedirects(true)
client.setTimeout(timeout*1000)

if(retry>0) {
client.setRetryCount(retry)
}

URL urlo
String cleanUrl = url.replaceAll("^(https?://)([^:@/]+):[^@/]*@", '$1$2:****@');
Expand Down
Expand Up @@ -3840,6 +3840,8 @@ class ScheduledExecutionService implements ApplicationContextAware, Initializing
int timeout = 10
int contimeout = 0
int retryCount = 5
int httpResponseCode = 0

if (configurationService.getString("jobs.options.remoteUrlTimeout")) {
try {
timeout = configurationService.getInteger("jobs.options.remoteUrlTimeout", null)
Expand Down Expand Up @@ -3911,32 +3913,47 @@ class ScheduledExecutionService implements ApplicationContextAware, Initializing
}
}
}
try {
def framework = frameworkService.getRundeckFramework()
def projectConfig = framework.frameworkProjectMgr.loadProjectConfig(scheduledExecution.project)
boolean disableRemoteOptionJsonCheck = projectConfig.hasProperty(REMOTE_OPTION_DISABLE_JSON_CHECK)

remoteResult = ScheduledExecutionController.getRemoteJSON(srcUrl, timeout, contimeout, retryCount, disableRemoteOptionJsonCheck)
result = remoteResult.json
if (remoteResult.stats) {
remoteStats.putAll(remoteResult.stats)
}
} catch (Exception e) {
err.message = "Failed loading remote option values"
err.exception = e
err.srcUrl = cleanUrl
log.error("getRemoteJSON error: URL ${cleanUrl} : ${e.message}");
e.printStackTrace()
remoteStats.finishTime = System.currentTimeMillis()
remoteStats.durationTime = remoteStats.finishTime - remoteStats.startTime
}
if (remoteResult.error) {
err.message = "Failed loading remote option values"
err.exception = new Exception(remoteResult.error)
err.srcUrl = cleanUrl
log.error("getRemoteJSON error: URL ${cleanUrl} : ${remoteResult.error}");
}
logRemoteOptionStats(remoteStats, [jobName: scheduledExecution.generateFullName(), id: scheduledExecution.extid, jobProject: scheduledExecution.project, optionName: mapConfig.option, user: username])
int count = retryCount

//cycle to retry if getRemoteJSON dont get the remote values
do{
try {
//validate if not the firt attemp
if(retryCount > count){
Thread.sleep(contimeout*1000)
}
def framework = frameworkService.getRundeckFramework()
def projectConfig = framework.frameworkProjectMgr.loadProjectConfig(scheduledExecution.project)
boolean disableRemoteOptionJsonCheck = projectConfig.hasProperty(REMOTE_OPTION_DISABLE_JSON_CHECK)

remoteResult = ScheduledExecutionController.getRemoteJSON(srcUrl, timeout, contimeout, retryCount, disableRemoteOptionJsonCheck)
result = remoteResult.json
if (remoteResult.stats) {
remoteStats.putAll(remoteResult.stats)
if(remoteResult.stats.httpStatusCode){
httpResponseCode = remoteResult.stats.httpStatusCode
}
}
} catch (Exception e) {
err.message = "Failed loading remote option values"
err.exception = e
err.srcUrl = cleanUrl
log.error("getRemoteJSON error: URL ${cleanUrl} : ${e.message}");
e.printStackTrace()
remoteStats.finishTime = System.currentTimeMillis()
remoteStats.durationTime = remoteStats.finishTime - remoteStats.startTime
}
if (remoteResult.error) {
err.message = "Failed loading remote option values"
err.exception = new Exception(remoteResult.error)
err.srcUrl = cleanUrl
log.error("getRemoteJSON error: URL ${cleanUrl} : ${remoteResult.error}");
}
logRemoteOptionStats(remoteStats, [jobName: scheduledExecution.generateFullName(), id: scheduledExecution.extid, jobProject: scheduledExecution.project, optionName: mapConfig.option, user: username])
count--
}while(count > 0 && (httpResponseCode < 200 || httpResponseCode > 300 ))

//validate result contents
boolean valid = true;
def validationerrors = []
Expand Down
Expand Up @@ -5523,51 +5523,51 @@ class ScheduledExecutionServiceSpec extends RundeckHibernateSpec implements Serv
result.nodeStepDescriptions[0].name=='test2'

}
def "load remote options timeout configuration"(){
given:
def "load remote options timeout configuration from url params"(){

given:"a option getting values from a URL"
def fwkservice=Mock(FrameworkService)
defineBeans{
frameworkService(InstanceFactoryBean,fwkservice)
}
service.configurationService = Mock(ConfigurationService)
service.frameworkService = fwkservice


when:"the connection values are set directly on the URL"
def se = new ScheduledExecution(jobName: 'monkey1', project: 'testProject', description: 'blah2')
se.addToOptions(new Option(
name:'test',
realValuesUrl: new URL('file://test')
name:'test',
realValuesUrl: new URL('file://test#timeout='+timeout+';contimeout='+conTimeout+';retry='+retry)
))
se.save()

_ * service.frameworkService.getRundeckFramework()>>Mock(IFramework){
_ * getFrameworkProjectMgr()>>Mock(ProjectManager){
_ * loadProjectConfig('testProject')
}
}

def input=[:]
ScheduledExecutionController.metaClass.static.getRemoteJSON={String url,int vtimeout, int vcontimeout, int vretry, boolean disableRemoteJsonCheck->
input.url=url
input.timeout=vtimeout
input.contimeout=vcontimeout
input.retry=vretry
[
json: [
'some', 'option', 'values'
]
json: [
'some', 'option', 'values'
]
]
}
when:
def result = service.loadOptionsRemoteValues(se,[option:'test'],'auser')
then:
input.url=='file://test'

then:"the values on the input should be the same as the spectec values "
input.url=='file://test#timeout='+timeout+';contimeout='+conTimeout+';retry='+retry
input.timeout==expectTimeout
input.contimeout==expectConTimeout
input.retry==expectRetry
result.values==['some','option','values']
1 * service.configurationService.getString("jobs.options.remoteUrlTimeout")>>timeout?.toString()
_ * service.configurationService.getInteger("jobs.options.remoteUrlTimeout", null) >> timeout
1 * service.configurationService.getString("jobs.options.remoteUrlConnectionTimeout")>>conTimeout?.toString()
_ * service.configurationService.getInteger("jobs.options.remoteUrlConnectionTimeout", null) >> conTimeout
1 * service.configurationService.getString("jobs.options.remoteUrlRetry")>>retry?.toString()
_ * service.configurationService.getInteger("jobs.options.remoteUrlRetry", null) >> retry
1 * service.frameworkService.getRundeckFramework()>>Mock(IFramework){
1 * getFrameworkProjectMgr()>>Mock(ProjectManager){
1 * loadProjectConfig('testProject')
}
}

where:
timeout | conTimeout | retry | expectTimeout | expectConTimeout | expectRetry
Expand All @@ -5576,6 +5576,98 @@ class ScheduledExecutionServiceSpec extends RundeckHibernateSpec implements Serv
null | null | null | 10 | 0 | 5
}

def "load remote options timeout configuration from config.properties"(){

given:"a option getting values from a URL"
def fwkservice=Mock(FrameworkService)
defineBeans{
frameworkService(InstanceFactoryBean,fwkservice)
}
service.configurationService = Mock(ConfigurationService)
service.frameworkService = fwkservice
def se = new ScheduledExecution(jobName: 'monkey1', project: 'testProject', description: 'blah2')
se.addToOptions(new Option(
name:'test',
realValuesUrl: new URL('file://test')
))
se.save()
def input=[:]
ScheduledExecutionController.metaClass.static.getRemoteJSON={String url,int vtimeout, int vcontimeout, int vretry, boolean disableRemoteJsonCheck->
input.url=url
input.timeout=vtimeout
input.contimeout=vcontimeout
input.retry=vretry
[
json: [
'some', 'option', 'values'
]
]
}

when:"the values are set on the config.properties"
service.configurationService.getString("jobs.options.remoteUrlTimeout") >> timeout
service.configurationService.getInteger("jobs.options.remoteUrlTimeout",null) >> timeout
service.configurationService.getString("jobs.options.remoteUrlConnectionTimeout") >> conTimeout
service.configurationService.getInteger("jobs.options.remoteUrlConnectionTimeout",null) >> conTimeout
service.configurationService.getString("jobs.options.remoteUrlRetry") >> retry
service.configurationService.getInteger("jobs.options.remoteUrlRetry",null) >> retry
_ * service.frameworkService.getRundeckFramework()>>Mock(IFramework){
_ * getFrameworkProjectMgr()>>Mock(ProjectManager){
_ * loadProjectConfig('testProject')
}
}
def result = service.loadOptionsRemoteValues(se,[option:'test'],'auser')

then:"values setted on the config.properties should be equals to input values"
input.url=='file://test'
input.timeout==expectTimeout
input.contimeout==expectConTimeout
input.retry==expectRetry
result.values==['some','option','values']

where:
timeout | conTimeout | retry | expectTimeout | expectConTimeout | expectRetry
1 | 1 | 1 | 1 | 1 | 1
2 | 2 | 2 | 2 | 2 | 2
null | null | null | 10 | 0 | 5
}

def "load remote options get an exception"(){

given:"a job with an url option"
def fwkservice=Mock(FrameworkService)
defineBeans{
frameworkService(InstanceFactoryBean,fwkservice)
}
service.configurationService = Mock(ConfigurationService)
service.frameworkService = fwkservice
def se = new ScheduledExecution(jobName: 'monkey1', project: 'testProject', description: 'blah2')
se.addToOptions(new Option(
name:'test',
realValuesUrl: new URL('file://test')
))
se.save()
_ * service.frameworkService.getRundeckFramework()>>Mock(IFramework){
_ * getFrameworkProjectMgr()>>Mock(ProjectManager){
_ * loadProjectConfig('testProject')
}
}

when:"getRemoteJSON trow an exception"
Exception e = new Exception("some exception")
ScheduledExecutionController.metaClass.static.getRemoteJSON={String url,int vtimeout, int vcontimeout, int vretry, boolean disableRemoteJsonCheck->
throw new Exception(e)
}
def result = service.loadOptionsRemoteValues(se,[option:'test'],'auser')

then:"result should have the information of the exception"
result.err.exception.toString() == "java.lang.Exception: java.lang.Exception: some exception"
result.values == null
result.err.message == "Failed loading remote option values"
}



def "sort url options result"(){
given:

Expand Down

0 comments on commit 95cb59f

Please sign in to comment.