Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #102 from rhq-project/bug/1124614
Browse files Browse the repository at this point in the history
BZ 1124614 - auto-update agent if its version doesn't match the latest agent version
  • Loading branch information
jshaughn committed Jul 31, 2014
2 parents 120bf6e + d3d57a4 commit 8576ff2
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 26 deletions.
34 changes: 34 additions & 0 deletions modules/core/client-api/intentional-api-changes-since-4.12.0.xml
@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<!--
~ RHQ Management Platform
~ Copyright (C) 2005-2014 Red Hat, Inc.
~ All rights reserved.
~
~ This program is free software; you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation version 2 of the License.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program; if not, write to the Free Software Foundation, Inc.,
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-->

<differences>
<difference>
<className>org/rhq/core/clientapi/server/core/ConnectAgentRequest</className>
<differenceType>7004</differenceType> <!-- number of args changed -->
<method>ConnectAgentRequest(*)</method>
<justification>Only agents use this method and this is needed to fix BZ 1124614</justification>
</difference>
<difference>
<className>org/rhq/core/clientapi/server/core/ConnectAgentResults</className>
<differenceType>7004</differenceType> <!-- number of args changed -->
<method>ConnectAgentResults(*)</method>
<justification>Only agents use this method and this is needed to fix BZ 1124614</justification>
</difference>
</differences>
Expand Up @@ -30,22 +30,24 @@
* @author John Mazzitelli
*/
public class ConnectAgentRequest implements Serializable {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

private final String agentName;
private final AgentVersion agentVersion;
private final boolean autoUpdateEnabled;

public ConnectAgentRequest(String agentName, AgentVersion agentVersion) {
public ConnectAgentRequest(String agentName, AgentVersion agentVersion, boolean autoUpdateEnabled) {
this.agentName = agentName;
this.agentVersion = agentVersion;
this.autoUpdateEnabled = autoUpdateEnabled;
}

/**
* The name of the agent that is requesting to be connected.
* This is not necessarily the agent's hostname or IP address, it is
* the string assigned to the agent that makes it unique among all other
* agents in the system.
*
*
* @return agent name
*/
public String getAgentName() {
Expand All @@ -54,20 +56,34 @@ public String getAgentName() {

/**
* The version information of the agent asking to be connected.
*
*
* @return agent version
*/
public AgentVersion getAgentVersion() {
return agentVersion;
}

/**
* Returns true if the connecting agent will attempt to auto-update itself if its
* {@link #getAgentVersion() version} is not supported. False will be returned
* if this agent will be "dead in the water" if it is not supported because it will
* not attempt to update itself to a newer version of the agent that is supported.
*
* @return auto update flag as set on the agent
*/
public boolean isAutoUpdateEnabled() {
return autoUpdateEnabled;
}

@Override
public String toString() {
StringBuilder str = new StringBuilder("ConnectAgentRequest: ");
str.append("agent-name=[");
str.append(this.agentName);
str.append("; version-info=[");
str.append(this.agentVersion);
str.append("; auto-update-enabled=[");
str.append(this.autoUpdateEnabled);
str.append("]");
return str.toString();
}
Expand Down
Expand Up @@ -30,14 +30,16 @@
* @author John Mazzitelli
*/
public class ConnectAgentResults implements Serializable {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

private final long serverTime;
private final boolean isDown;
private final AgentVersion latestAgentVersion;

public ConnectAgentResults(long serverTime, boolean isDown) {
public ConnectAgentResults(long serverTime, boolean isDown, AgentVersion latestAgentVersion) {
this.serverTime = serverTime;
this.isDown = isDown;
this.latestAgentVersion = latestAgentVersion;
}

/**
Expand Down Expand Up @@ -66,8 +68,22 @@ public boolean isDown() {
return isDown;
}

/**
* Returns the latest agent version as known by the server returning this results object.
* This agent version is that version of the agent update distribution that is served up by
* this server. This should represent the most up-to-date agent version available.
*
* This can be null if the latest agent version cannot be determined.
*
* @return the most up-to-date agent version known
*/
public AgentVersion getLatestAgentVersion() {
return latestAgentVersion;
}

@Override
public String toString() {
return "ConnectAgentResults: [server-time=" + this.serverTime + ", is-down=" + this.isDown + "]";
return "ConnectAgentResults: [server-time=" + this.serverTime + ", is-down=" + this.isDown
+ ", latestAgentVersion=" + this.latestAgentVersion + "]";
}
}
Expand Up @@ -1482,9 +1482,7 @@ public void run() {
String address = server_config.getConnectorBindAddress();
int port = server_config.getConnectorBindPort();
String remote_endpoint = server_config.getConnectorRemoteEndpoint();
String version = Version.getProductVersion();
String build = Version.getBuildNumber();
AgentVersion agentVersion = new AgentVersion(version, build);
AgentVersion agentVersion = getAgentVersion();
String installId = System.getProperty(AgentRegistrationRequest.SYSPROP_INSTALL_ID);
String installLocation = getAgentHomeDirectory();
if (installLocation != null && installLocation.trim().length() == 0) {
Expand Down Expand Up @@ -2253,6 +2251,23 @@ void sendConnectRequestToServer(RemoteCommunicator comm, boolean attemptFailover

try {
ConnectAgentResults results = (ConnectAgentResults) connectResponse.getResults();

// BZ 1124614 - if the agent is configured to auto-update itself, and it is not of the same version
// as the latest agent version as told to us by the server, then this agent should update now.
// Notice we will only check version string - we ignore build number to determine version equality
boolean agentUpdateEnabled = getConfiguration().isAgentUpdateEnabled();
if (agentUpdateEnabled) {
AgentVersion latestVersion = results.getLatestAgentVersion();
if (latestVersion != null && latestVersion.getVersion() != null) {
AgentVersion ourVersion = getAgentVersion();
if (!ourVersion.getVersion().equals(latestVersion.getVersion())) {
throw new AgentNotSupportedException(MSG.getMsg(
AgentI18NResourceKeys.AGENT_VERSION_DOES_NOT_MATCH_AUTO_UPDATE_NOW, ourVersion,
latestVersion));
}
}
}

long serverTime = results.getServerTime();
serverClockNotification(serverTime);

Expand All @@ -2267,6 +2282,8 @@ void sendConnectRequestToServer(RemoteCommunicator comm, boolean attemptFailover
plugin_container.getInventoryManager().requestFullAvailabilityReport();
}
}
} catch (AgentNotSupportedException anse) {
throw anse; // bubble this up to the outer try-catch so we can update this agent now
} catch (Throwable t) {
// should never happen, should always cast to non-null ConnectAgentResults
LOG.error(AgentI18NResourceKeys.TIME_UNKNOWN, ThrowableUtil.getAllMessages(t));
Expand All @@ -2291,11 +2308,24 @@ void sendConnectRequestToServer(RemoteCommunicator comm, boolean attemptFailover
return;
}

/**
* Returns this agent's version information.
*
* @return agent version POJO
*/
private AgentVersion getAgentVersion() {
String version = Version.getProductVersion();
String build = Version.getBuildNumber();
AgentVersion agentVersion = new AgentVersion(version, build);
return agentVersion;
}

private Command createConnectAgentCommand() throws Exception {
AgentConfiguration config = getConfiguration();
String agentName = config.getAgentName();
AgentVersion version = new AgentVersion(Version.getProductVersion(), Version.getBuildNumber());
ConnectAgentRequest request = new ConnectAgentRequest(agentName, version);
boolean agentUpdateEnabled = config.isAgentUpdateEnabled();
AgentVersion version = getAgentVersion();
ConnectAgentRequest request = new ConnectAgentRequest(agentName, version, agentUpdateEnabled);

RemotePojoInvocationCommand connectCommand = new RemotePojoInvocationCommand();
Method connectMethod = CoreServerService.class.getMethod("connectAgent", ConnectAgentRequest.class);
Expand Down
Expand Up @@ -185,9 +185,12 @@ public interface AgentI18NResourceKeys {
@I18NMessage("Not sending another connect message since one was recently sent: [{0}]")
String NOT_SENDING_DUP_CONNECT = "AgentMain.not-sending-dup-connect";

@I18NMessage("This version of the agent is not supported by the server - an agent update must be applied")
@I18NMessage("This version of the agent is not supported - an agent update will be applied. Cause: {0}")
String AGENT_NOT_SUPPORTED = "AgentMain.agent-not-supported";

@I18NMessage("This agent has auto-update enabled and its version of [{0}] does not match the latest version [{1}] - this agent will be considered unsupported and an agent update will now be applied")
String AGENT_VERSION_DOES_NOT_MATCH_AUTO_UPDATE_NOW = "AgentMain.agent-version-no-match-update-now";

@I18NMessage("The agent is not talking to its primary server [{0}:{1,number,#}] - it is talking to [{2}:{3,number,#}]")
String NOT_TALKING_TO_PRIMARY_SERVER = "PrimaryServerSwitchoverThread.not-talking-to-primary";

Expand Down
Expand Up @@ -643,12 +643,13 @@ public Integer getAgentIdByScheduleId(int scheduleId) {
}

@ExcludeDefaultInterceptors
public boolean isAgentVersionSupported(AgentVersion agentVersionInfo) {
public AgentVersionCheckResults isAgentVersionSupported(AgentVersion agentVersionInfo) {
try {
Properties properties = getAgentUpdateVersionFileContent();

String supportedAgentVersions = properties.getProperty(RHQ_AGENT_SUPPORTED_VERSIONS); // this is optional
String latestAgentVersion = properties.getProperty(RHQ_AGENT_LATEST_VERSION);
String latestAgentBuild = properties.getProperty(RHQ_AGENT_LATEST_BUILD_NUMBER);
if (latestAgentVersion == null) {
throw new NullPointerException("no agent version in file");
}
Expand All @@ -665,10 +666,10 @@ public boolean isAgentVersionSupported(AgentVersion agentVersionInfo) {
isSupported = agentVersionInfo.getVersion().matches(supportedAgentVersions);
}

return isSupported;
return new AgentVersionCheckResults(isSupported, new AgentVersion(latestAgentVersion, latestAgentBuild));
} catch (Exception e) {
LOG.warn("Cannot determine if agent version [" + agentVersionInfo + "] is supported. Cause: " + e);
return false; // assume we can't talk to it
return new AgentVersionCheckResults(false, null); // assume we can't talk to it
}
}

Expand Down
Expand Up @@ -25,6 +25,7 @@
import javax.ejb.Local;

import org.jetbrains.annotations.NotNull;

import org.rhq.core.clientapi.server.core.AgentVersion;
import org.rhq.core.clientapi.server.core.CoreServerService;
import org.rhq.core.clientapi.server.core.PingRequest;
Expand Down Expand Up @@ -270,11 +271,12 @@ public interface AgentManagerLocal extends AgentManagerRemote {
*
* @param agentVersion the version of the agent to verify
*
* @return <code>true</code> if this server can support an agent with the given version; if the server
* @return POJO whose isSupported is <code>true</code> if this server can support an agent with the given version; if the server
* knows it cannot communicate successfully with an agent of that version, <code>false</code>
* will be returned
* will be in the POJO's isSupported attribute. The POJO also contains agent version information on the latest
* known agent available.
*/
boolean isAgentVersionSupported(AgentVersion agentVersion);
AgentVersionCheckResults isAgentVersionSupported(AgentVersion agentVersion);

/**
* Returns the path on the server's file system where the agent update version file is found.
Expand Down
@@ -0,0 +1,73 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.core;

import java.io.Serializable;
import java.util.Properties;

import org.rhq.core.clientapi.server.core.AgentVersion;

/**
* A simple POJO that returns results from the AgentManagerBean that indicates if
* a particular version is supported or not. As part of these results, you get some information
* from the agent version file that is maintained by the server in case additional information
* is needed after the version check is made (such as, if the agent version is not supported, this
* addition information can tell you what is supported).
*
* @author John Mazzitelli
*/
public class AgentVersionCheckResults implements Serializable {
private static final long serialVersionUID = 1L;

private final boolean isSupported;
private final AgentVersion latestAgentVersion;

public AgentVersionCheckResults(boolean isSupported, AgentVersion latestAgentVersion) {
this.isSupported = isSupported;
this.latestAgentVersion = (AgentVersion) ((latestAgentVersion != null) ? latestAgentVersion : new Properties());

}

public boolean isSupported() {
return isSupported;
}

/**
* Returns the latest agent version information as known by the server. This contains
* information about the agent update distribution that the server provides.
*
* This will be null if the latest agent version information could not be determined.
*
* @return latest agent version information
*/
public AgentVersion getLatestAgentVersion() {
return latestAgentVersion;
}

@Override
public String toString() {
StringBuilder str = new StringBuilder("AgentVersionCheckResults: ");
str.append("is-supported=[");
str.append(this.isSupported);
str.append("; latest-agent-version=[");
str.append(this.latestAgentVersion);
str.append("]");
return str.toString();
}
}
Expand Up @@ -86,7 +86,7 @@ public AgentRegistrationResults registerAgent(AgentRegistrationRequest request)
AgentNotSupportedException {

// fail-fast if we can't even support this agent
if (!getAgentManager().isAgentVersionSupported(request.getAgentVersion())) {
if (!getAgentManager().isAgentVersionSupported(request.getAgentVersion()).isSupported()) {
log.warn("Agent [" + request.getName() + "][" + request.getAddress() + ':' + request.getPort() + "]["
+ request.getAgentVersion() + "] would like to register with this server but it is not supported");
throw new AgentNotSupportedException("Agent [" + request.getName() + "] is an unsupported agent: "
Expand Down Expand Up @@ -338,7 +338,8 @@ public ConnectAgentResults connectAgent(ConnectAgentRequest request) throws Agen

log.info("Agent [" + agentName + "][" + agentVersion + "] would like to connect to this server");

if (!getAgentManager().isAgentVersionSupported(agentVersion)) {
AgentVersionCheckResults agentVersionCheckResults = getAgentManager().isAgentVersionSupported(agentVersion);
if (!agentVersionCheckResults.isSupported()) {
log.warn("Agent [" + agentName + "][" + agentVersion
+ "] would like to connect to this server but it is not supported");
throw new AgentNotSupportedException("Agent [" + agentName + "] is an unsupported agent: " + agentVersion);
Expand All @@ -360,7 +361,8 @@ public ConnectAgentResults connectAgent(ConnectAgentRequest request) throws Agen
PartitionEventType.AGENT_CONNECT, agentName + " - " + server.getName());

log.info("Agent [" + agentName + "] has connected to this server at " + new Date());
return new ConnectAgentResults(System.currentTimeMillis(), agent.isBackFilled());
return new ConnectAgentResults(System.currentTimeMillis(), agent.isBackFilled(),
agentVersionCheckResults.getLatestAgentVersion());
}

/**
Expand Down

0 comments on commit 8576ff2

Please sign in to comment.