diff --git a/ChangeLog b/ChangeLog index 885e2eeb..d311ccfc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -79,6 +79,8 @@ Changes in HQApi 3.0 Changes in HQApi 2.4 + *) [HHQ-3925] Add agent transferPlugin() AgentAPI and associated CLI command + *) [HHQ-3924] Add agent ping CLI command. *) [HHQ-3786] Allow for listing of alerts from the CLI based on resource diff --git a/hqu/hqapi1/app/AgentController.groovy b/hqu/hqapi1/app/AgentController.groovy index e8d307bd..051328ef 100644 --- a/hqu/hqapi1/app/AgentController.groovy +++ b/hqu/hqapi1/app/AgentController.groovy @@ -1,6 +1,7 @@ import org.hyperic.hq.authz.shared.PermissionException import org.hyperic.hq.hqapi1.ErrorCode +import org.hyperic.hq.appdef.server.session.AgentManagerEJBImpl as AgentMan class AgentController extends ApiController { @@ -93,4 +94,47 @@ class AgentController extends ApiController { } } } + + def transferPlugin(params) { + def id = params.getOne('id')?.toInteger() + def plugin = params.getOne('plugin') + + def failureXml + if (!id) { + failureXml = getFailureXML(ErrorCode.INVALID_PARAMETERS, "Agent id not given") + } else if (!plugin) { + failureXml = getFailureXML(ErrorCode.INVALID_PARAMETERS, "No plugin given") + } else { + try { + def agent = getAgent(id, null, null) + if (!agent) { + failureXml = getFailureXML(ErrorCode.OBJECT_NOT_FOUND, + "Agent with id=" + id + " not found") + } else { + // TODO: No api that simply takes an agent + def platform = agent.platforms[0] + // TODO: EJB reference.. + AgentMan.one.transferAgentPluginAsync(user, platform.entityId, plugin) + } + } catch (FileNotFoundException e) { + failureXml = getFailureXML(ErrorCode.INVALID_PARAMETERS, + "Plugin " + plugin + " not found") + } catch (PermissionException e) { + failureXml = getFailureXML(ErrorCode.PERMISSION_DENIED) + } catch (Exception e) { + log.error("UnexpectedError: " + e.getMessage(), e); + failureXml = getFailureXML(ErrorCode.UNEXPECTED_ERROR) + } + } + + renderXml() { + out << StatusResponse() { + if (failureXml) { + out << failureXml + } else { + out << getSuccessXML() + } + } + } + } } \ No newline at end of file diff --git a/src/org/hyperic/hq/hqapi1/AgentApi.java b/src/org/hyperic/hq/hqapi1/AgentApi.java index b351c661..e364a20c 100644 --- a/src/org/hyperic/hq/hqapi1/AgentApi.java +++ b/src/org/hyperic/hq/hqapi1/AgentApi.java @@ -35,6 +35,7 @@ import org.hyperic.hq.hqapi1.types.AgentResponse; import org.hyperic.hq.hqapi1.types.AgentsResponse; import org.hyperic.hq.hqapi1.types.PingAgentResponse; +import org.hyperic.hq.hqapi1.types.StatusResponse; /** * The Hyperic HQ Agent API. @@ -130,4 +131,26 @@ public PingAgentResponse pingAgent(Agent agent) return doGet("agent/ping.hqu", params, new XmlResponseHandler(PingAgentResponse.class)); } + + /** + * Transfer a plugin to the given {@link Agent}. This operation is asynchronous + * and will result in an agent restart. + * + * @param agent The agent to ping. + * @param plugin The full plugin name including the -plugin.jar or -plugin.xml suffix. + * + * @return {@link org.hyperic.hq.hqapi1.types.ResponseStatus#SUCCESS} indicates + * the request was successful. + * + * @throws java.io.IOException If a network error occurs while making the request. + */ + public StatusResponse transferPlugin(Agent agent, String plugin) + throws IOException + { + Map params = new HashMap(); + params.put("id", new String[] { String.valueOf(agent.getId()) }); + params.put("plugin", new String[] { plugin }); + return doGet("agent/transferPlugin.hqu", params, + new XmlResponseHandler(StatusResponse.class)); + } } diff --git a/src/org/hyperic/hq/hqapi1/tools/AgentCommand.java b/src/org/hyperic/hq/hqapi1/tools/AgentCommand.java index 676db264..83977360 100644 --- a/src/org/hyperic/hq/hqapi1/tools/AgentCommand.java +++ b/src/org/hyperic/hq/hqapi1/tools/AgentCommand.java @@ -39,6 +39,8 @@ import org.springframework.stereotype.Component; import org.hyperic.hq.hqapi1.types.PingAgentResponse; import org.hyperic.hq.hqapi1.types.ResourceResponse; +import org.hyperic.hq.hqapi1.types.StatusResponse; + import java.io.InputStream; import java.util.Arrays; import java.util.List; @@ -46,15 +48,17 @@ @Component public class AgentCommand extends AbstractCommand { - private static final String CMD_LIST = "list"; - private static final String CMD_PING = "ping"; + private static final String CMD_LIST = "list"; + private static final String CMD_PING = "ping"; + private static final String CMD_TRANSFER_PLUGIN = "transferPlugin"; private static final String OPT_ID = "id"; private static final String OPT_ADDRESS = "agentAddress"; private static final String OPT_PORT = "agentPort"; private static final String OPT_FQDN = "fqdn"; + private static final String OPT_PLUGIN = "plugin"; - private static String[] COMMANDS = { CMD_LIST, CMD_PING }; + private static String[] COMMANDS = { CMD_LIST, CMD_PING, CMD_TRANSFER_PLUGIN }; private void printUsage() { System.err.println("One of " + Arrays.toString(COMMANDS) + " required"); @@ -75,6 +79,8 @@ public int handleCommand(String[] args) throws Exception { list(trim(args)); } else if (args[0].equals(CMD_PING)) { ping(trim(args)); + } else if (args[0].equals(CMD_TRANSFER_PLUGIN)) { + transferPlugin(trim(args)); } else { printUsage(); return 1; @@ -162,4 +168,75 @@ private void ping(String[] args) throws Exception { } } } + + private void printTransferResponse(Agent a, String plugin) { + System.out.println("Successfully transferred plugin " + plugin + " to " + + a.getAddress() + ":" + a.getPort()); + } + + private void transferPlugin(String[] args) throws Exception { + + OptionParser p = getOptionParser(); + + p.accepts(OPT_ID, "The id of the agent"). + withRequiredArg().ofType(Integer.class); + p.accepts(OPT_ADDRESS, "The address of the agent. Must be used with --" + OPT_PORT). + withRequiredArg().ofType(String.class); + p.accepts(OPT_PORT, "The port of the agent. Must be used with --" + OPT_ADDRESS). + withRequiredArg().ofType(Integer.class); + p.accepts(OPT_FQDN, "The platform FQDN of the agent"). + withRequiredArg().ofType(String.class); + p.accepts(OPT_PLUGIN, "The plugin to transfer"). + withRequiredArg().ofType(String.class); + + OptionSet options = getOptions(p, args); + + HQApi api = getApi(options); + + AgentApi agentApi = api.getAgentApi(); + + if (!options.has(OPT_PLUGIN)) { + System.err.println("Error, required argument --" + OPT_PLUGIN + " not given."); + System.exit(-1); + } + + String plugin = (String)options.valueOf(OPT_PLUGIN); + + if (options.has(OPT_ID)) { + Integer id = (Integer)options.valueOf(OPT_ID); + AgentResponse response = agentApi.getAgent(id); + checkSuccess(response); + StatusResponse transferResponse = agentApi.transferPlugin(response.getAgent(), plugin); + checkSuccess(transferResponse); + printTransferResponse(response.getAgent(), plugin); + } else if (options.has(OPT_ADDRESS) && options.has(OPT_PORT)) { + String address = (String)options.valueOf(OPT_ADDRESS); + Integer port = (Integer)options.valueOf(OPT_PORT); + AgentResponse response = agentApi.getAgent(address, port); + checkSuccess(response); + StatusResponse transferResponse = agentApi.transferPlugin(response.getAgent(), plugin); + checkSuccess(transferResponse); + printTransferResponse(response.getAgent(), plugin); + } else if (options.has(OPT_FQDN)) { + ResourceApi rApi = api.getResourceApi(); + String fqdn = (String)options.valueOf(OPT_FQDN); + ResourceResponse resourceResponse = rApi.getPlatformResource(fqdn, false, false); + checkSuccess(resourceResponse); + Agent a = resourceResponse.getResource().getAgent(); + StatusResponse transferResponse = agentApi.transferPlugin(a, plugin); + checkSuccess(transferResponse); + printTransferResponse(a, plugin); + } else { + // Ping via XML + InputStream is = getInputStream(options); + + AgentsResponse resp = XmlUtil.deserialize(AgentsResponse.class, is); + List agents = resp.getAgent(); + for (Agent a : agents) { + StatusResponse transferResponse = agentApi.transferPlugin(a, plugin); + checkSuccess(transferResponse); + printTransferResponse(a, plugin); + } + } + } }