mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-317: Merge Add support for failover-only connections.
This commit is contained in:
@@ -61,6 +61,13 @@ public class ConnectionModel extends ChildObjectModel {
|
||||
*/
|
||||
private Integer connectionWeight;
|
||||
|
||||
/**
|
||||
* Whether this connection should be reserved for failover. Failover-only
|
||||
* connections within a balancing group are only used when all non-failover
|
||||
* connections are unavailable.
|
||||
*/
|
||||
private boolean failoverOnly;
|
||||
|
||||
/**
|
||||
* The identifiers of all readable sharing profiles associated with this
|
||||
* connection.
|
||||
@@ -196,6 +203,32 @@ public class ConnectionModel extends ChildObjectModel {
|
||||
return connectionWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this connection should be reserved for failover.
|
||||
* Failover-only connections within a balancing group are only used when
|
||||
* all non-failover connections are unavailable.
|
||||
*
|
||||
* @return
|
||||
* true if this connection should be reserved for failover, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isFailoverOnly() {
|
||||
return failoverOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this connection should be reserved for failover.
|
||||
* Failover-only connections within a balancing group are only used when
|
||||
* all non-failover connections are unavailable.
|
||||
*
|
||||
* @param failoverOnly
|
||||
* true if this connection should be reserved for failover, false
|
||||
* otherwise.
|
||||
*/
|
||||
public void setFailoverOnly(boolean failoverOnly) {
|
||||
this.failoverOnly = failoverOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections that can be established to this
|
||||
* connection concurrently by any one user.
|
||||
|
@@ -32,6 +32,7 @@ import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObject;
|
||||
import org.apache.guacamole.form.BooleanField;
|
||||
import org.apache.guacamole.form.EnumField;
|
||||
import org.apache.guacamole.form.Field;
|
||||
import org.apache.guacamole.form.Form;
|
||||
@@ -121,6 +122,13 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
|
||||
*/
|
||||
public static final String CONNECTION_WEIGHT = "weight";
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls whether the connection should
|
||||
* be used as a spare only (all other non-spare connections within the same
|
||||
* balancing group should be preferred).
|
||||
*/
|
||||
public static final String FAILOVER_ONLY_NAME = "failover-only";
|
||||
|
||||
/**
|
||||
* All attributes related to restricting user accounts, within a logical
|
||||
* form.
|
||||
@@ -134,7 +142,8 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
|
||||
* All attributes related to load balancing in a logical form.
|
||||
*/
|
||||
public static final Form LOAD_BALANCING = new Form("load-balancing", Arrays.<Field>asList(
|
||||
new NumericField(CONNECTION_WEIGHT)
|
||||
new NumericField(CONNECTION_WEIGHT),
|
||||
new BooleanField(FAILOVER_ONLY_NAME, "true")
|
||||
));
|
||||
|
||||
/**
|
||||
@@ -281,6 +290,9 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
|
||||
// Set connection weight
|
||||
attributes.put(CONNECTION_WEIGHT, NumericField.format(getModel().getConnectionWeight()));
|
||||
|
||||
// Set whether connection is failover-only
|
||||
attributes.put(FAILOVER_ONLY_NAME, getModel().isFailoverOnly() ? "true" : null);
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@@ -333,6 +345,9 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate failover-only attribute
|
||||
getModel().setFailoverOnly("true".equals(attributes.get(FAILOVER_ONLY_NAME)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,4 +451,17 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this connection should be reserved for failover.
|
||||
* Failover-only connections within a balancing group are only used when
|
||||
* all non-failover connections are unavailable.
|
||||
*
|
||||
* @return
|
||||
* true if this connection should be reserved for failover, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isFailoverOnly() {
|
||||
return getModel().isFailoverOnly();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -44,7 +44,6 @@ import org.apache.guacamole.GuacamoleResourceNotFoundException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.GuacamoleServerException;
|
||||
import org.apache.guacamole.GuacamoleUpstreamException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionMapper;
|
||||
import org.apache.guacamole.net.GuacamoleSocket;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
@@ -143,6 +142,10 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
* @param connections
|
||||
* The connections being accessed.
|
||||
*
|
||||
* @param includeFailoverOnly
|
||||
* Whether connections which have been designated for use in failover
|
||||
* situations only (hot spares) may be considered.
|
||||
*
|
||||
* @return
|
||||
* The connection that has been acquired on behalf of the given user.
|
||||
*
|
||||
@@ -150,7 +153,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
* If access is denied to the given user for any reason.
|
||||
*/
|
||||
protected abstract ModeledConnection acquire(RemoteAuthenticatedUser user,
|
||||
List<ModeledConnection> connections) throws GuacamoleException;
|
||||
List<ModeledConnection> connections, boolean includeFailoverOnly)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Releases possibly-exclusive access to the given connection on behalf of
|
||||
@@ -647,8 +651,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
final ModeledConnection connection, GuacamoleClientInformation info)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Acquire access to single connection
|
||||
acquire(user, Collections.singletonList(connection));
|
||||
// Acquire access to single connection, ignoring the failover-only flag
|
||||
acquire(user, Collections.singletonList(connection), true);
|
||||
|
||||
// Connect only if the connection was successfully acquired
|
||||
ActiveConnectionRecord connectionRecord = activeConnectionRecordProvider.get();
|
||||
@@ -668,6 +672,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
ModeledConnectionGroup connectionGroup,
|
||||
GuacamoleClientInformation info) throws GuacamoleException {
|
||||
|
||||
// Track failures in upstream (remote desktop) connections
|
||||
boolean upstreamHasFailed = false;
|
||||
|
||||
// If group has no associated balanced connections, cannot connect
|
||||
List<ModeledConnection> connections = getBalancedConnections(user, connectionGroup);
|
||||
if (connections.isEmpty())
|
||||
@@ -678,10 +685,11 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
// Acquire group
|
||||
acquire(user, connectionGroup);
|
||||
|
||||
// Attempt to acquire to any child
|
||||
// Attempt to acquire to any child, including failover-only
|
||||
// connections only if at least one upstream failure has occurred
|
||||
ModeledConnection connection;
|
||||
try {
|
||||
connection = acquire(user, connections);
|
||||
connection = acquire(user, connections, upstreamHasFailed);
|
||||
}
|
||||
|
||||
// Ensure connection group is always released if child acquire fails
|
||||
@@ -701,6 +709,14 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
if (connectionGroup.isSessionAffinityEnabled())
|
||||
user.preferConnection(connection.getIdentifier());
|
||||
|
||||
// Warn if we are connecting to a failover-only connection
|
||||
if (connection.isFailoverOnly())
|
||||
logger.warn("One or more normal connections within "
|
||||
+ "group \"{}\" have failed. Some connection "
|
||||
+ "attempts are being routed to designated "
|
||||
+ "failover-only connections.",
|
||||
connectionGroup.getIdentifier());
|
||||
|
||||
return tunnel;
|
||||
|
||||
}
|
||||
@@ -711,6 +727,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
logger.info("Upstream error intercepted for connection \"{}\". Failing over to next connection in group...", connection.getIdentifier());
|
||||
logger.debug("Upstream remote desktop reported an error during connection.", e);
|
||||
connections.remove(connection);
|
||||
upstreamHasFailed = true;
|
||||
}
|
||||
|
||||
} while (!connections.isEmpty());
|
||||
|
@@ -171,7 +171,8 @@ public class RestrictedGuacamoleTunnelService
|
||||
|
||||
@Override
|
||||
protected ModeledConnection acquire(RemoteAuthenticatedUser user,
|
||||
List<ModeledConnection> connections) throws GuacamoleException {
|
||||
List<ModeledConnection> connections, boolean includeFailoverOnly)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Do not acquire connection unless within overall limits
|
||||
if (!tryIncrement(totalActiveConnections, environment.getAbsoluteMaxConnections()))
|
||||
@@ -222,6 +223,11 @@ public class RestrictedGuacamoleTunnelService
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip connections which are failover-only if they are excluded
|
||||
// from this connection attempt
|
||||
if (!includeFailoverOnly && connection.isFailoverOnly())
|
||||
continue;
|
||||
|
||||
// Attempt to aquire connection according to per-user limits
|
||||
Seat seat = new Seat(username, connection.getIdentifier());
|
||||
if (tryAdd(activeSeats, seat,
|
||||
|
@@ -20,6 +20,7 @@
|
||||
"FIELD_HEADER_MAX_CONNECTIONS" : "Maximum number of connections:",
|
||||
"FIELD_HEADER_MAX_CONNECTIONS_PER_USER" : "Maximum number of connections per user:",
|
||||
|
||||
"FIELD_HEADER_FAILOVER_ONLY" : "Use for failover only:",
|
||||
"FIELD_HEADER_WEIGHT" : "Connection weight:",
|
||||
|
||||
"FIELD_HEADER_GUACD_HOSTNAME" : "Hostname:",
|
||||
|
@@ -65,9 +65,9 @@ CREATE TABLE `guacamole_connection` (
|
||||
`max_connections` int(11),
|
||||
`max_connections_per_user` int(11),
|
||||
|
||||
-- Connection weight
|
||||
-- Load-balancing behavior
|
||||
`connection_weight` int(11),
|
||||
|
||||
`failover_only` boolean NOT NULL DEFAULT 0,
|
||||
|
||||
PRIMARY KEY (`connection_id`),
|
||||
UNIQUE KEY `connection_name_parent` (`connection_name`, `parent_id`),
|
||||
|
@@ -23,3 +23,10 @@
|
||||
|
||||
ALTER TABLE guacamole_connection
|
||||
ADD COLUMN connection_weight int(11);
|
||||
|
||||
--
|
||||
-- Add failover-only flag
|
||||
--
|
||||
|
||||
ALTER TABLE guacamole_connection
|
||||
ADD COLUMN failover_only BOOLEAN NOT NULL DEFAULT 0;
|
||||
|
@@ -38,6 +38,7 @@
|
||||
<result column="proxy_encryption_method" property="proxyEncryptionMethod" jdbcType="VARCHAR"
|
||||
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
||||
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
||||
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
||||
|
||||
<!-- Associated sharing profiles -->
|
||||
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
||||
@@ -97,7 +98,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
FROM guacamole_connection
|
||||
WHERE connection_id IN
|
||||
<foreach collection="identifiers" item="identifier"
|
||||
@@ -129,7 +131,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
FROM guacamole_connection
|
||||
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
|
||||
WHERE guacamole_connection.connection_id IN
|
||||
@@ -166,7 +169,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
FROM guacamole_connection
|
||||
WHERE
|
||||
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
|
||||
@@ -194,7 +198,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
)
|
||||
VALUES (
|
||||
#{object.name,jdbcType=VARCHAR},
|
||||
@@ -205,7 +210,8 @@
|
||||
#{object.proxyHostname,jdbcType=VARCHAR},
|
||||
#{object.proxyPort,jdbcType=INTEGER},
|
||||
#{object.proxyEncryptionMethod,jdbcType=VARCHAR},
|
||||
#{object.connectionWeight,jdbcType=INTEGER}
|
||||
#{object.connectionWeight,jdbcType=INTEGER},
|
||||
#{object.failoverOnly,jdbcType=BOOLEAN}
|
||||
)
|
||||
|
||||
</insert>
|
||||
@@ -221,7 +227,8 @@
|
||||
proxy_hostname = #{object.proxyHostname,jdbcType=VARCHAR},
|
||||
proxy_port = #{object.proxyPort,jdbcType=INTEGER},
|
||||
proxy_encryption_method = #{object.proxyEncryptionMethod,jdbcType=VARCHAR},
|
||||
connection_weight = #{object.connectionWeight,jdbcType=INTEGER}
|
||||
connection_weight = #{object.connectionWeight,jdbcType=INTEGER},
|
||||
failover_only = #{object.failoverOnly,jdbcType=BOOLEAN}
|
||||
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
|
||||
</update>
|
||||
|
||||
|
@@ -108,6 +108,7 @@ CREATE TABLE guacamole_connection (
|
||||
|
||||
-- Connection Weight
|
||||
connection_weight integer,
|
||||
failover_only boolean NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Guacamole proxy (guacd) overrides
|
||||
proxy_port integer,
|
||||
|
@@ -23,3 +23,10 @@
|
||||
|
||||
ALTER TABLE guacamole_connection
|
||||
ADD COLUMN connection_weight int;
|
||||
|
||||
--
|
||||
-- Add failover-only flag
|
||||
--
|
||||
|
||||
ALTER TABLE guacamole_connection
|
||||
ADD COLUMN failover_only BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
|
@@ -38,6 +38,7 @@
|
||||
<result column="proxy_encryption_method" property="proxyEncryptionMethod" jdbcType="VARCHAR"
|
||||
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
||||
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
||||
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
||||
|
||||
<!-- Associated sharing profiles -->
|
||||
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
||||
@@ -97,7 +98,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
FROM guacamole_connection
|
||||
WHERE connection_id IN
|
||||
<foreach collection="identifiers" item="identifier"
|
||||
@@ -129,7 +131,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
FROM guacamole_connection
|
||||
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
|
||||
WHERE guacamole_connection.connection_id IN
|
||||
@@ -166,7 +169,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
FROM guacamole_connection
|
||||
WHERE
|
||||
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
|
||||
@@ -194,7 +198,8 @@
|
||||
proxy_hostname,
|
||||
proxy_port,
|
||||
proxy_encryption_method,
|
||||
connection_weight
|
||||
connection_weight,
|
||||
failover_only
|
||||
)
|
||||
VALUES (
|
||||
#{object.name,jdbcType=VARCHAR},
|
||||
@@ -205,7 +210,8 @@
|
||||
#{object.proxyHostname,jdbcType=VARCHAR},
|
||||
#{object.proxyPort,jdbcType=INTEGER},
|
||||
#{object.proxyEncryptionMethod,jdbcType=VARCHAR}::guacamole_proxy_encryption_method,
|
||||
#{object.connectionWeight,jdbcType=INTEGER}
|
||||
#{object.connectionWeight,jdbcType=INTEGER},
|
||||
#{object.failoverOnly,jdbcType=BOOLEAN}
|
||||
)
|
||||
|
||||
</insert>
|
||||
@@ -221,7 +227,8 @@
|
||||
proxy_hostname = #{object.proxyHostname,jdbcType=VARCHAR},
|
||||
proxy_port = #{object.proxyPort,jdbcType=INTEGER},
|
||||
proxy_encryption_method = #{object.proxyEncryptionMethod,jdbcType=VARCHAR}::guacamole_proxy_encryption_method,
|
||||
connection_weight = #{object.connectionWeight,jdbcType=INTEGER}
|
||||
connection_weight = #{object.connectionWeight,jdbcType=INTEGER},
|
||||
failover_only = #{object.failoverOnly,jdbcType=BOOLEAN}
|
||||
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}::integer
|
||||
</update>
|
||||
|
||||
|
Reference in New Issue
Block a user