From 213862de49da91838c36836626f67986d1515ae3 Mon Sep 17 00:00:00 2001 From: Yan Pujante Date: Fri, 26 Oct 2012 14:34:12 -1000 Subject: [PATCH] #166: basic flow working --- .../grails-app/conf/UrlMappings.groovy | 9 ++++-- .../controllers/AgentsController.groovy | 24 ++++++++------ .../controllers/CommandsController.groovy | 28 +++++++++++++++- .../grails-app/views/agents/commands.gsp | 14 ++------ .../grails-app/views/commands/_command.gsp | 19 +++++++++++ .../grails-app/views/commands/_command_js.gsp | 32 +++++++++++++++++++ .../web-app/js/console_jquery.js | 8 +++++ .../engine/commands/CommandsService.groovy | 5 +++ .../commands/CommandsServiceImpl.groovy | 10 ++++++ 9 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command.gsp create mode 100644 console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command_js.gsp diff --git a/console/org.linkedin.glu.console-webapp/grails-app/conf/UrlMappings.groovy b/console/org.linkedin.glu.console-webapp/grails-app/conf/UrlMappings.groovy index b885863a..9bbbe1f4 100644 --- a/console/org.linkedin.glu.console-webapp/grails-app/conf/UrlMappings.groovy +++ b/console/org.linkedin.glu.console-webapp/grails-app/conf/UrlMappings.groovy @@ -240,15 +240,20 @@ class UrlMappings // commands "/commands/$id/stream"(controller: 'commands', action: 'stream') { - __nvbe = 'Commands' + __nvbe = 'Agents' __role = UrlMappings.role('/commands/$id/stream') } "/commands/renderHistory"(controller: 'commands', action: 'renderHistory') { - __nvbe = 'Commands' + __nvbe = 'Agents' __role = UrlMappings.role('/commands/renderHistory') } + "/commands/renderCommand/$id"(controller: 'commands', action: 'renderCommand') { + __nvbe = 'Agents' + __role = UrlMappings.role('/commands/renderCommand') + } + // plan "/plan/execute/$id"(controller: 'plan', action: 'execute') { __nvbe = 'Plans' diff --git a/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/AgentsController.groovy b/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/AgentsController.groovy index 90043df6..726f76b7 100644 --- a/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/AgentsController.groovy +++ b/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/AgentsController.groovy @@ -424,23 +424,27 @@ class AgentsController extends ControllerBase * Commands view page */ def commands = { - def pageCommands = CommandExecution.findAllByFabricAndAgent(request.fabric.name, - params.id, - [sort: 'startTime', order: 'desc']) - def command = null + boolean isCommandRunning = false if(params.commandId) { - command = pageCommands.find { it.commandId == params.commandId} - + command = commandsService.findCurrentCommandExecutions([params.commandId])[params.commandId] + if(!command) - command = CommandExecution.findByFabricAndAgentAndCommandId(request.fabric.name, - params.id, - params.commandId) + { + command = CommandExecution.findByCommandId(params.commandId) + +// command = CommandExecution.findAllByFabricAndAgentAndCommandId(request.fabric.name, +// params.id, +// params.commandId) + isCommandRunning = false + } + else + isCommandRunning = true } - [commands: pageCommands, command: command] + [command: command, isCommandRunning: isCommandRunning] } /** diff --git a/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/CommandsController.groovy b/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/CommandsController.groovy index 4a081adf..94ec11e5 100644 --- a/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/CommandsController.groovy +++ b/console/org.linkedin.glu.console-webapp/grails-app/controllers/org/linkedin/glu/console/controllers/CommandsController.groovy @@ -62,13 +62,39 @@ public class CommandsController extends ControllerBase * Render history according to criteria */ def renderHistory = { - println "renderHistory: ${params}" def commands = CommandExecution.findAllByFabricAndAgent(request.fabric.name, params.agentId, [sort: 'startTime', order: 'desc']) render(template: 'history', model: [commands: commands]) } + /** + * Renders a single command + */ + def renderCommand = { + def command = null + boolean isCommandRunning = false + + if(params.id) + { + command = commandsService.findCurrentCommandExecutions([params.id])[params.id] + + if(!command) + { + command = CommandExecution.findByCommandId(params.id) + + isCommandRunning = false + } + else + isCommandRunning = true + } + + if(command) + render(template: 'command', model: [command: command, isCommandRunning: isCommandRunning]) + else + render "not found" + } + /** * Writes the stream requested * diff --git a/console/org.linkedin.glu.console-webapp/grails-app/views/agents/commands.gsp b/console/org.linkedin.glu.console-webapp/grails-app/views/agents/commands.gsp index 5bcdb84b..d8122b00 100644 --- a/console/org.linkedin.glu.console-webapp/grails-app/views/agents/commands.gsp +++ b/console/org.linkedin.glu.console-webapp/grails-app/views/agents/commands.gsp @@ -52,16 +52,8 @@ } + -function renderCommandStream(commandId, streamType, success) -{ -%{--YP Implementation note: this is obviously hacky, but there does not seem to be a way to use g.remoteFunction + javascript variables in all places! - - ${g.remoteFunction(controller: 'commands', id: , action: 'stream', params: [streamType: ], update:[success: ''])} - ---}% - jQuery.ajax({type:'GET',data:{'streamType': streamType}, url:'/console/commands/' + commandId + '/stream',success:function(data,textStatus){jQuery('#' + success).html(data);},error:function(XMLHttpRequest,textStatus,errorThrown){}}); -} function shouldRefresh() { return document.getElementById('autoRefresh').checked; @@ -120,8 +112,8 @@ function showHide() - -
×
${command.username.encodeAsHTML()}@${command.agent.encodeAsHTML()}# ${command.command.encodeAsHTML()} 2>&1 [] [${'$'}?=${command.exitValue?.encodeAsHTML()}]
${command.username.encodeAsHTML()}@${command.agent.encodeAsHTML()}# []
+ +

History: Auto Refresh: diff --git a/console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command.gsp b/console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command.gsp new file mode 100644 index 00000000..60f89e40 --- /dev/null +++ b/console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command.gsp @@ -0,0 +1,19 @@ +%{-- + - Copyright (c) 2012 Yan Pujante + - + - Licensed under the Apache License, Version 2.0 (the "License"); you may not + - use this file except in compliance with the License. You may obtain a copy of + - the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, software + - distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + - License for the specific language governing permissions and limitations under + - the License. + --}% + + +
×
${command.username.encodeAsHTML()}@${command.agent.encodeAsHTML()}# ${command.command.encodeAsHTML()} 2>&1 [] [${'$'}?=${command.exitValue?.encodeAsHTML()}]
${command.username.encodeAsHTML()}@${command.agent.encodeAsHTML()}# []
Spinner
setTimeout("renderCommand('${command.commandId}', 'shell-${command.commandId}')", '${params.refreshRate ?: 2000}')
+
diff --git a/console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command_js.gsp b/console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command_js.gsp new file mode 100644 index 00000000..6457445b --- /dev/null +++ b/console/org.linkedin.glu.console-webapp/grails-app/views/commands/_command_js.gsp @@ -0,0 +1,32 @@ +%{-- + - Copyright (c) 2012 Yan Pujante + - + - Licensed under the Apache License, Version 2.0 (the "License"); you may not + - use this file except in compliance with the License. You may obtain a copy of + - the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, software + - distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + - License for the specific language governing permissions and limitations under + - the License. + --}% + +function renderCommandStream(commandId, streamType, success) +{ +%{--YP Implementation note: this is obviously hacky, but there does not seem to be a way to use g.remoteFunction + javascript variables in all places! + + ${g.remoteFunction(controller: 'commands', id: , action: 'stream', params: [streamType: ], update:[success: ''])} + +--}% + jQuery.ajax({type:'GET',data:{'streamType': streamType}, url:'/console/commands/' + commandId + '/stream',success:function(data,textStatus){jQuery('#' + success).html(data);},error:function(XMLHttpRequest,textStatus,errorThrown){}}); +} +function renderCommand(commandId, success) { + if(!isHidden('#' + success)) + { + jQuery.ajax({type:'GET',url:'/console/commands/renderCommand/' + commandId,success:function(data,textStatus){jQuery('#' + success).parent().html(data);},error:function(XMLHttpRequest,textStatus,errorThrown){}}); + } +} + \ No newline at end of file diff --git a/console/org.linkedin.glu.console-webapp/web-app/js/console_jquery.js b/console/org.linkedin.glu.console-webapp/web-app/js/console_jquery.js index d3488942..c2900563 100644 --- a/console/org.linkedin.glu.console-webapp/web-app/js/console_jquery.js +++ b/console/org.linkedin.glu.console-webapp/web-app/js/console_jquery.js @@ -62,3 +62,11 @@ function show(selector) { toggleClass(selector, false, 'hidden'); } + +/** + * Returns a boolean if the object is visible + */ +function isHidden(selector) +{ + return $(selector).hasClass('hidden') +} diff --git a/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsService.groovy b/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsService.groovy index df10e202..5a21cbe5 100644 --- a/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsService.groovy +++ b/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsService.groovy @@ -57,4 +57,9 @@ public interface CommandsService */ void writeStream(Fabric fabric, String commandId, StreamType streamType, Closure closure) throws NoSuchCommandExecutionException + + /** + * @return a map with all currently running commands + */ + Map findCurrentCommandExecutions(Collection commandIds) } diff --git a/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsServiceImpl.groovy b/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsServiceImpl.groovy index 69ba5071..49f027d4 100644 --- a/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsServiceImpl.groovy +++ b/orchestration/org.linkedin.glu.orchestration-engine/src/main/groovy/org/linkedin/glu/orchestration/engine/commands/CommandsServiceImpl.groovy @@ -40,6 +40,7 @@ import org.linkedin.glu.agent.rest.common.AgentRestUtils import org.linkedin.groovy.util.config.Config import java.util.concurrent.TimeoutException import org.linkedin.glu.groovy.utils.concurrent.GluGroovyConcurrentUtils +import org.linkedin.glu.groovy.utils.collections.GluGroovyCollectionUtils /** * @author yan@pongasoft.com */ @@ -85,6 +86,15 @@ public class CommandsServiceImpl implements CommandsService * The commands that are currently executing */ private final Map _currentCommandExecutions = [:] + @Override + Map findCurrentCommandExecutions(Collection commandIds) + { + synchronized(_currentCommandExecutions) + { + GluGroovyCollectionUtils.subMap(_currentCommandExecutions, commandIds) + } + } + @Override String executeShellCommand(Fabric fabric, String agentName, args) {