/**
* Copyright (C) 2012-2015 Dell, Inc
* See annotations for authorship information
*
* ====================================================================
* Licensed 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.dasein.cloud.google.capabilities;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.log4j.Logger;
import org.dasein.cloud.*;
import org.dasein.cloud.network.IPVersion;
import org.dasein.cloud.network.LbAlgorithm;
import org.dasein.cloud.network.LbEndpointType;
import org.dasein.cloud.network.LbPersistence;
import org.dasein.cloud.network.LbProtocol;
import org.dasein.cloud.network.LoadBalancerAddressType;
import org.dasein.cloud.network.LoadBalancerCapabilities;
import org.dasein.cloud.util.NamingConstraints;
import org.dasein.cloud.google.Google;
public class GCELoadBalancerCapabilities extends AbstractCapabilities<Google> implements LoadBalancerCapabilities {
static private final Logger logger = Logger.getLogger(GCELoadBalancerCapabilities.class);
public GCELoadBalancerCapabilities(@Nonnull Google Google) {
super(Google);
}
@Nonnull
@Override
public LoadBalancerAddressType getAddressType() throws CloudException, InternalException {
return LoadBalancerAddressType.DNS;
}
@Override
public int getMaxPublicPorts() throws CloudException, InternalException {
// 0 means all ports
return 0;
}
@Nonnull
@Override
public String getProviderTermForLoadBalancer(Locale locale) {
return "load balancer"; // target pools are a component utilized by load balancer
}
@Nullable
@Override
public VisibleScope getLoadBalancerVisibleScope() {
return VisibleScope.ACCOUNT_REGION;
}
@Override
public boolean healthCheckRequiresLoadBalancer() throws CloudException, InternalException {
/*
* http://salt.readthedocs.org/en/latest/topics/cloud/gce.html#http-health-check
*
* It looks like Health check is user implemented, documents seem to always reference
* health check in a load balance context.
*/
return true;
}
@Override
public Requirement identifyEndpointsOnCreateRequirement() throws CloudException, InternalException {
/*
* https://developers.google.com/compute/docs/load-balancing/#configurelb
*
* standing up load balancing appears to be a 3 step process
* with the final step being to define listeners/endpoints
*/
return Requirement.OPTIONAL;
}
@Nonnull
@Override
public Requirement identifyListenersOnCreateRequirement() throws CloudException, InternalException {
/*
* https://developers.google.com/compute/docs/load-balancing/#configurelb
*
* standing up load balancing appears to be a 3 step process
* with the final step being to define listeners/endpoints
*/
return Requirement.OPTIONAL;
}
@Override
public boolean isAddressAssignedByProvider() throws CloudException, InternalException {
/*
* https://developers.google.com/compute/docs/load-balancing/
* me@local:~$ gcutil --project=<project-id> addinstance www1 www2 www3 --zone=$ZONE \
* --tags=$TAG --metadata_from_file=startup-script:$HOME/lb_startup.sh
*/
return true;
}
@Override
public boolean isDataCenterLimited() throws CloudException, InternalException {
/*
* https://developers.google.com/compute/docs/load-balancing/#algorithm
*
* You can associate target pools in different zones with a single forwarding
* rule to provide protection from planned or unplanned zone outages.
*/
return false;
}
@Nonnull
@Override
public Iterable<LbAlgorithm> listSupportedAlgorithms() throws CloudException, InternalException {
/*
* https://developers.google.com/compute/docs/load-balancing/#algorithm
* By default, to distribute traffic to instances, Google Compute Engine picks an instance
* based on a hash of the source IP and port and the destination IP and port. Incoming TCP
* connections are spread across instances and each new connection may go to a different
* instance. All packets for a connection are directed to the same instance until the
* connection is closed.
*
* https://developers.google.com/compute/docs/load-balancing/#sessionAffinity
* sessionAffinity
* NONE 5-tuple hashing provides a good distribution of traffic across many virtual machines but if you wanted to use a single backend with a specific client ('stick' a client to a single virtual machine instance), you can also specify the following options:
* CLIENT_IP_PROTO 3-tuple hashing, which includes the source / destination IP and network protocol
* CLIENT_IP 2-tuple hashing, which includes the source / destination IP
*/
return Collections.singletonList(LbAlgorithm.SOURCE);
}
@Nonnull
@Override
public Iterable<LbEndpointType> listSupportedEndpointTypes() throws CloudException, InternalException {
return Collections.singletonList(LbEndpointType.VM);
}
static private volatile List<IPVersion> versions;
@Nonnull
@Override
public Iterable<IPVersion> listSupportedIPVersions() throws CloudException, InternalException {
// https://developers.google.com/compute/docs/networking
/*
* Google Compute Engine currently does not support IPv6
*/
if( versions == null ) {
versions = Collections.unmodifiableList(Arrays.asList(
IPVersion.IPV4
));
}
return versions;
}
@Nonnull
@Override
public Iterable<LbPersistence> listSupportedPersistenceOptions() throws CloudException, InternalException {
/*
* https://developers.google.com/compute/docs/load-balancing/#targetpools
*
* sessionAffinity
* [Optional] Describes the method used to select a backend virtual machine instance. You can only set
* this value during the creation of the target pool. Once set, you cannot modify this value. By default,
* a 5-tuple method is used and the default value for this field is NONE. The 5-tuple hash method
* selects a backend based on:
* Layer 4 Protocol (e.g. TCP, UDP)
* Source / Destination IP
* Source / Destination Port
* 5-tuple hashing provides a good distribution of traffic across many virtual machines but if
* you wanted to use a single backend with a specific client ('stick' a client to a single virtual
* machine instance), you can also specify the following options:
* CLIENT_IP_PROTO
* 3-tuple hashing, which includes the source / destination IP and network protocol
* CLIENT_IP
* 2-tuple hashing, which includes the source / destination IP
* In general, if you select a 3-tuple or 2-tuple method, it will provide for better session affinity
* than the default 5-tuple method, at the cost of possibly unequal distribution of traffic.
* Caution: If a large portion of your clients are behind a proxy server, you should not use the
* sessionAffinity feature because it would force all clients behind the proxy to be pinned to a
* specific backend.
*/
return Collections.singletonList(LbPersistence.SUBNET); // Best guess given above...
}
static private volatile List<LbProtocol> protocols;
@Nonnull
@Override
public Iterable<LbProtocol> listSupportedProtocols() throws CloudException, InternalException {
/*
* The type of protocol that this forwarding rule matches. Valid values are:
* "AH": Specifies the IP Authentication Header protocol.
* "ESP": Specifies the IP Encapsulating Security Payload protocol.
* "SCTP": Specifies the Stream Control Transmission Protocol.
* "TCP": Specifies the Transmission Control Protocol.
* "UDP": Specifies the User Datagram Protocol.
* If left empty, this field will default to TCP. Also note that certain protocols can only
* be used with target pools or target instances:
* If you use ESP, AH, or SCTP, you must specify a target instance. It is not possible to specify
* a target pool when using these protocols.
* If you use TCP or UDP, you can specify either a target pool or a target instance.
*/
if( protocols == null ) {
protocols = Collections.unmodifiableList(Arrays.asList(
LbProtocol.RAW_TCP //,
//LbProtocol.SCTP,
//LbProtocol.UDP,
//LbProtocol.ESP,
//LbProtocol.AH
));
}
return protocols;
}
@Override
public boolean supportsAddingEndpoints() throws CloudException, InternalException {
// https://developers.google.com/compute/docs/load-balancing/
/*
* "You can add or remove instances from an existing target pool"
*
* Caution: If your target pool currently has the sessionAffinity field set,
* resizing the target pool could cause requests that come from the same IP
* to go to a different instance initially. Eventually, all connections from
* the IP will go to the same virtual machine, as the old connections close.
*/
return true;
}
@Override
public boolean supportsMonitoring() throws CloudException, InternalException {
// https://developers.google.com/compute/docs/load-balancing/
/*
* Google Compute Engine load balancing allows you to create forwarding
* rule objects that match and direct certain types of traffic to a load
* balancer. A target pool object controls the load balancer and contains
* the set of instances to send traffic to. Target pools also contain a health
* check object to determine the health of instances in the corresponding
* target pool.
*/
return true;
}
@Override
public boolean supportsMultipleTrafficTypes() throws CloudException, InternalException {
// https://developers.google.com/compute/docs/networking
/*
* Google Compute Engine currently does not support IPv6
*/
return false;
}
@Override
public Requirement healthCheckRequiresName() throws CloudException, InternalException {
return Requirement.REQUIRED;
}
@Override
public Requirement identifyVlanOnCreateRequirement() throws CloudException, InternalException {
return Requirement.NONE;
}
@Override
public @Nonnull Requirement identifyHealthCheckOnCreateRequirement() throws CloudException, InternalException {
return Requirement.OPTIONAL;
}
@Override
public @Nonnull NamingConstraints getLoadBalancerNamingConstraints() {
return NamingConstraints.getAlphaNumeric(1, 63)
.withRegularExpression("^[a-z][-a-z0-9]{0,61}[a-z0-9]$")
.lowerCaseOnly()
.withNoSpaces()
.withLastCharacterSymbolAllowed(false)
.constrainedBy('-');
}
@Override
public boolean supportsSslCertificateStore() throws CloudException, InternalException {
return true;
}
}