use of com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO in project cloudstack by apache.
the class HAProxyConfigurator method getRulesForPool.
private List<String> getRulesForPool(final LoadBalancerTO lbTO, final boolean keepAliveEnabled) {
StringBuilder sb = new StringBuilder();
final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString();
final String publicIP = lbTO.getSrcIp();
final String publicPort = Integer.toString(lbTO.getSrcPort());
final String algorithm = lbTO.getAlgorithm();
final List<String> result = new ArrayList<String>();
// add line like this: "listen 65_37_141_30-80 65.37.141.30:80"
sb = new StringBuilder();
sb.append("listen ").append(poolName).append(" ").append(publicIP).append(":").append(publicPort);
result.add(sb.toString());
sb = new StringBuilder();
sb.append("\t").append("balance ").append(algorithm);
result.add(sb.toString());
int i = 0;
Boolean destsAvailable = false;
final String stickinessSubRule = getLbSubRuleForStickiness(lbTO);
final List<String> dstSubRule = new ArrayList<String>();
final List<String> dstWithCookieSubRule = new ArrayList<String>();
for (final DestinationTO dest : lbTO.getDestinations()) {
// add line like this: "server 65_37_141_30-80_3 10.1.1.4:80 check"
if (dest.isRevoked()) {
continue;
}
sb = new StringBuilder();
sb.append("\t").append("server ").append(poolName).append("_").append(Integer.toString(i++)).append(" ").append(dest.getDestIp()).append(":").append(dest.getDestPort()).append(" check");
if (lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals("tcp-proxy")) {
sb.append(" send-proxy");
}
dstSubRule.add(sb.toString());
if (stickinessSubRule != null) {
sb.append(" cookie ").append(dest.getDestIp().replace(".", "_")).append('-').append(dest.getDestPort()).toString();
dstWithCookieSubRule.add(sb.toString());
}
destsAvailable = true;
}
Boolean httpbasedStickiness = false;
/* attach stickiness sub rule only if the destinations are available */
if (stickinessSubRule != null && destsAvailable == true) {
for (final StickinessPolicyTO stickinessPolicy : lbTO.getStickinessPolicies()) {
if (stickinessPolicy == null) {
continue;
}
if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()) || StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
httpbasedStickiness = true;
}
}
if (httpbasedStickiness) {
result.addAll(dstWithCookieSubRule);
} else {
result.addAll(dstSubRule);
}
result.add(stickinessSubRule);
} else {
result.addAll(dstSubRule);
}
if (stickinessSubRule != null && !destsAvailable) {
s_logger.warn("Haproxy stickiness policy for lb rule: " + lbTO.getSrcIp() + ":" + lbTO.getSrcPort() + ": Not Applied, cause: backends are unavailable");
}
if (publicPort.equals(NetUtils.HTTP_PORT) && !keepAliveEnabled || httpbasedStickiness) {
sb = new StringBuilder();
sb.append("\t").append("mode http");
result.add(sb.toString());
sb = new StringBuilder();
sb.append("\t").append("option httpclose");
result.add(sb.toString());
}
result.add(blankLine);
return result;
}
use of com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO in project cloudstack by apache.
the class NetscalerResource method getNetScalerProtocol.
private String getNetScalerProtocol(final LoadBalancerTO loadBalancer) throws ExecutionException {
final String port = Integer.toString(loadBalancer.getSrcPort());
String lbProtocol = loadBalancer.getLbProtocol();
final StickinessPolicyTO[] stickyPolicies = loadBalancer.getStickinessPolicies();
String nsProtocol = "TCP";
if (lbProtocol == null) {
lbProtocol = loadBalancer.getProtocol();
}
if (stickyPolicies != null && stickyPolicies.length > 0 && stickyPolicies[0] != null) {
final StickinessPolicyTO stickinessPolicy = stickyPolicies[0];
if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()) || StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
nsProtocol = "HTTP";
return nsProtocol;
}
}
if (lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO) || lbProtocol.equalsIgnoreCase(NetUtils.HTTP_PROTO)) {
return lbProtocol.toUpperCase();
}
if (port.equals(NetUtils.HTTP_PORT)) {
nsProtocol = "HTTP";
} else if (NetUtils.TCP_PROTO.equalsIgnoreCase(lbProtocol)) {
nsProtocol = "TCP";
} else if (NetUtils.UDP_PROTO.equalsIgnoreCase(lbProtocol)) {
nsProtocol = "UDP";
}
return nsProtocol;
}
use of com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO in project cloudstack by apache.
the class HAProxyConfigurator method getLbSubRuleForStickiness.
/*
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
[ postonly ] [ domain <domain> ]*
Enable cookie-based persistence in a backend.
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
Arguments :
<name> is the name of the cookie which will be monitored, modified or
inserted in order to bring persistence. This cookie is sent to
the client via a "Set-Cookie" header in the response, and is
brought back by the client in a "Cookie" header in all requests.
Special care should be taken to choose a name which does not
conflict with any likely application cookie. Also, if the same
backends are subject to be used by the same clients (eg:
HTTP/HTTPS), care should be taken to use different cookie names
between all backends if persistence between them is not desired.
rewrite This keyword indicates that the cookie will be provided by the
server and that haproxy will have to modify its value to set the
server's identifier in it. This mode is handy when the management
of complex combinations of "Set-cookie" and "Cache-control"
headers is left to the application. The application can then
decide whether or not it is appropriate to emit a persistence
cookie. Since all responses should be monitored, this mode only
works in HTTP close mode. Unless the application behaviour is
very complex and/or broken, it is advised not to start with this
mode for new deployments. This keyword is incompatible with
"insert" and "prefix".
insert This keyword indicates that the persistence cookie will have to
be inserted by haproxy in the responses. If the server emits a
cookie with the same name, it will be replaced anyway. For this
reason, this mode can be used to upgrade existing configurations
running in the "rewrite" mode. The cookie will only be a session
cookie and will not be stored on the client's disk. Due to
caching effects, it is generally wise to add the "indirect" and
"nocache" or "postonly" keywords (see below). The "insert"
keyword is not compatible with "rewrite" and "prefix".
prefix This keyword indicates that instead of relying on a dedicated
cookie for the persistence, an existing one will be completed.
This may be needed in some specific environments where the client
does not support more than one single cookie and the application
already needs it. In this case, whenever the server sets a cookie
named <name>, it will be prefixed with the server's identifier
and a delimiter. The prefix will be removed from all client
requests so that the server still finds the cookie it emitted.
Since all requests and responses are subject to being modified,
this mode requires the HTTP close mode. The "prefix" keyword is
not compatible with "rewrite" and "insert".
indirect When this option is specified in insert mode, cookies will only
be added when the server was not reached after a direct access,
which means that only when a server is elected after applying a
load-balancing algorithm, or after a redispatch, then the cookie
will be inserted. If the client has all the required information
to connect to the same server next time, no further cookie will
be inserted. In all cases, when the "indirect" option is used in
insert mode, the cookie is always removed from the requests
transmitted to the server. The persistence mechanism then becomes
totally transparent from the application point of view.
nocache This option is recommended in conjunction with the insert mode
when there is a cache between the client and HAProxy, as it
ensures that a cacheable response will be tagged non-cacheable if
a cookie needs to be inserted. This is important because if all
persistence cookies are added on a cacheable home page for
instance, then all customers will then fetch the page from an
outer cache and will all share the same persistence cookie,
leading to one server receiving much more traffic than others.
See also the "insert" and "postonly" options.
postonly This option ensures that cookie insertion will only be performed
on responses to POST requests. It is an alternative to the
"nocache" option, because POST responses are not cacheable, so
this ensures that the persistence cookie will never get cached.
Since most sites do not need any sort of persistence before the
first POST which generally is a login request, this is a very
efficient method to optimize caching without risking to find a
persistence cookie in the cache.
See also the "insert" and "nocache" options.
domain This option allows to specify the domain at which a cookie is
inserted. It requires exactly one parameter: a valid domain
name. If the domain begins with a dot, the browser is allowed to
use it for any host ending with that name. It is also possible to
specify several domain names by invoking this option multiple
times. Some browsers might have small limits on the number of
domains, so be careful when doing that. For the record, sending
10 domains to MSIE 6 or Firefox 2 works as expected.
There can be only one persistence cookie per HTTP backend, and it can be
declared in a defaults section. The value of the cookie will be the value
indicated after the "cookie" keyword in a "server" statement. If no cookie
is declared for a given server, the cookie is not set.
Examples :
cookie JSESSIONID prefix
cookie SRV insert indirect nocache
cookie SRV insert postonly indirect
appsession <cookie> len <length> timeout <holdtime>
[request-learn] [prefix] [mode <path-parameters|query-string>]
Define session stickiness on an existing application cookie.
May be used in sections : defaults | frontend | listen | backend
no | no | yes | yes
Arguments :
<cookie> this is the name of the cookie used by the application and which
HAProxy will have to learn for each new session.
<length> this is the max number of characters that will be memorized and
checked in each cookie value.
<holdtime> this is the time after which the cookie will be removed from
memory if unused. If no unit is specified, this time is in
milliseconds.
request-learn
If this option is specified, then haproxy will be able to learn
the cookie found in the request in case the server does not
specify any in response. This is typically what happens with
PHPSESSID cookies, or when haproxy's session expires before
the application's session and the correct server is selected.
It is recommended to specify this option to improve reliability.
prefix When this option is specified, haproxy will match on the cookie
prefix (or URL parameter prefix). The appsession value is the
data following this prefix.
Example :
appsession ASPSESSIONID len 64 timeout 3h prefix
This will match the cookie ASPSESSIONIDXXXX=XXXXX,
the appsession value will be XXXX=XXXXX.
mode This option allows to change the URL parser mode.
2 modes are currently supported :
- path-parameters :
The parser looks for the appsession in the path parameters
part (each parameter is separated by a semi-colon), which is
convenient for JSESSIONID for example.
This is the default mode if the option is not set.
- query-string :
In this mode, the parser will look for the appsession in the
query string.
When an application cookie is defined in a backend, HAProxy will check when
the server sets such a cookie, and will store its value in a table, and
associate it with the server's identifier. Up to <length> characters from
the value will be retained. On each connection, haproxy will look for this
cookie both in the "Cookie:" headers, and as a URL parameter (depending on
the mode used). If a known value is found, the client will be directed to the
server associated with this value. Otherwise, the load balancing algorithm is
applied. Cookies are automatically removed from memory when they have been
unused for a duration longer than <holdtime>.
The definition of an application cookie is limited to one per backend.
Example :
appsession JSESSIONID len 52 timeout 3h
*/
private String getLbSubRuleForStickiness(final LoadBalancerTO lbTO) {
int i = 0;
if (lbTO.getStickinessPolicies() == null) {
return null;
}
final StringBuilder sb = new StringBuilder();
for (final StickinessPolicyTO stickinessPolicy : lbTO.getStickinessPolicies()) {
if (stickinessPolicy == null) {
continue;
}
final List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
i++;
/*
* cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
[ postonly ] [ domain <domain> ]*
*/
if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
/* Default Values */
// optional
String cookieName = null;
// optional
String mode = "insert ";
// optional
Boolean indirect = false;
// optional
Boolean nocache = false;
// optional
Boolean postonly = false;
// optional
StringBuilder domainSb = null;
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("cookie-name".equalsIgnoreCase(key)) {
cookieName = value;
}
if ("mode".equalsIgnoreCase(key)) {
mode = value;
}
if ("domain".equalsIgnoreCase(key)) {
if (domainSb == null) {
domainSb = new StringBuilder();
}
domainSb = domainSb.append("domain ");
domainSb.append(value).append(" ");
}
if ("indirect".equalsIgnoreCase(key)) {
indirect = true;
}
if ("nocache".equalsIgnoreCase(key)) {
nocache = true;
}
if ("postonly".equalsIgnoreCase(key)) {
postonly = true;
}
}
if (cookieName == null) {
// re-check all haproxy mandatory params
final StringBuilder tempSb = new StringBuilder();
String srcip = lbTO.getSrcIp();
if (srcip == null) {
srcip = "TESTCOOKIE";
}
tempSb.append("lbcooki_").append(srcip.hashCode()).append("_").append(lbTO.getSrcPort());
cookieName = tempSb.toString();
}
sb.append("\t").append("cookie ").append(cookieName).append(" ").append(mode).append(" ");
if (indirect) {
sb.append("indirect ");
}
if (nocache) {
sb.append("nocache ");
}
if (postonly) {
sb.append("postonly ");
}
if (domainSb != null) {
sb.append(domainSb).append(" ");
}
} else if (StickinessMethodType.SourceBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
/* Default Values */
// optional
String tablesize = "200k";
// optional
String expire = "30m";
/* overwrite default values with the stick parameters */
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("tablesize".equalsIgnoreCase(key)) {
tablesize = value;
}
if ("expire".equalsIgnoreCase(key)) {
expire = value;
}
}
sb.append("\t").append("stick-table type ip size ").append(tablesize).append(" expire ").append(expire);
sb.append("\n\t").append("stick on src");
} else if (StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
/*
* FORMAT : appsession <cookie> len <length> timeout <holdtime>
* [request-learn] [prefix] [mode
* <path-parameters|query-string>]
*/
/* example: appsession JSESSIONID len 52 timeout 3h */
// optional
String cookieName = null;
// optional
String length = "52";
// optional
String holdtime = "3h";
// optional
String mode = null;
// optional
Boolean requestlearn = false;
// optional
Boolean prefix = false;
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("cookie-name".equalsIgnoreCase(key)) {
cookieName = value;
}
if ("length".equalsIgnoreCase(key)) {
length = value;
}
if ("holdtime".equalsIgnoreCase(key)) {
holdtime = value;
}
if ("mode".equalsIgnoreCase(key)) {
mode = value;
}
if ("request-learn".equalsIgnoreCase(key)) {
requestlearn = true;
}
if ("prefix".equalsIgnoreCase(key)) {
prefix = true;
}
}
if (cookieName == null) {
// re-check all haproxy mandatory params
final StringBuilder tempSb = new StringBuilder();
String srcip = lbTO.getSrcIp();
if (srcip == null) {
srcip = "TESTCOOKIE";
}
tempSb.append("appcookie_").append(srcip.hashCode()).append("_").append(lbTO.getSrcPort());
cookieName = tempSb.toString();
}
sb.append("\t").append("appsession ").append(cookieName).append(" len ").append(length).append(" timeout ").append(holdtime).append(" ");
if (prefix) {
sb.append("prefix ");
}
if (requestlearn) {
sb.append("request-learn").append(" ");
}
if (mode != null) {
sb.append("mode ").append(mode).append(" ");
}
} else {
/*
* Error is silently swallowed.
* Not supposed to reach here, validation of methods are
* done at the higher layer
*/
s_logger.warn("Haproxy stickiness policy for lb rule: " + lbTO.getSrcIp() + ":" + lbTO.getSrcPort() + ": Not Applied, cause:invalid method ");
return null;
}
}
if (i == 0) {
return null;
}
return sb.toString();
}
use of com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO in project cloudstack by apache.
the class F5BigIpResource method addVirtualServer.
// Virtual server methods
private void addVirtualServer(String virtualServerName, LbProtocol protocol, String srcIp, int srcPort, StickinessPolicyTO[] stickyPolicies) throws ExecutionException {
try {
if (!virtualServerExists(virtualServerName)) {
s_logger.debug("Adding virtual server " + virtualServerName);
_virtualServerApi.create(genVirtualServerDefinition(virtualServerName, protocol, srcIp, srcPort), new String[] { "255.255.255.255" }, genVirtualServerResource(virtualServerName), genVirtualServerProfile(protocol));
_virtualServerApi.set_snat_automap(genStringArray(virtualServerName));
if (!virtualServerExists(virtualServerName)) {
throw new ExecutionException("Failed to add virtual server " + virtualServerName);
}
}
if ((stickyPolicies != null) && (stickyPolicies.length > 0) && (stickyPolicies[0] != null)) {
StickinessPolicyTO stickinessPolicy = stickyPolicies[0];
if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
String[] profileNames = genStringArray("Cookie-profile-" + virtualServerName);
if (!persistenceProfileExists(profileNames[0])) {
LocalLBPersistenceMode[] lbPersistenceMode = new iControl.LocalLBPersistenceMode[1];
lbPersistenceMode[0] = iControl.LocalLBPersistenceMode.PERSISTENCE_MODE_COOKIE;
_persistenceProfileApi.create(profileNames, lbPersistenceMode);
_virtualServerApi.add_persistence_profile(genStringArray(virtualServerName), genPersistenceProfile(profileNames[0]));
}
List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
for (Pair<String, String> param : paramsList) {
if ("holdtime".equalsIgnoreCase(param.first())) {
//F5 default
long timeout = 180;
if (param.second() != null) {
timeout = Long.parseLong(param.second());
}
LocalLBProfileULong[] cookieTimeout = new LocalLBProfileULong[1];
cookieTimeout[0] = new LocalLBProfileULong();
cookieTimeout[0].setValue(timeout);
_persistenceProfileApi.set_cookie_expiration(profileNames, cookieTimeout);
}
}
}
} else {
_virtualServerApi.remove_all_persistence_profiles(genStringArray(virtualServerName));
}
} catch (RemoteException e) {
throw new ExecutionException(e.getMessage());
}
}
use of com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO in project cloudstack by apache.
the class NetscalerResource method addLBVirtualServer.
private void addLBVirtualServer(final String virtualServerName, final String publicIp, final int publicPort, final String lbAlgorithm, final String protocol, final StickinessPolicyTO[] stickyPolicies, final AutoScaleVmGroupTO vmGroupTO) throws ExecutionException {
try {
String lbMethod;
if ("roundrobin".equalsIgnoreCase(lbAlgorithm)) {
lbMethod = "ROUNDROBIN";
} else if ("leastconn".equalsIgnoreCase(lbAlgorithm)) {
lbMethod = "LEASTCONNECTION";
} else if ("source".equalsIgnoreCase(lbAlgorithm)) {
lbMethod = "SOURCEIPHASH";
} else {
throw new ExecutionException("Got invalid load balancing algorithm: " + lbAlgorithm + " in the load balancing rule");
}
boolean vserverExisis = false;
lbvserver vserver = getVirtualServerIfExisits(virtualServerName);
if (vserver != null) {
if (!vserver.get_servicetype().equalsIgnoreCase(protocol)) {
throw new ExecutionException("Can not update virtual server:" + virtualServerName + " as current protocol:" + vserver.get_servicetype() + " of virtual server is different from the " + " intended protocol:" + protocol);
}
vserverExisis = true;
}
// Use new vserver always for configuration
vserver = new lbvserver();
vserver.set_name(virtualServerName);
vserver.set_ipv46(publicIp);
vserver.set_port(publicPort);
vserver.set_servicetype(protocol);
vserver.set_lbmethod(lbMethod);
// netmask can only be set for source IP load balancer algorithm
if (!lbMethod.equalsIgnoreCase("SOURCEIPHASH")) {
vserver.set_netmask(null);
vserver.set_v6netmasklen(null);
}
if (stickyPolicies != null && stickyPolicies.length > 0 && stickyPolicies[0] != null) {
// netscaler default 2 min
long timeout = 2;
String cookieName = null;
final StickinessPolicyTO stickinessPolicy = stickyPolicies[0];
// get the session persistence parameters
final List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
for (final Pair<String, String> param : paramsList) {
if ("holdtime".equalsIgnoreCase(param.first())) {
timeout = Long.parseLong(param.second());
} else if ("name".equalsIgnoreCase(param.first())) {
cookieName = param.second();
}
}
// configure virtual server based on the persistence method
if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
vserver.set_persistencetype("COOKIEINSERT");
} else if (StickinessMethodType.SourceBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
vserver.set_persistencetype("SOURCEIP");
} else if (StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
vserver.set_persistencetype("RULE");
vserver.set_rule("HTTP.REQ.HEADER(\"COOKIE\").VALUE(0).typecast_nvlist_t('=',';').value(\"" + cookieName + "\")");
vserver.set_resrule("HTTP.RES.HEADER(\"SET-COOKIE\").VALUE(0).typecast_nvlist_t('=',';').value(\"" + cookieName + "\")");
} else {
throw new ExecutionException("Got invalid session persistence method: " + stickinessPolicy.getMethodName() + " in the load balancing rule");
}
// set session persistence timeout
vserver.set_timeout(timeout);
} else {
// delete the LB stickyness policy
vserver.set_persistencetype("NONE");
}
if (vserverExisis) {
apiCallResult = lbvserver.update(_netscalerService, vserver);
} else {
apiCallResult = lbvserver.add(_netscalerService, vserver);
}
if (apiCallResult.errorcode != 0) {
throw new ExecutionException("Failed to create new load balancing virtual server:" + virtualServerName + " due to " + apiCallResult.message);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Created load balancing virtual server " + virtualServerName + " on the Netscaler device");
}
} catch (final nitro_exception e) {
throw new ExecutionException("Failed to create new virtual server:" + virtualServerName + " due to " + e.getMessage());
} catch (final Exception e) {
throw new ExecutionException("Failed to create new virtual server:" + virtualServerName + " due to " + e.getMessage());
}
}
Aggregations