From kalumet-commits-return-18-apmail-incubator-kalumet-commits-archive=incubator.apache.org@incubator.apache.org Wed Oct 26 08:53:00 2011 Return-Path: X-Original-To: apmail-incubator-kalumet-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-kalumet-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 38D417EFA for ; Wed, 26 Oct 2011 08:53:00 +0000 (UTC) Received: (qmail 89742 invoked by uid 500); 26 Oct 2011 08:53:00 -0000 Delivered-To: apmail-incubator-kalumet-commits-archive@incubator.apache.org Received: (qmail 89720 invoked by uid 500); 26 Oct 2011 08:52:59 -0000 Mailing-List: contact kalumet-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: kalumet-dev@incubator.apache.org Delivered-To: mailing list kalumet-commits@incubator.apache.org Received: (qmail 89710 invoked by uid 99); 26 Oct 2011 08:52:57 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 26 Oct 2011 08:52:57 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 26 Oct 2011 08:52:53 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 945E823888EA; Wed, 26 Oct 2011 08:52:33 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1189084 - in /incubator/kalumet/trunk: agent/src/main/java/org/apache/kalumet/agent/ agent/src/main/java/org/apache/kalumet/agent/updater/ agent/src/main/java/org/apache/kalumet/agent/utils/ common/src/main/java/org/apache/kalumet/ utils/s... Date: Wed, 26 Oct 2011 08:52:33 -0000 To: kalumet-commits@incubator.apache.org From: jbonofre@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111026085233.945E823888EA@eris.apache.org> Author: jbonofre Date: Wed Oct 26 08:52:32 2011 New Revision: 1189084 URL: http://svn.apache.org/viewvc?rev=1189084&view=rev Log: Add SQL script utils. Add the software updater. Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/SoftwareUpdater.java incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/utils/EventUtils.java incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptRunnerUtils.java incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptUtils.java Modified: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/Main.java incubator/kalumet/trunk/common/src/main/java/org/apache/kalumet/FileManipulator.java Modified: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/Main.java URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/Main.java?rev=1189084&r1=1189083&r2=1189084&view=diff ============================================================================== --- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/Main.java (original) +++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/Main.java Wed Oct 26 08:52:32 2011 @@ -19,8 +19,8 @@ package org.apache.kalumet.agent; import org.apache.commons.cli.*; -import org.apache.kalumet.agent.utils.AgentUtils; import org.apache.kalumet.model.Kalumet; +import org.apache.kalumet.utils.AgentUtils; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.slf4j.Logger; Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/SoftwareUpdater.java URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/SoftwareUpdater.java?rev=1189084&view=auto ============================================================================== --- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/SoftwareUpdater.java (added) +++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/SoftwareUpdater.java Wed Oct 26 08:52:32 2011 @@ -0,0 +1,1053 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.kalumet.agent.updater; + +import org.apache.commons.vfs.FileObject; +import org.apache.kalumet.FileManipulator; +import org.apache.kalumet.FileManipulatorException; +import org.apache.kalumet.KalumetException; +import org.apache.kalumet.agent.Configuration; +import org.apache.kalumet.agent.utils.EventUtils; +import org.apache.kalumet.model.*; +import org.apache.kalumet.model.update.UpdateLog; +import org.apache.kalumet.model.update.UpdateMessage; +import org.apache.kalumet.utils.*; +import org.apache.kalumet.ws.client.ClientException; +import org.apache.kalumet.ws.client.SoftwareClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; + +/** + * Software software updater. + */ +public class SoftwareUpdater { + + private static final transient Logger LOGGER = LoggerFactory.getLogger(SoftwareUpdater.class); + + /** + * Updates a Software. + * + * @param environment the target environment. + * @param software the target software. + * @param updateLog the UpdateLog to use. + */ + public static void update(Environment environment, Software software, UpdateLog updateLog) throws UpdateException { + LOGGER.info("Updating software {}", software.getName()); + + if (!software.isActive()) { + LOGGER.info("Software {} is inactive, so not updated", software.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " is inactive, so not updated")); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " is inactive, so not updated"); + return; + } + + if (software.getAgent() != null && software.getAgent().trim().length() > 0 && !software.getAgent().equals(Configuration.AGENT_ID)) { + LOGGER.info("Delegating software {} update to agent {}", software.getName(), software.getAgent()); + EventUtils.post(environment, "UPDATE", "Delegating software " + software.getName() + " update to agent " + software.getAgent()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating software " + software.getName() + " update to agent " + software.getAgent())); + Agent delegationAgent = Configuration.CONFIG_CACHE.getAgent(software.getAgent()); + if (delegationAgent == null) { + LOGGER.error("Agent {} is not found in the configuration", software.getAgent()); + throw new UpdateException("Agent " + software.getAgent() + " is not found in the configuration"); + } + try { + LOGGER.debug("Call software WS"); + SoftwareClient client = new SoftwareClient(delegationAgent.getHostname(), delegationAgent.getPort()); + client.update(environment.getName(), software.getName(), true); + } catch (ClientException clientException) { + LOGGER.error("Software {} update failed", software.getName(), clientException); + throw new UpdateException("Software " + software.getName() + " update failed", clientException); + } + return; + } + + // add an update message + updateLog.addUpdateMessage(new UpdateMessage("info", "Updating software " + software.getName())); + // post an event + EventUtils.post(environment, "UPDATE", "Updating software " + software.getName()); + + // iterate in the software update plan + for (Iterator updatePlanIterator = software.getUpdatePlan().iterator(); updatePlanIterator.hasNext(); ) { + Object item = updatePlanIterator.next(); + + // command update + if (item instanceof Command) { + Command command = (Command) item; + try { + SoftwareUpdater.executeCommand(environment, software, command, updateLog); + } catch (Exception e) { + if (command.isBlocker()) { + LOGGER.error("Command {} execution failed", command.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("error", "Command " + command.getName() + " execution failed: " + e.getMessage())); + EventUtils.post(environment, "ERROR", "Command " + command.getName() + " execution failed: " + e.getMessage()); + throw new UpdateException("Command " + command.getName() + " execution failed", e); + } else { + LOGGER.warn("Command {} execution failed", command.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("warn", "Command " + command.getName() + " execution failed: " + e.getMessage())); + updateLog.addUpdateMessage(new UpdateMessage("info", "Command " + command.getName() + " is not an update blocker, update continues")); + EventUtils.post(environment, "WARN", "Command " + command.getName() + " execution failed: " + e.getMessage()); + EventUtils.post(environment, "UPDATE", "Command " + command.getName() + " is not an update blocker, update continues"); + } + } + } + + // location update + if (item instanceof Location) { + Location location = (Location) item; + try { + SoftwareUpdater.updateLocation(environment, software, location, updateLog); + } catch (Exception e) { + if (location.isBlocker()) { + LOGGER.error("Location {} update failed", location.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("error", "Location " + location.getName() + " update failed: " + e.getMessage())); + EventUtils.post(environment, "ERROR", "Location " + location.getName() + " update failed: " + e.getMessage()); + throw new UpdateException("Location " + location.getName() + " update failed", e); + } else { + LOGGER.warn("Location " + location.getName() + " update failed", e); + updateLog.addUpdateMessage(new UpdateMessage("warn", "Location " + location.getName() + " update failed: " + e.getMessage())); + updateLog.addUpdateMessage(new UpdateMessage("info", "Location " + location.getName() + " is not an update blocker, update continues")); + EventUtils.post(environment, "WARN", "Location " + location.getName() + " execution failed: " + e.getMessage()); + EventUtils.post(environment, "UPDATE", "Location " + location.getName() + " is not an update blocker, update continues"); + } + } + } + + // configuration update + if (item instanceof ConfigurationFile) { + ConfigurationFile configurationFile = (ConfigurationFile) item; + try { + SoftwareUpdater.updateConfigurationFile(environment, software, configurationFile, updateLog); + } catch (Exception e) { + if (configurationFile.isBlocker()) { + LOGGER.error("Configuration file {} update failed", configurationFile.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("error", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage())); + EventUtils.post(environment, "ERROR", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage()); + throw new UpdateException("Configuration file " + configurationFile.getName() + " update failed", e); + } else { + LOGGER.warn("Configuration file {} update failed", configurationFile.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("warn", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage())); + updateLog.addUpdateMessage(new UpdateMessage("info", "Configuration file " + configurationFile.getName() + " is not an update blocker, update continues")); + EventUtils.post(environment, "WARN", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage()); + EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " is not an update blocker, update continues"); + } + } + } + + // database update + if (item instanceof Database) { + Database database = (Database) item; + try { + SoftwareUpdater.updateDatabase(environment, software, database, updateLog); + } catch (Exception e) { + if (database.isBlocker()) { + LOGGER.error("Database {} update failed", database.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("error", "Database " + database.getName() + " update failed: " + e.getMessage())); + EventUtils.post(environment, "ERROR", "Database " + database.getName() + " update failed: " + e.getMessage()); + throw new UpdateException("Database " + database.getName() + " update failed", e); + } else { + LOGGER.warn("Database {} update failed", database.getName(), e); + updateLog.addUpdateMessage(new UpdateMessage("warn", "Database " + database.getName() + " update failed: " + e.getMessage())); + updateLog.addUpdateMessage(new UpdateMessage("info", "Database " + database.getName() + " is not an update blocker, update continues")); + EventUtils.post(environment, "WARN", "Database " + database.getName() + " update failed: " + e.getMessage()); + EventUtils.post(environment, "UPDATE", "Database " + database.getName() + " is not an update blocker, update continues"); + } + } + } + } + } + + /** + * Wrapper method to update a software (via WebService). + * + * @param environmentName the target environment name. + * @param softwareName the target software name. + * @param delegation flag indicating if the update is a delegation from another agent (true), or a client call (false). + */ + public static void update(String environmentName, String softwareName, boolean delegation) throws KalumetException { + LOGGER.info("Software {} update requested by WS", softwareName); + + LOGGER.debug("Loading configuration"); + Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION); + + Environment environment = kalumet.getEnvironment(environmentName); + if (environment == null) { + LOGGER.error("Environment {} is not found in the configuration", environmentName); + throw new KalumetException("Environment " + environmentName + " is not found in the configuration"); + } + Software software = environment.getSoftware(softwareName); + if (software == null) { + LOGGER.error("Software {} is not found in environment {}", softwareName, environment.getName()); + throw new KalumetException("Software " + softwareName + " is not found in environment " + environment.getName()); + } + + LOGGER.debug("Creating an update log"); + UpdateLog updateLog = new UpdateLog("Software " + software.getName() + " update in progress ...", environment.getName(), environment); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " update requested by WS"); + + if (!delegation) { + LOGGER.info("Send a notification and waiting for the count down"); + updateLog.addUpdateMessage(new UpdateMessage("info", "Send a notification and waiting for the count down")); + EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down"); + NotifierUtils.waitAndNotify(environment); + } + try { + LOGGER.debug("Call the software updater"); + SoftwareUpdater.update(environment, software, updateLog); + } catch (Exception e) { + LOGGER.error("Software {} update failed", software.getName(), e); + EventUtils.post(environment, "ERROR", "Software " + software.getName() + " update failed: " + e.getMessage()); + if (!delegation) { + updateLog.setStatus("Software " + software.getName() + " update failed"); + updateLog.addUpdateMessage(new UpdateMessage("error", "Software " + software.getName() + " update failed: " + e.getMessage())); + PublisherUtils.publish(environment); + } + throw new KalumetException("Software " + software.getName() + " update failed", e); + } + + LOGGER.info("Software {} updated", software.getName()); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " updated"); + if (!delegation) { + LOGGER.debug("The update is a client call, publish result"); + EventUtils.post(environment, "UPDATE", "Update completed"); + if (updateLog.isUpdated()) { + updateLog.setStatus("Software " + software.getName() + " updated"); + } else { + updateLog.setStatus("Software " + software.getName() + " already up to date"); + } + updateLog.addUpdateMessage(new UpdateMessage("info", "Update completed")); + LOGGER.info("Publishing update report"); + PublisherUtils.publish(environment); + } + } + + /** + * Execute a software command. + * + * @param environment the target environment. + * @param software the target software. + * @param command the target command. + * @param updateLog the UpdateLog to use. + * @throws UpdateException in case of error during the command execution. + */ + public static void executeCommand(Environment environment, Software software, Command command, UpdateLog updateLog) throws UpdateException { + LOGGER.info("Executing software {} command {}", software.getName(), command.getName()); + + if (!command.isActive()) { + LOGGER.info("Software {} command {} is inactive, so not executed", software.getName(), command.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " command " + command.getName() + " is inactive, so not executed")); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " command " + command.getName() + " is inactive, so not executed"); + return; + } + + if (command.getAgent() != null && command.getAgent().trim().length() > 0 && !command.getAgent().equals(Configuration.AGENT_ID)) { + // delegates the command execution to another agent + LOGGER.info("Delegating command {} execution to agent {}", command.getName(), command.getAgent()); + Agent agentDelegation = Configuration.CONFIG_CACHE.getAgent(command.getAgent()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating command " + command.getName() + " execution to agent " + command.getAgent())); + EventUtils.post(environment, "UPDATE", "Delegating command " + command.getName() + " execution to agent " + command); + if (agentDelegation == null) { + LOGGER.error("Agent {} is not found in the configuration", command.getAgent()); + throw new UpdateException("Agent " + command.getAgent() + " is not found in the configuration"); + } + try { + LOGGER.debug("Call software WS"); + SoftwareClient client = new SoftwareClient(agentDelegation.getHostname(), agentDelegation.getPort()); + client.executeCommand(environment.getName(), software.getName(), command.getName(), true); + } catch (ClientException clientException) { + LOGGER.error("Command {} execution failed", command.getName(), clientException); + throw new UpdateException("Command " + command.getName() + " execution failed: " + clientException.getMessage(), clientException); + } + return; + } + + String commandExec = VariableUtils.replace(command.getCommand(), environment.getVariables()); + String output = null; + try { + output = CommandUtils.execute(commandExec); + } catch (KalumetException kalumetException) { + LOGGER.error("Command {} execution failed", command.getName(), kalumetException); + throw new UpdateException("Command " + command.getName() + " execution failed", kalumetException); + } + + LOGGER.info("Software {} command {} executed: {}", new Object[]{ software.getName(), command.getName(), output }); + // add an update message + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " command " + command.getName() + " executed: " + output)); + // post an event + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " command " + command.getName() + " executed: " + output); + } + + /** + * Wrapper method to execute a software command (via WS). + * + * @param environmentName the target environment name. + * @param softwareName the target software name. + * @param commandName the target command name. + * @param delegation flag indicating if the execution is a delegation from another agent (true), or a client call (false). + */ + public static void executeCommand(String environmentName, String softwareName, String commandName, boolean delegation) throws KalumetException { + LOGGER.info("Software {} command {} execution requested by WS", softwareName, commandName); + Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION); + Environment environment = kalumet.getEnvironment(environmentName); + if (environment == null) { + LOGGER.error("Environment {} is not found in the configuration", environmentName); + throw new KalumetException("Environment " + environmentName + " is not found in the configuration"); + } + Software software = environment.getSoftware(softwareName); + if (software == null) { + LOGGER.error("Software {} is not found in environment {}", softwareName, environmentName); + throw new KalumetException("Software " + softwareName + " is not found in environment " + environmentName); + } + Command command = software.getCommand(commandName); + if (command == null) { + LOGGER.error("Command {} is not found in software {}", commandName, softwareName); + throw new KalumetException("Command " + commandName + " is not found in software " + softwareName); + } + // update the agent configuration cache + LOGGER.debug("Updating agent configuration cache"); + Configuration.CONFIG_CACHE = kalumet; + // post a journal event + EventUtils.post(environment, "UPDATE", "Software " + softwareName + " command " + commandName + " execution requested by WS"); + // create an update logger + UpdateLog updateLog = new UpdateLog("Software " + softwareName + " command " + commandName + " execution in progress ...", environment.getName(), environment); + if (!delegation) { + // the call is not a delegation from another agent + LOGGER.info("Send a notification and waiting for the count down"); + EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down"); + NotifierUtils.waitAndNotify(environment); + } + try { + // call the updater + LOGGER.debug("Call the software updater"); + SoftwareUpdater.executeCommand(environment, software, command, updateLog); + } catch (Exception e) { + LOGGER.error("Command {} execution failed", command.getName(), e); + EventUtils.post(environment, "ERROR", "Command " + command.getName() + " execution failed: " + e.getMessage()); + if (!delegation) { + updateLog.setStatus("Command " + command.getName() + " execution failed"); + updateLog.addUpdateMessage(new UpdateMessage("error", "Command " + command.getName() + " execution failed: " + e.getMessage())); + PublisherUtils.publish(environment); + } + throw new UpdateException("Command " + command.getName() + " execution failed", e); + } + + // command execution is completed + LOGGER.info("Command {} has been executed successfully", command.getName()); + EventUtils.post(environment, "UPDATE", "Command " + command.getName() + " has been executed successfully"); + if (!delegation) { + updateLog.setStatus("Command " + command.getName() + " has been executed successfully"); + updateLog.addUpdateMessage(new UpdateMessage("info", "Command " + command.getName() + " has been executed successfully")); + LOGGER.info("Publishing update report"); + PublisherUtils.publish(environment); + } + } + + /** + * Wrapper method to update a location (via WS). + * + * @param environmentName the target environment name. + * @param softwareName the target software name. + * @param locationName the target location name. + * @param delegation true if the call is performed by another agent, false else. + * @throws UpdateException in case of location update failure. + */ + public static void updateLocation(String environmentName, String softwareName, String locationName, boolean delegation) throws KalumetException { + LOGGER.info("Software {} location {} update requested by WS", softwareName, locationName); + + // loading AutoDeploy configuration + LOGGER.debug("Loading configuration"); + Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION); + Environment environment = kalumet.getEnvironment(environmentName); + if (environment == null) { + LOGGER.error("Environment {} is not found in the configuration", environmentName); + throw new KalumetException("Environment " + environmentName + " is not found in the configuration"); + } + Software software = environment.getSoftware(softwareName); + if (software == null) { + LOGGER.error("Software {} is not found in environment {}", softwareName, environmentName); + throw new KalumetException("Software " + softwareName + " is not found in environment " + environmentName); + } + Location location = software.getLocation(locationName); + if (location == null) { + LOGGER.error("Location {} is not found in software {}",locationName, softwareName); + throw new KalumetException("Location " + locationName + " is not found in software " + softwareName); + } + + // update configuration cache + LOGGER.debug("Updating configuration cache"); + Configuration.CONFIG_CACHE = kalumet; + + // post journal event + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " location " + location.getName() + " update requested by WS"); + // create an update logger + UpdateLog updateLog = new UpdateLog("Software " + software.getName() + " location " + location.getName() + " update in progress ....", environment.getName(), environment); + + if (!delegation) { + // the call is not a delegation from another agent, it's an atomic update + LOGGER.info("Send a notification and waiting for the count down"); + EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down"); + NotifierUtils.waitAndNotify(environment); + } + try { + // call software updater + LOGGER.debug("Call software updater"); + SoftwareUpdater.updateLocation(environment, software, location, updateLog); + } catch (Exception e) { + LOGGER.error("Location {} update failed", location.getName(), e); + EventUtils.post(environment, "ERROR", "Location " + location.getName() + " update failed: " + e.getMessage()); + if (!delegation) { + updateLog.setStatus("Location " + locationName + " update failed"); + updateLog.addUpdateMessage(new UpdateMessage("error", "Location " + locationName + " update failed: " + e.getMessage())); + PublisherUtils.publish(environment); + } + throw new UpdateException("Location " + location.getName() + " update failed", e); + } + + // location updated + LOGGER.info("Location {} updated", location.getName()); + EventUtils.post(environment, "UPDATE", "Location " + location.getName() + " updated"); + if (!delegation) { + updateLog.setStatus("Location " + location.getName() + " updated"); + updateLog.addUpdateMessage(new UpdateMessage("info", "Location " + location.getName() + " updated")); + LOGGER.info("Publishing update report"); + PublisherUtils.publish(environment); + } + } + + /** + * Updates an Software Location. + * + * @param environment the target Environment. + * @param software the target Software. + * @param location the target Location. + * @param updateLog the UpdateLog to use. + * @throws UpdateException in case of error during the location update. + */ + public static void updateLocation(Environment environment, Software software, Location location, UpdateLog updateLog) throws UpdateException { + LOGGER.info("Updating software {} location {}", software.getName(), location.getName()); + + if (!location.isActive()) { + LOGGER.info("Software {} location {} is inactive, so not updated", software.getName(), location.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " location " + location.getName() + " is inactive, so not updated")); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " location " + location.getName() + "is inactive, so not updated"); + return; + } + + if (location.getAgent() != null && location.getAgent().trim().length() > 0 && !location.getAgent().equals(Configuration.AGENT_ID)) { + // delegates the location update to another agent + LOGGER.info("Delegating location {} update to agent {}", location.getName(), location.getAgent()); + Agent agentDelegation = Configuration.CONFIG_CACHE.getAgent(location.getAgent()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating location " + location.getName() + " update to agent " + location.getAgent())); + EventUtils.post(environment, "UPDATE", "Delegating location " + location.getName() + " update to agent " + location.getAgent()); + if (agentDelegation == null) { + LOGGER.error("Agent {} is not found in the configuration", location.getAgent()); + throw new UpdateException("Agent " + location.getAgent() + " is not found in the configuration"); + } + try { + // call the WebService + LOGGER.debug("Call software WS"); + SoftwareClient client = new SoftwareClient(agentDelegation.getHostname(), agentDelegation.getPort()); + client.updateLocation(environment.getName(), software.getName(), location.getName(), true); + } catch (ClientException clientException) { + LOGGER.error("Location {} update failed", location.getName(), clientException); + throw new UpdateException("Location " + location.getName() + " update failed: " + clientException.getMessage(), clientException); + } + return; + } + + // constructs the location URI + String locationUri = VariableUtils.replace(location.getUri(), environment.getVariables()); + if (!FileManipulator.protocolExists(locationUri)) { + LOGGER.debug("The location URI is relative to the software URI"); + locationUri = FileManipulator.format(VariableUtils.replace(software.getUri(), environment.getVariables())) + "!/" + locationUri; + } + // constructs the location destination path + String locationPath = VariableUtils.replace(location.getPath(), environment.getVariables()); + // get a file manipulator + FileManipulator fileManipulator = null; + try { + fileManipulator = FileManipulator.getInstance(); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't initialize file manipulator", fileManipulatorException); + throw new UpdateException("Can't initialize file manipulator", fileManipulatorException); + } + try { + LOGGER.debug("Copying {} to {}", locationUri, locationPath); + fileManipulator.copy(locationUri, locationPath); + updateLog.setUpdated(true); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Location {} update failed", location.getName(), fileManipulatorException); + throw new UpdateException("Location " + location.getName() + " update failed", fileManipulatorException); + } + LOGGER.info("Software {} location {} updated", software.getName(), location.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " location " + location.getName() + " updated")); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " location " + location.getName() + " updated"); + } + + /** + * Wrapper method to update a configuration file (via WS). + * + * @param environmentName the target environment name. + * @param softwareName the target software name. + * @param configurationFileName the target configuration file name. + * @param delegation true if the call is made by another agent (delegation), false if the call is made by a client. + * @throws KalumetException in case of update failure. + */ + public static void updateConfigurationFile(String environmentName, String softwareName, String configurationFileName, boolean delegation) throws KalumetException { + LOGGER.info("Software {} configuration file {} update requested by WS", softwareName, configurationFileName); + + // loading configuration + LOGGER.debug("Loading configuration"); + Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION); + + Environment environment = kalumet.getEnvironment(environmentName); + if (environment == null) { + LOGGER.error("Environment {} is not found in the configuration", environmentName); + throw new KalumetException("Environment " + environmentName + " is not found in the configuration"); + } + Software software = environment.getSoftware(softwareName); + if (software == null) { + LOGGER.error("Software {} is not found in environment {}", softwareName, environmentName); + throw new KalumetException("Software " + softwareName + " is not found in environment " + environmentName); + } + ConfigurationFile configurationFile = software.getConfigurationFile(configurationFileName); + if (configurationFile == null) { + LOGGER.error("Configuration file {} is not found in software {}", configurationFileName, softwareName); + throw new KalumetException("Configuration file " + configurationFileName + " is not found in software " + softwareName); + } + + // update agent configuration cache + LOGGER.debug("Updating agent configuration cache"); + Configuration.CONFIG_CACHE = kalumet; + + // post journal event + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " configuration file " + configurationFile.getName() + " update requested by WS"); + // create update log + UpdateLog updateLog = new UpdateLog("Software " + software.getName() + " configuration file " + configurationFile.getName() + " update in progress ...", environment.getName(), environment); + + if (!delegation) { + // the update is not call by another agent, it's an atomic update + LOGGER.info("Send a notification and waiting for the count down"); + EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down"); + NotifierUtils.waitAndNotify(environment); + } + + try { + // call software updater + LOGGER.debug("Call software updater"); + SoftwareUpdater.updateConfigurationFile(environment, software, configurationFile, updateLog); + } catch (Exception e) { + LOGGER.error("Configuration file {} update failed", configurationFile.getName(), e); + EventUtils.post(environment, "ERROR", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage()); + if (!delegation) { + updateLog.setStatus("Configuration file " + configurationFile.getName() + " update failed"); + updateLog.addUpdateMessage(new UpdateMessage("error", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage())); + PublisherUtils.publish(environment); + } + throw new UpdateException("Configuration file " + configurationFile.getName() + " update failed", e); + } + + // configuration file updated + LOGGER.info("Configuration file {} updated", configurationFile.getName()); + EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " updated"); + if (!delegation) { + updateLog.setStatus("Configuration file " + configurationFile.getName() + " updated"); + updateLog.addUpdateMessage(new UpdateMessage("info", "Configuration file " + configurationFile.getName() + " updated")); + LOGGER.info("Publishing update report"); + PublisherUtils.publish(environment); + } + } + + /** + * Update an Software ConfigurationFile. + * + * @param environment the target Environment. + * @param software the target Software. + * @param configurationFile the target ConfigurationFile. + * @param updateLog the UpdateLog to use. + * @throws UpdateException in case of error during the configuration file update. + */ + public static void updateConfigurationFile(Environment environment, Software software, ConfigurationFile configurationFile, UpdateLog updateLog) throws UpdateException { + LOGGER.info("Updating software {} configuration file {}", software.getName(), configurationFile.getName()); + + if (!configurationFile.isActive()) { + LOGGER.info("Software {} configuration file {} is inactive, so not updated", software.getName(), configurationFile.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " configuration file " + configurationFile.getName() + " is inactive, so not updated")); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " configuration file " + configurationFile.getName() + " is inactive, so not updated"); + return; + } + + if (configurationFile.getAgent() != null && configurationFile.getAgent().trim().length() > 0 && !configurationFile.getAgent().equals(Configuration.AGENT_ID)) { + // delegates configuration file update to another agent + LOGGER.info("Delegating configuration file {} update to agent {}", configurationFile.getName(), configurationFile.getAgent()); + Agent agentDelegation = Configuration.CONFIG_CACHE.getAgent(configurationFile.getAgent()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating configuration file " + configurationFile.getName() + " update to agent " + configurationFile.getAgent())); + EventUtils.post(environment, "UPDATE", "Delegating configuration file " + configurationFile.getName() + " update to agent " + configurationFile.getAgent()); + if (agentDelegation == null) { + LOGGER.error("Agent {} is not found in the configuration", configurationFile.getAgent()); + throw new UpdateException("Agent " + configurationFile.getAgent() + " is not found in the configuration"); + } + try { + // call WS + LOGGER.debug("Call software WS"); + SoftwareClient client = new SoftwareClient(agentDelegation.getHostname(), agentDelegation.getPort()); + client.updateConfigurationFile(environment.getName(), software.getName(), configurationFile.getName(), true); + } catch (ClientException clientException) { + LOGGER.error("Configuration file {} update failed", configurationFile.getName(), clientException); + throw new UpdateException("Configuration file " + configurationFile.getName() + " update failed", clientException); + } + return; + } + + // defines the configuration file URI + LOGGER.debug("Getting configuration file URI"); + String configurationFileUri = VariableUtils.replace(configurationFile.getUri(), environment.getVariables()); + if (!FileManipulator.protocolExists(configurationFileUri)) { + LOGGER.debug("The configuration file URI is relative to the software URI"); + configurationFileUri = FileManipulator.format(VariableUtils.replace(software.getUri(), environment.getVariables())) + "!/" + configurationFileUri; + } + + // defines the software cache directory + LOGGER.debug("Getting software cache directory"); + String softwareCacheDir = null; + try { + softwareCacheDir = FileManipulator.createSoftwareCacheDir(environment, software); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't initialize software cache directory", fileManipulatorException); + throw new UpdateException("Can't initialize software cache directory", fileManipulatorException); + } + + // initializes file manipulator + LOGGER.debug("Initializing file manipulator"); + FileManipulator fileManipulator = null; + try { + fileManipulator = FileManipulator.getInstance(); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't initialize file manipulator", fileManipulatorException); + throw new UpdateException("Can't initialize file manipulator", fileManipulatorException); + } + + // copy configuration file into cache + String configurationFileCacheLocation = softwareCacheDir + "/config/" + configurationFile.getName(); + LOGGER.debug("Copying configuration file {} into cache", configurationFile.getName()); + try { + fileManipulator.copy(configurationFileUri, configurationFileCacheLocation); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't copy configuration file {} into cache", configurationFile.getName(), fileManipulatorException); + throw new UpdateException("Can't copy configuration file " + configurationFile.getName() + " into cache", fileManipulatorException); + } + + // change mappings into the configuration file cache + LOGGER.debug("Replacing mappings key/value"); + for (Iterator mappingIterator = configurationFile.getMappings().iterator(); mappingIterator.hasNext(); ) { + Mapping mapping = (Mapping) mappingIterator.next(); + FileManipulator.searchAndReplace(mapping.getKey(), VariableUtils.replace(mapping.getValue(), environment.getVariables()), configurationFileCacheLocation); + } + + // compare configuration file cache with target + LOGGER.debug("Comparing the configuration file cache with the target location"); + String configurationFileDestinationPath = VariableUtils.replace(configurationFile.getPath(), environment.getVariables()); + try { + if (!fileManipulator.contentEquals(configurationFileCacheLocation, configurationFileDestinationPath)) { + // the configuration file needs to be updated + LOGGER.debug("Configuration file {} needs to be updated", configurationFile.getName()); + fileManipulator.copy(configurationFileCacheLocation, configurationFileDestinationPath); + updateLog.setStatus("UPDATE PERFORMED"); + updateLog.setUpdated(true); + updateLog.addUpdateMessage(new UpdateMessage("info", "Configuration file " + configurationFile.getName() + " updated")); + EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " updated"); + LOGGER.info("Configuration file {} updated", configurationFile.getName()); + } + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Configuration file {} update failed", configurationFile.getName(), fileManipulatorException); + throw new UpdateException("Configuration file " + configurationFile.getName() + " update failed: " + fileManipulatorException.getMessage(), fileManipulatorException); + } + } + + /** + * Wrapper method to update a software database (via WS). + * + * @param environmentName the target environment name. + * @param softwareName the target software name. + * @param databaseName the target database name. + * @param delegation true if the call is made by another agent (delegation), false if the call is made by a client. + * @throws KalumetException in case of update failure. + */ + public static void updateDatabase(String environmentName, String softwareName, String databaseName, boolean delegation) throws KalumetException { + LOGGER.info("Software {} database {} update requested by WS", softwareName, databaseName); + + // load configuration + Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION); + Environment environment = kalumet.getEnvironment(environmentName); + if (environment == null) { + LOGGER.error("Environment {} is not found in the configuration", environmentName); + throw new KalumetException("Environment " + environmentName + " is not found in the configuration"); + } + Software software = environment.getSoftware(softwareName); + if (software == null) { + LOGGER.error("Software {} is not found in environment {}", softwareName, environmentName); + throw new KalumetException("Software " + softwareName + " is not found in environment " + environmentName); + } + Database database = software.getDatabase(databaseName); + if (database == null) { + LOGGER.error("Database {} is not found in software {}", databaseName, softwareName); + throw new KalumetException("Database " + databaseName + " is not found in software " + softwareName); + } + + // updating configuration cache + LOGGER.debug("Updating configuration cache"); + Configuration.CONFIG_CACHE = kalumet; + + // post journal event + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " database " + database.getName() + " update requested by WS"); + // create update log + UpdateLog updateLog = new UpdateLog("Software " + software.getName() + " database " + database.getName() + " update in progress ...", environment.getName(), environment); + + if (!delegation) { + // the call is not a delegation from another agent, it's an atomic update + LOGGER.info("Send a notification and waiting for the count down"); + EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down"); + NotifierUtils.waitAndNotify(environment); + } + + try { + // call software updater + LOGGER.debug("Call software updater"); + SoftwareUpdater.updateDatabase(environment, software, database, updateLog); + } catch (Exception e) { + LOGGER.error("Database {} update failed", database.getName(), e); + EventUtils.post(environment, "ERROR", "Database " + database.getName() + " update failed: " + e.getMessage()); + if (!delegation) { + updateLog.setStatus("Database " + database.getName() + " update failed"); + updateLog.addUpdateMessage(new UpdateMessage("error", "Database " + database.getName() + " update failed: " + e.getMessage())); + PublisherUtils.publish(environment); + } + throw new UpdateException("Database " + database.getName() + " update failed", e); + } + + // database updated + LOGGER.info("Database {} updated", database.getName()); + EventUtils.post(environment, "UPDATE", "Database " + database.getName() + " updated"); + if (!delegation) { + updateLog.setStatus("Database " + database.getName() + " updated"); + updateLog.addUpdateMessage(new UpdateMessage("info", "Database " + database.getName() + " updated")); + LOGGER.info("Publishing update report"); + PublisherUtils.publish(environment); + } + } + + /** + * Update a software database. + * + * @param environment the target Environment. + * @param software the target Software. + * @param database the target Database. + * @param updateLog the update logger to use. + */ + public static void updateDatabase(Environment environment, Software software, Database database, UpdateLog updateLog) throws UpdateException { + LOGGER.info("Update software {} database {}", software.getName(), database.getName()); + + if (!database.isActive()) { + LOGGER.info("Software {} database {} (environment {}) is inactive, so not updated", new Object[]{ software.getName(), database.getName(), environment.getName() }); + updateLog.addUpdateMessage(new UpdateMessage("info", "Software " + software.getName() + " database " + database.getName() + " is inactive, so not updated")); + EventUtils.post(environment, "UPDATE", "Software " + software.getName() + " database " + database.getName() + " is inactive, so not updated"); + return; + } + + if (database.getAgent() != null && database.getAgent().trim().length() > 0 && !database.getAgent().equals(Configuration.AGENT_ID)) { + // the database update is delegated to another agent + LOGGER.info("Delegating software {} database {} update to agent {}", new Object[]{ software.getName(), database.getName(), database.getAgent() }); + Agent delegationAgent = Configuration.CONFIG_CACHE.getAgent(database.getAgent()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating database " + database.getName() + " update to agent " + database.getAgent())); + EventUtils.post(environment, "UPDATE", "Delegating database " + database.getName() + " update to agent " + database.getAgent()); + if (delegationAgent == null) { + // the database agent is not found in the configuration + LOGGER.error("Agent {} is not found in the configuration", database.getAgent()); + throw new UpdateException("Agent " + database.getAgent() + " is not found in the configuration"); + } + try { + // call the WebService + LOGGER.debug("Call software WS"); + SoftwareClient client = new SoftwareClient(delegationAgent.getHostname(), delegationAgent.getPort()); + client.updateDatabase(environment.getName(), software.getName(), database.getName(), true); + } catch (ClientException clientException) { + LOGGER.error("Database {} update failed", database.getName(), clientException); + throw new UpdateException("Database " + database.getName() + " update failed", clientException); + } + return; + } + + // launch SQL scripts of the database + LOGGER.debug("Executing SQL scripts"); + for (Iterator sqlScriptIterator = database.getSqlScripts().iterator(); sqlScriptIterator.hasNext(); ) { + SqlScript sqlScript = (SqlScript) sqlScriptIterator.next(); + try { + SoftwareUpdater.executeSqlScript(environment, software, database, sqlScript, updateLog); + } catch (UpdateException updateException) { + // SQL script execution has failed + if (sqlScript.isBlocker()) { + // the SQL script is update blocker + LOGGER.error("SQL script {} execution failed", updateException); + throw new UpdateException("SQL script " + sqlScript.getName() + " execution failed", updateException); + } else { + // the SQL script is not update blocker + LOGGER.warn("SQL script {} execution failed", updateException); + updateLog.addUpdateMessage(new UpdateMessage("warn", "SQL script " + sqlScript.getName() + " execution failed: " + updateException.getMessage())); + updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + sqlScript.getName() + " is not update blocker, update continues")); + EventUtils.post(environment, "WARN", "SQL script " + sqlScript.getName() + " execution failed: " + updateException.getMessage()); + EventUtils.post(environment, "UPDATE", "SQL script " + sqlScript.getName() + " is not update blocker, update continues"); + } + } + } + } + + /** + * Executes SQL script. + * + * @param environment the target Environment. + * @param software the target Software. + * @param database the target Database. + * @param sqlScript the target SqlScript. + * @param updateLog the update log to use. + * @throws UpdateException in case of error during the SQL script execution. + */ + public static void executeSqlScript(Environment environment, Software software, Database database, SqlScript sqlScript, UpdateLog updateLog) throws UpdateException { + LOGGER.info("Executing SQL script {}", sqlScript.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "Executing SQL script " + sqlScript.getName())); + EventUtils.post(environment, "UPDATE", "Executing SQL script " + sqlScript.getName()); + + if (!sqlScript.isActive()) { + // the SQL script is not active + LOGGER.info("SQL script {} is inactive, so not executed", sqlScript.getName()); + updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + sqlScript.getName() + " is inactive, so not executed")); + EventUtils.post(environment, "UPDATE", "SQL script " + sqlScript.getName() + " is inactive, so not executed"); + return; + } + + // construct the SQL script URI + String sqlScriptUri = VariableUtils.replace(sqlScript.getUri(), environment.getVariables()); + if (!FileManipulator.protocolExists(sqlScriptUri)) { + // the SQL script URI is relative, constructs using the software URI + LOGGER.debug("The SQL script URI is relative to the software URI"); + sqlScriptUri = FileManipulator.format(VariableUtils.replace(software.getUri(), environment.getVariables())) + "!/" + sqlScriptUri; + } + + // get the cache directory + LOGGER.debug("Getting software cache directory"); + String softwareCacheDir = null; + try { + softwareCacheDir = FileManipulator.createSoftwareCacheDir(environment, software); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't initialize software cache directory", fileManipulatorException); + throw new UpdateException("Can't initialize software cache directory", fileManipulatorException); + } + + // get file manipulator instance + LOGGER.debug("Initializing file manipulator"); + FileManipulator fileManipulator = null; + try { + fileManipulator = FileManipulator.getInstance(); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't initialize file manipulator", fileManipulatorException); + throw new UpdateException("Can't initialize file manipulator", fileManipulatorException); + } + + // copy the SQL script into the software cache directory + LOGGER.debug("Copying the SQL script into the software cache directory"); + String sqlScriptCache = softwareCacheDir + "/sql/" + sqlScript.getName() + ".cache"; + String sqlScriptRuntime = softwareCacheDir + "/sql/" + sqlScript.getName(); + try { + fileManipulator.copy(sqlScriptUri, sqlScriptCache); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.error("Can't copy SQL script from {} to {}", new Object[]{ sqlScriptUri, sqlScriptCache }, fileManipulatorException); + throw new UpdateException("Can't copy SQL script " + sqlScriptUri + " to " + sqlScriptCache, fileManipulatorException); + } + + if (fileManipulator.isFolder(sqlScriptCache)) { + // TODO add a generic method to reuse in the case of directory + + // the user provided a directory + updateLog.addUpdateMessage(new UpdateMessage("info", sqlScript.getName() + "is a folder, iterate in the SQL scripts")); + EventUtils.post(environment, "UPDATE", sqlScript.getName() + " is a folder, iterate in the SQL scripts"); + LOGGER.info("{} is a folder, iterate in the SQL scripts", sqlScript.getName()); + FileObject[] children = fileManipulator.browse(sqlScriptCache); + for (int i = 0; i < children.length; i++) { + FileObject current = children[i]; + String name = current.getName().getBaseName(); + String singleSqlScriptCache = sqlScriptCache + "/" + name; + String singleSqlScriptRuntime = sqlScriptRuntime + "/" + name; + // change mappings in the current SQL script + for (Iterator mappingIterator = sqlScript.getMappings().iterator(); mappingIterator.hasNext(); ) { + Mapping mapping = (Mapping) mappingIterator.next(); + FileManipulator.searchAndReplace(mapping.getKey(), VariableUtils.replace(mapping.getValue(), environment.getVariables()), singleSqlScriptCache); + } + try { + if (sqlScript.isForce() || (!fileManipulator.contentEquals(singleSqlScriptCache, singleSqlScriptRuntime))) { + fileManipulator.copy(singleSqlScriptCache, singleSqlScriptRuntime); + + if (database.getSqlCommand() != null && database.getSqlCommand().trim().length() > 0) { + // execute SQL script using system command + String command = VariableUtils.replace(database.getSqlCommand(), environment.getVariables()); + String output = SqlScriptUtils.executeUsingCommand(singleSqlScriptRuntime, command); + updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + name + " executed: " + output)); + EventUtils.post(environment, "UPDATE", "SQL script " + name + " executed: " + output); + LOGGER.info("SQL script {} executed: {}", name, output); + } else { + // execute SQL script using JDBC + String user = null; + String password = null; + String driver = null; + String url = null; + if (database.getConnectionPool() != null && database.getConnectionPool().trim().length() > 0) { + // the database is linked to a connection pool + // looking for the connection pool (from the cache) + LOGGER.debug("Database has a reference to a connection pool"); + // looking for the connection pool definition + String connectionPoolName = VariableUtils.replace(database.getConnectionPool(), environment.getVariables()); + JDBCConnectionPool connectionPool = null; + for (Iterator applicationServerIterator = environment.getJ2EEApplicationServers().getJ2EEApplicationServers().iterator(); applicationServerIterator.hasNext(); ) { + J2EEApplicationServer applicationServer = (J2EEApplicationServer) applicationServerIterator.next(); + connectionPool = applicationServer.getJDBCConnectionPool(connectionPoolName); + if (connectionPool != null) { + break; + } + } + if (connectionPool == null) { + LOGGER.error("JDBC connection pool {} is not found in any J2EE application servers", connectionPoolName); + throw new UpdateException("JDBC connection pool " + connectionPoolName + " is not found in any J2EE application servers"); + } + user = VariableUtils.replace(connectionPool.getUser(), environment.getVariables()); + password = VariableUtils.replace(connectionPool.getPassword(), environment.getVariables()); + driver = VariableUtils.replace(connectionPool.getDriver(), environment.getVariables()); + url = VariableUtils.replace(connectionPool.getUrl(), environment.getVariables()); + } else { + // use the database connection data + user = VariableUtils.replace(database.getUser(), environment.getVariables()); + password = VariableUtils.replace(database.getPassword(), environment.getVariables()); + driver = VariableUtils.replace(database.getDriver(), environment.getVariables()); + url = VariableUtils.replace(database.getJdbcurl(), environment.getVariables()); + } + // execute SQL script using JDBC + SqlScriptUtils.executeUsingJdbc(singleSqlScriptRuntime, driver, user, password, url); + } + // add message + updateLog.setStatus("Update performed"); + updateLog.setUpdated(true); + updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + sqlScript.getName() + " executed")); + EventUtils.post(environment, "UPDATE", "SQL script " + sqlScript.getName() + " executed"); + LOGGER.info("SQL script " + sqlScript.getName() + " executed"); + } + } catch (Exception e) { + // SQL script execution failed, delete the SQL script from the cache + try { + fileManipulator.delete(sqlScriptRuntime); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.warn("Can't delete SQL script cache", fileManipulatorException); + } + LOGGER.error("SQL script {} execution failed", sqlScript.getName(), e); + throw new UpdateException("SQL script " + sqlScript.getName() + " execution failed", e); + } + } + } else { + // the user provided a single SQL script + + // change mappings into the SQL script + LOGGER.debug("Replacing mappings into the SQL script {}", sqlScript.getName()); + for (Iterator mappingIterator = sqlScript.getMappings().iterator(); mappingIterator.hasNext(); ) { + Mapping mapping = (Mapping) mappingIterator.next(); + FileManipulator.searchAndReplace(mapping.getKey(), mapping.getValue(), sqlScriptCache); + } + + // compare the SQL script origin with the runtime one + try { + if (!fileManipulator.contentEquals(sqlScriptCache, sqlScriptRuntime)) { + // the SQL script needs to be executed + LOGGER.debug("The SQL script {} needs to be executed", sqlScript.getName()); + // copy the SQL script cache to the runtime + LOGGER.debug("Copy the SQL script cache to the runtime"); + fileManipulator.copy(sqlScriptCache, sqlScriptRuntime); + if (database.getSqlCommand() != null && database.getSqlCommand().trim().length() > 0) { + // execute the SQL script using a command + LOGGER.info("Executing the SQL script using a system command"); + String command = VariableUtils.replace(database.getSqlCommand(), environment.getVariables()); + String output = SqlScriptUtils.executeUsingCommand(sqlScriptRuntime, command); + updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + sqlScript.getName() + " executed: " + output)); + EventUtils.post(environment, "UPDATE", "SQL script " + sqlScript.getName() + " executed: " + output); + LOGGER.info("SQL script " + sqlScript.getName() + " executed: " + output); + } else { + // execute SQL script using JDBC + LOGGER.info("Executing SQL script using JDBC"); + String user = null; + String password = null; + String driver = null; + String url = null; + if (database.getConnectionPool() != null && database.getConnectionPool().trim().length() > 0) { + // the database has a reference to an existing connection pool + LOGGER.debug("Database has a reference to a connection pool"); + // looking for the connection pool definition + String connectionPoolName = VariableUtils.replace(database.getConnectionPool(), environment.getVariables()); + JDBCConnectionPool connectionPool = null; + for (Iterator applicationServerIterator = environment.getJ2EEApplicationServers().getJ2EEApplicationServers().iterator(); applicationServerIterator.hasNext(); ) { + J2EEApplicationServer applicationServer = (J2EEApplicationServer) applicationServerIterator.next(); + connectionPool = applicationServer.getJDBCConnectionPool(connectionPoolName); + if (connectionPool != null) { + break; + } + } + if (connectionPool == null) { + LOGGER.error("JDBC connection pool {} is not found in any J2EE application servers", connectionPoolName); + throw new UpdateException("JDBC connection pool " + connectionPoolName + " is not found in any J2EE application servers"); + } + user = VariableUtils.replace(connectionPool.getUser(), environment.getVariables()); + password = VariableUtils.replace(connectionPool.getPassword(), environment.getVariables()); + driver = VariableUtils.replace(connectionPool.getDriver(), environment.getVariables()); + url = VariableUtils.replace(connectionPool.getUrl(), environment.getVariables()); + } else { + // use the database data + LOGGER.debug("Use database data definition"); + user = VariableUtils.replace(database.getUser(), environment.getVariables()); + password = VariableUtils.replace(database.getPassword(), environment.getVariables()); + driver = VariableUtils.replace(database.getDriver(), environment.getVariables()); + url = VariableUtils.replace(database.getJdbcurl(), environment.getVariables()); + } + // execute SQL script + SqlScriptUtils.executeUsingJdbc(sqlScriptRuntime, driver, user, password, url); + } + // add log messages + updateLog.setStatus("Update performed"); + updateLog.setUpdated(true); + updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + sqlScript.getName() + " executed")); + EventUtils.post(environment, "UPDATE", "SQL script " + sqlScript.getName() + " executed"); + LOGGER.info("SQL script " + sqlScript.getName() + " executed"); + } + } catch (Exception e) { + // SQL script execution failed, delete SQL script from the cache + try { + fileManipulator.delete(sqlScriptRuntime); + } catch (FileManipulatorException fileManipulatorException) { + LOGGER.warn("Can't delete SQL script cache", fileManipulatorException); + } + LOGGER.error("SQL script {} execution failed", sqlScript.getName(), e); + throw new UpdateException("SQL script " + sqlScript.getName() + " execution failed", e); + } + } + } + +} \ No newline at end of file Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/utils/EventUtils.java URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/utils/EventUtils.java?rev=1189084&view=auto ============================================================================== --- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/utils/EventUtils.java (added) +++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/utils/EventUtils.java Wed Oct 26 08:52:32 2011 @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.kalumet.agent.utils; + +import org.apache.kalumet.KalumetException; +import org.apache.kalumet.agent.Configuration; +import org.apache.kalumet.model.Environment; +import org.apache.kalumet.model.Kalumet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Agent utils method to post event. + */ +public class EventUtils { + + private final static transient Logger LOGGER = LoggerFactory.getLogger(EventUtils.class); + + /** + * Wrapper method to post an event. + * + * @param environment the target environment. + * @param author the event author. + * @param severity the event severity. + * @param event the event message. + */ + public static void post(Environment environment, String author, String severity, String event) { + LOGGER.debug("Loading configuration from the cache"); + Kalumet kalumet = Configuration.CONFIG_CACHE; + if (kalumet == null) { + LOGGER.debug("No configuration in cache, updating it"); + try { + kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION); + } catch (KalumetException kalumetException) { + LOGGER.warn("Can't post journal event", kalumetException); + return; + } + Configuration.CONFIG_CACHE = kalumet; + } + org.apache.kalumet.utils.EventUtils.post(environment, author, severity, event, kalumet); + } + + /** + * Wrapper method to post an event. + * + * @param environment the target environment. + * @param severity the event severity. + * @param event the event message. + */ + public static void post(Environment environment, String severity, String event) { + EventUtils.post(environment, Configuration.AGENT_ID, severity, event); + } + +} Modified: incubator/kalumet/trunk/common/src/main/java/org/apache/kalumet/FileManipulator.java URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/common/src/main/java/org/apache/kalumet/FileManipulator.java?rev=1189084&r1=1189083&r2=1189084&view=diff ============================================================================== --- incubator/kalumet/trunk/common/src/main/java/org/apache/kalumet/FileManipulator.java (original) +++ incubator/kalumet/trunk/common/src/main/java/org/apache/kalumet/FileManipulator.java Wed Oct 26 08:52:32 2011 @@ -466,7 +466,7 @@ public class FileManipulator { * @return the environment j2EEApplication cache directory path. * @throws FileManipulatorException in case of creation failure. */ - public static String createEnvironmentApplicationCacheDir(Environment environment, J2EEApplication j2EEApplication) throws FileManipulatorException { + public static String createJ2EEApplicationCacheDir(Environment environment, J2EEApplication j2EEApplication) throws FileManipulatorException { String directory = FileManipulator.createEnvironmentCacheDir(environment); directory = directory + "/applications/" + j2EEApplication.getName(); FileManipulator fileManipulator = FileManipulator.getInstance(); @@ -482,7 +482,7 @@ public class FileManipulator { * @return the environment software cache directory path. * @throws FileManipulatorException in case of creation failure. */ - public static String createEnvironmentSoftwareCacheDir(Environment environment, Software software) throws FileManipulatorException { + public static String createSoftwareCacheDir(Environment environment, Software software) throws FileManipulatorException { String directory = FileManipulator.createEnvironmentCacheDir(environment); directory = directory + "/softwares/" + software.getName(); FileManipulator fileManipulator = FileManipulator.getInstance(); Added: incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptRunnerUtils.java URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptRunnerUtils.java?rev=1189084&view=auto ============================================================================== --- incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptRunnerUtils.java (added) +++ incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptRunnerUtils.java Wed Oct 26 08:52:32 2011 @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.kalumet.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.sql.*; + +public class SqlScriptRunnerUtils { + + private final static transient Logger LOGGER = LoggerFactory.getLogger(SqlScriptRunnerUtils.class); + + private static final String DEFAULT_DELIMITER = ";"; + + private Connection connection; + + private boolean stopOnError = false; + private boolean autoCommit = false; + + private String delimiter = DEFAULT_DELIMITER; + private boolean fullLineDelimiter = false; + + public SqlScriptRunnerUtils(Connection connection) { + this.connection = connection; + } + + public void setStopOnError(boolean stopOnError) { + this.stopOnError = stopOnError; + } + + public void setAutoCommit(boolean autoCommit) { + this.autoCommit = autoCommit; + } + + public void setDelimiter(String delimiter) { + this.delimiter = delimiter; + } + + public void setFullLineDelimiter(boolean fullLineDelimiter) { + this.fullLineDelimiter = fullLineDelimiter; + } + + public void runScript(Reader reader) throws Exception { + runScriptWithConnection(connection, reader); + } + + public void closeConnection() { + try { + connection.close(); + } catch (Exception e) { + // ignore + } + } + + /** + * Execute an SQL script (read in using the Reader parameter) using the connection passed in. + * + * @param conn the connection to use for the script. + * @param reader the source of the script. + * @throws java.sql.SQLException if any SQL errors occur. + * @throws java.io.IOException if there is an error reading from the Reader. + */ + private void runScriptWithConnection(Connection conn, Reader reader) throws Exception { + StringBuffer command = null; + try { + BufferedReader lineReader = new BufferedReader(reader); + String line; + while ((line = lineReader.readLine()) != null) { + if (command == null) { + command = new StringBuffer(); + } + String trimmedLine = line.trim(); + if (trimmedLine.length() < 1) { + // do nothing + } else if (trimmedLine.startsWith("//") || trimmedLine.startsWith("--")) { + LOGGER.info(trimmedLine); + } else if (!fullLineDelimiter && trimmedLine.endsWith(delimiter) + || fullLineDelimiter && trimmedLine.equals(delimiter)) { + command.append(line.substring(0, line.lastIndexOf(delimiter))); + command.append(" "); + Statement statement = conn.createStatement(); + + LOGGER.info(command.toString()); + + if (stopOnError) { + statement.execute(command.toString()); + } else { + try { + statement.execute(command.toString()); + } catch (SQLException e) { + e.fillInStackTrace(); + LOGGER.warn("Error executing SQL {}", command); + } + } + + if (autoCommit && !conn.getAutoCommit()) { + conn.commit(); + } + + command = null; + try { + statement.close(); + } catch (Exception e) { + // ignore to workaround a bug in Jakarta DBCP + } + Thread.yield(); + } else { + command.append(line); + command.append(" "); + } + } + if (!autoCommit && !conn.getAutoCommit()) { + conn.commit(); + } + } catch (Exception e) { + LOGGER.error("Error executing SQL {}", command, e); + throw e; + } finally { + conn.rollback(); + } + } + +} + Added: incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptUtils.java URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptUtils.java?rev=1189084&view=auto ============================================================================== --- incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptUtils.java (added) +++ incubator/kalumet/trunk/utils/src/main/java/org/apache/kalumet/utils/SqlScriptUtils.java Wed Oct 26 08:52:32 2011 @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.kalumet.utils; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; + +import org.apache.commons.lang.StringUtils; +import org.apache.kalumet.KalumetException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * SQL script execution utils. + */ +public class SqlScriptUtils { + + private static final transient Logger LOGGER = LoggerFactory.getLogger(SqlScriptUtils.class); + + /** + * Execute a SQL script using a system command. + * + * @param path the SQL script path. + * @param command the system command to use for SQL script execution. + * @return the SQL script execution output. + * @throws KalumetException in case of error during the SQL script execution. + */ + public static String executeUsingCommand(String path, String command) throws KalumetException { + LOGGER.info("Executing SQL script {} using command {}", path, command); + // replace %s by the SQL script path in the command + LOGGER.debug("Replacing %s by the SQL script path in the command"); + String execCommand = StringUtils.replace(command, "%s", path); + LOGGER.debug("Executing the SQL command"); + String output = null; + try { + output = CommandUtils.execute(execCommand); + } catch (KalumetException kalumetException) { + LOGGER.error("SQL script {} execution failed", path, kalumetException); + throw new KalumetException("SQL script " + path + " execution failed", kalumetException); + } + return output; + } + + /** + * Execute a SQL script using a JDBC connection. + * + * @param path the SQL script path. + * @param driver the JDBC connection driver class name. + * @param user the JDBC connection user name. + * @param password the JDBC connection user password. + * @param url the JDBC connection URL. + * @throws KalumetException in case of error during the SQL script execution. + */ + public static void executeUsingJdbc(String path, String driver, String user, String password, String url) throws KalumetException { + LOGGER.info("Executing SQL script {} using JDBC connection {}", path, url); + Connection connection = null; + try { + // creates JDBC connection. + LOGGER.debug("Creating JDBC connection"); + connection = SqlScriptUtils.getConnection(driver, user, password, url); + // creates the SQL script buffered reader. + LOGGER.debug("Creating the SQL script buffered reader"); + BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(path)))); + // uses the SQL script runner + LOGGER.debug("Call SQL script runner"); + SqlScriptRunnerUtils sqlScriptRunner = new SqlScriptRunnerUtils(connection); + sqlScriptRunner.setAutoCommit(true); + sqlScriptRunner.setStopOnError(true); + sqlScriptRunner.runScript(reader); + } catch (Exception e) { + LOGGER.error("SQL script {} execution failed", path, e); + throw new KalumetException("SQL script " + path + " execution failed", e); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (Exception e) { + LOGGER.warn("Can't close the JDBC connection", e); + } + } + } + } + + /** + * Create a JDBC connection. + * + * @param driver the JDBC driver class name. + * @param user the JDBC user name. + * @param password the JDBC user password. + * @param url the JDBC URL. + * @return the JDBC connection. + */ + private static Connection getConnection(String driver, String user, String password, String url) throws KalumetException { + try { + Class.forName(driver); + return DriverManager.getConnection(url, user, password); + } catch (Exception e) { + LOGGER.error("Can't create JDBC connection", e); + throw new KalumetException("Can't create JDBC connection", e); + } + } + +}