formatting code
Project: http://git-wip-us.apache.org/repos/asf/stratos/repo Commit: http://git-wip-us.apache.org/repos/asf/stratos/commit/8ccdeb6d Tree: http://git-wip-us.apache.org/repos/asf/stratos/tree/8ccdeb6d Diff: http://git-wip-us.apache.org/repos/asf/stratos/diff/8ccdeb6d Branch: refs/heads/stratos-4.1.x Commit: 8ccdeb6da58569c9f3ddb9faf326f72a2f63785e Parents: 72f7af7 Author: Isuru Haththotuwa <[email protected]> Authored: Wed Nov 4 19:31:59 2015 +0530 Committer: Isuru Haththotuwa <[email protected]> Committed: Tue Nov 10 13:33:14 2015 +0530 ---------------------------------------------------------------------- .../apache/stratos/aws/extension/AWSHelper.java | 2024 +++++++++--------- .../stratos/aws/extension/AWSLoadBalancer.java | 653 +++--- 2 files changed, 1328 insertions(+), 1349 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/stratos/blob/8ccdeb6d/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java index c9500f7..bcb92e5 100644 --- a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java +++ b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java @@ -49,1066 +49,1044 @@ import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingCli import com.amazonaws.services.elasticloadbalancing.model.*; public class AWSHelper { - private String awsAccessKey; - private String awsSecretKey; - private String lbPrefix; - private String lbSecurityGroupName; - private String lbSecurityGroupDescription; - private String allowedCidrIpForLBSecurityGroup; - private int statisticsInterval; - private String sslCertificateId; - private String appStickySessionCookie; + private String awsAccessKey; + private String awsSecretKey; + private String lbPrefix; + private String lbSecurityGroupName; + private String lbSecurityGroupDescription; + private String allowedCidrIpForLBSecurityGroup; + private int statisticsInterval; + private String sslCertificateId; + private String appStickySessionCookie; - private AtomicInteger lbSequence; + private AtomicInteger lbSequence; - private List<String> allowedProtocolsForLBSecurityGroup; + private List<String> allowedProtocolsForLBSecurityGroup; - private ConcurrentHashMap<String, String> regionToSecurityGroupIdMap; + private ConcurrentHashMap<String, String> regionToSecurityGroupIdMap; - private BasicAWSCredentials awsCredentials; - private ClientConfiguration clientConfiguration; + private BasicAWSCredentials awsCredentials; + private ClientConfiguration clientConfiguration; - AmazonElasticLoadBalancingClient elbClient; - AmazonEC2Client ec2Client; - private AmazonCloudWatchClient cloudWatchClient; + AmazonElasticLoadBalancingClient elbClient; + AmazonEC2Client ec2Client; + private AmazonCloudWatchClient cloudWatchClient; - private static final Log log = LogFactory.getLog(AWSHelper.class); + private static final Log log = LogFactory.getLog(AWSHelper.class); - public AWSHelper() throws LoadBalancerExtensionException { - // Read values for awsAccessKey, awsSecretKey etc. from config file + public AWSHelper() throws LoadBalancerExtensionException { + // Read values for awsAccessKey, awsSecretKey etc. from config file - String awsPropertiesFile = System - .getProperty(Constants.AWS_PROPERTIES_FILE); + String awsPropertiesFile = System + .getProperty(Constants.AWS_PROPERTIES_FILE); - Properties properties = new Properties(); + Properties properties = new Properties(); - InputStream inputStream = null; + InputStream inputStream = null; - try { - inputStream = new FileInputStream(awsPropertiesFile); + try { + inputStream = new FileInputStream(awsPropertiesFile); - properties.load(inputStream); + properties.load(inputStream); - this.awsAccessKey = properties - .getProperty(Constants.AWS_ACCESS_KEY); - this.awsSecretKey = properties - .getProperty(Constants.AWS_SECRET_KEY); + this.awsAccessKey = properties + .getProperty(Constants.AWS_ACCESS_KEY); + this.awsSecretKey = properties + .getProperty(Constants.AWS_SECRET_KEY); - if (this.awsAccessKey.isEmpty() || this.awsSecretKey.isEmpty()) { - throw new LoadBalancerExtensionException( - "Invalid AWS credentials."); - } + if (this.awsAccessKey.isEmpty() || this.awsSecretKey.isEmpty()) { + throw new LoadBalancerExtensionException( + "Invalid AWS credentials."); + } - this.lbPrefix = properties.getProperty(Constants.LB_PREFIX); + this.lbPrefix = properties.getProperty(Constants.LB_PREFIX); - if (this.lbPrefix.isEmpty() - || this.lbPrefix.length() > Constants.LOAD_BALANCER_PREFIX_MAX_LENGTH) { - throw new LoadBalancerExtensionException( - "Invalid load balancer prefix."); - } + if (this.lbPrefix.isEmpty() + || this.lbPrefix.length() > Constants.LOAD_BALANCER_PREFIX_MAX_LENGTH) { + throw new LoadBalancerExtensionException( + "Invalid load balancer prefix."); + } - lbSequence = new AtomicInteger(1); + lbSequence = new AtomicInteger(1); - this.lbSecurityGroupName = properties - .getProperty(Constants.LOAD_BALANCER_SECURITY_GROUP_NAME); + this.lbSecurityGroupName = properties + .getProperty(Constants.LOAD_BALANCER_SECURITY_GROUP_NAME); - if (this.lbSecurityGroupName.isEmpty() - || this.lbSecurityGroupName.length() > Constants.SECURITY_GROUP_NAME_MAX_LENGTH) { - throw new LoadBalancerExtensionException( - "Invalid load balancer security group name."); - } + if (this.lbSecurityGroupName.isEmpty() + || this.lbSecurityGroupName.length() > Constants.SECURITY_GROUP_NAME_MAX_LENGTH) { + throw new LoadBalancerExtensionException( + "Invalid load balancer security group name."); + } - // Read the SSL certificate Id. This is mandatory if only we are using HTTPS as the front end protocol. - // http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/using-elb-listenerconfig-quickref.html - this.sslCertificateId = properties - .getProperty(Constants.LOAD_BALANCER_SSL_CERTIFICATE_ID).trim(); + // Read the SSL certificate Id. This is mandatory if only we are using HTTPS as the front end protocol. + // http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/using-elb-listenerconfig-quickref.html + this.sslCertificateId = properties + .getProperty(Constants.LOAD_BALANCER_SSL_CERTIFICATE_ID).trim(); - // Cookie name for application level stickiness - this.appStickySessionCookie = properties.getProperty(Constants.APP_STICKY_SESSION_COOKIE_NAME).trim(); - - this.allowedCidrIpForLBSecurityGroup = properties - .getProperty(Constants.ALLOWED_CIDR_IP_KEY); - - if (this.allowedCidrIpForLBSecurityGroup.isEmpty()) { - throw new LoadBalancerExtensionException( - "Invalid allowed CIDR IP."); - } + // Cookie name for application level stickiness + this.appStickySessionCookie = properties.getProperty(Constants.APP_STICKY_SESSION_COOKIE_NAME).trim(); - String allowedProtocols = properties - .getProperty(Constants.ALLOWED_PROTOCOLS); + this.allowedCidrIpForLBSecurityGroup = properties + .getProperty(Constants.ALLOWED_CIDR_IP_KEY); - if (allowedProtocols.isEmpty()) { - throw new LoadBalancerExtensionException( - "Please specify at least one Internet protocol."); - } + if (this.allowedCidrIpForLBSecurityGroup.isEmpty()) { + throw new LoadBalancerExtensionException( + "Invalid allowed CIDR IP."); + } - String[] protocols = allowedProtocols.split(","); + String allowedProtocols = properties + .getProperty(Constants.ALLOWED_PROTOCOLS); - this.allowedProtocolsForLBSecurityGroup = new ArrayList<String>(); + if (allowedProtocols.isEmpty()) { + throw new LoadBalancerExtensionException( + "Please specify at least one Internet protocol."); + } - for (String protocol : protocols) { - this.allowedProtocolsForLBSecurityGroup.add(protocol); - } + String[] protocols = allowedProtocols.split(","); - String interval = properties - .getProperty(Constants.STATISTICS_INTERVAL); + this.allowedProtocolsForLBSecurityGroup = new ArrayList<String>(); - if (interval == null || interval.isEmpty()) { - this.statisticsInterval = Constants.STATISTICS_INTERVAL_MULTIPLE_OF; - } else { - try { - this.statisticsInterval = Integer.parseInt(interval); + for (String protocol : protocols) { + this.allowedProtocolsForLBSecurityGroup.add(protocol); + } - if (this.statisticsInterval - % Constants.STATISTICS_INTERVAL_MULTIPLE_OF != 0) { - this.statisticsInterval = Constants.STATISTICS_INTERVAL_MULTIPLE_OF; - } - } catch (NumberFormatException e) { - log.warn("Invalid statistics interval. Setting it to 15."); - this.statisticsInterval = 15; - } - } + String interval = properties + .getProperty(Constants.STATISTICS_INTERVAL); - this.lbSecurityGroupDescription = Constants.LOAD_BALANCER_SECURITY_GROUP_DESCRIPTION; + if (interval == null || interval.isEmpty()) { + this.statisticsInterval = Constants.STATISTICS_INTERVAL_MULTIPLE_OF; + } else { + try { + this.statisticsInterval = Integer.parseInt(interval); - regionToSecurityGroupIdMap = new ConcurrentHashMap<String, String>(); + if (this.statisticsInterval + % Constants.STATISTICS_INTERVAL_MULTIPLE_OF != 0) { + this.statisticsInterval = Constants.STATISTICS_INTERVAL_MULTIPLE_OF; + } + } catch (NumberFormatException e) { + log.warn("Invalid statistics interval. Setting it to 15."); + this.statisticsInterval = 15; + } + } - awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey); - clientConfiguration = new ClientConfiguration(); + this.lbSecurityGroupDescription = Constants.LOAD_BALANCER_SECURITY_GROUP_DESCRIPTION; - elbClient = new AmazonElasticLoadBalancingClient(awsCredentials, - clientConfiguration); + regionToSecurityGroupIdMap = new ConcurrentHashMap<String, String>(); - ec2Client = new AmazonEC2Client(awsCredentials, clientConfiguration); - - cloudWatchClient = new AmazonCloudWatchClient(awsCredentials, - clientConfiguration); - - } catch (IOException e) { - log.error("Error reading aws configuration file."); - throw new LoadBalancerExtensionException( - "Error reading aws configuration file.", e); - } finally { - try { - inputStream.close(); - } catch (Exception e) { - log.warn("Failed to close input stream to aws configuration file."); - } - } - } - - public int getStatisticsInterval() { - return statisticsInterval; - } - - public int getNextLBSequence() { - return lbSequence.getAndIncrement(); - } - - public String getLbSecurityGroupName() { - return lbSecurityGroupName; - } - - public List<String> getAllowedProtocolsForLBSecurityGroup() { - return allowedProtocolsForLBSecurityGroup; - } - - /** - * Creates a load balancer and returns its DNS name. Useful when a new - * cluster is added. - * - * @param name - * of the load balancer to be created - * @param listeners - * to be attached to the load balancer - * @param region - * in which the load balancer needs to be created - * @return DNS name of newly created load balancer - * @throws LoadBalancerExtensionException - */ - public String createLoadBalancer(String name, List<Listener> listeners, - String region, String availabilityZone, boolean inVPC) throws LoadBalancerExtensionException { - - log.info("Creating load balancer " + name); - - CreateLoadBalancerRequest createLoadBalancerRequest = new CreateLoadBalancerRequest( - name); - - createLoadBalancerRequest.setListeners(listeners); - - // don't need this now since we are anyway updating zone according to the member + awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey); + clientConfiguration = new ClientConfiguration(); + + elbClient = new AmazonElasticLoadBalancingClient(awsCredentials, + clientConfiguration); + + ec2Client = new AmazonEC2Client(awsCredentials, clientConfiguration); + + cloudWatchClient = new AmazonCloudWatchClient(awsCredentials, + clientConfiguration); + + } catch (IOException e) { + log.error("Error reading aws configuration file."); + throw new LoadBalancerExtensionException( + "Error reading aws configuration file.", e); + } finally { + try { + inputStream.close(); + } catch (Exception e) { + log.warn("Failed to close input stream to aws configuration file."); + } + } + } + + public int getStatisticsInterval() { + return statisticsInterval; + } + + public int getNextLBSequence() { + return lbSequence.getAndIncrement(); + } + + public String getLbSecurityGroupName() { + return lbSecurityGroupName; + } + + public List<String> getAllowedProtocolsForLBSecurityGroup() { + return allowedProtocolsForLBSecurityGroup; + } + + /** + * Creates a load balancer and returns its DNS name. Useful when a new + * cluster is added. + * + * @param name of the load balancer to be created + * @param listeners to be attached to the load balancer + * @param region in which the load balancer needs to be created + * @return DNS name of newly created load balancer + * @throws LoadBalancerExtensionException + */ + public String createLoadBalancer(String name, List<Listener> listeners, + String region, String availabilityZone, boolean inVPC) throws LoadBalancerExtensionException { + + log.info("Creating load balancer " + name); + + CreateLoadBalancerRequest createLoadBalancerRequest = new CreateLoadBalancerRequest( + name); + + createLoadBalancerRequest.setListeners(listeners); + + // don't need this now since we are anyway updating zone according to the member // Set<String> availabilityZones = new HashSet<String>(); // availabilityZones.add(getAvailabilityZoneFromRegion(region)); // // createLoadBalancerRequest.setAvailabilityZones(availabilityZones); - Set<String> availabilityZones = new HashSet<String>(); - availabilityZones.add(availabilityZone); - createLoadBalancerRequest.setAvailabilityZones(availabilityZones); - - try { - if (inVPC) { - String securityGroupId = getSecurityGroupIdForRegion(region); - List<String> securityGroups = new ArrayList<String>(); - securityGroups.add(securityGroupId); - - createLoadBalancerRequest.setSecurityGroups(securityGroups); - } - - elbClient.setEndpoint(String.format( - Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - CreateLoadBalancerResult clbResult = elbClient - .createLoadBalancer(createLoadBalancerRequest); - - return clbResult.getDNSName(); - - } catch (AmazonClientException e) { - String errorMsg = "Could not create load balancer " + name; - log.error(errorMsg, e); - throw new LoadBalancerExtensionException(errorMsg, e); - } - } - - /** - * Deletes the load balancer with the name provided. Useful when a cluster, - * with which this load balancer was associated, is removed. - * - * @param loadBalancerName - * to be deleted - * @param region - * of the laod balancer - */ - public void deleteLoadBalancer(String loadBalancerName, String region) { - - log.info("Deleting load balancer " + loadBalancerName); - - DeleteLoadBalancerRequest deleteLoadBalancerRequest = new DeleteLoadBalancerRequest(); - deleteLoadBalancerRequest.setLoadBalancerName(loadBalancerName); - - try { - elbClient.setEndpoint(String.format( - Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - elbClient.deleteLoadBalancer(deleteLoadBalancerRequest); - log.info("Deleted load balancer " + loadBalancerName); - } catch (AmazonClientException e) { - log.error("Could not delete load balancer : " + loadBalancerName, e); - } - } - - /** - * Attaches provided instances to the load balancer. Useful when new - * instances get added to the cluster with which this load balancer is - * associated. - * - * @param loadBalancerName - * @param instances - * to attached to the load balancer - * @param region - * of the load balancer - */ - public void registerInstancesToLoadBalancer(String loadBalancerName, - List<Instance> instances, String region) { - - log.info("Registering following instance(s) to load balancer " - + loadBalancerName); - - for (Instance instance : instances) { - log.info(instance.getInstanceId()); - } - - RegisterInstancesWithLoadBalancerRequest registerInstancesWithLoadBalancerRequest = new RegisterInstancesWithLoadBalancerRequest( - loadBalancerName, instances); - - try { - elbClient.setEndpoint(String.format( - Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - elbClient - .registerInstancesWithLoadBalancer(registerInstancesWithLoadBalancerRequest); - - } catch (AmazonClientException e) { - log.error("Could not register instances to load balancer " - + loadBalancerName, e); - } - } - - /** - * Detaches provided instances from the load balancer, associated with some - * cluster. Useful when instances are removed from the cluster with which - * this load balancer is associated. - * - * @param loadBalancerName - * @param instances - * to be de-registered from load balancer - * @param region - * of the load balancer - */ - public void deregisterInstancesFromLoadBalancer(String loadBalancerName, List<Instance> instances, String region) { - - log.info("De-registering following instance(s) from load balancer " - + loadBalancerName); - - for (Instance instance : instances) { - log.info(instance.getInstanceId()); - } - - DeregisterInstancesFromLoadBalancerRequest deregisterInstancesFromLoadBalancerRequest = new DeregisterInstancesFromLoadBalancerRequest( - loadBalancerName, instances); - - try { - elbClient.setEndpoint(String.format( - Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - elbClient - .deregisterInstancesFromLoadBalancer(deregisterInstancesFromLoadBalancerRequest); - - } catch (AmazonClientException e) { - log.error("Could not de-register instances from load balancer " - + loadBalancerName, e); - } - } - - /** - * Returns description of the load balancer which is helpful in determining - * instances, listeners associated with load balancer - * - * @param loadBalancerName - * @param region - * of the load balancer - * @return description of the load balancer - */ - public LoadBalancerDescription getLoadBalancerDescription( - String loadBalancerName, String region) { - - List<String> loadBalancers = new ArrayList<String>(); - loadBalancers.add(loadBalancerName); - - DescribeLoadBalancersRequest describeLoadBalancersRequest = new DescribeLoadBalancersRequest( - loadBalancers); - - try { - elbClient.setEndpoint(String.format( - Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - DescribeLoadBalancersResult result = elbClient - .describeLoadBalancers(describeLoadBalancersRequest); - - if (result.getLoadBalancerDescriptions() != null - && result.getLoadBalancerDescriptions().size() > 0) - return result.getLoadBalancerDescriptions().get(0); - } catch (AmazonClientException e) { - log.error("Could not find description of load balancer " - + loadBalancerName, e); - } - - return null; - } - - /** - * Returns instances attached to the load balancer. Useful when deciding if - * all attached instances are required or some should be detached. - * - * @param loadBalancerName - * @param region - * @return list of instances attached - */ - public List<Instance> getAttachedInstances(String loadBalancerName, - String region) { - try { - LoadBalancerDescription lbDescription = getLoadBalancerDescription( - loadBalancerName, region); - - if (lbDescription == null) { - log.warn("Could not find description of load balancer " - + loadBalancerName); - return null; - } - - return lbDescription.getInstances(); - - } catch (AmazonClientException e) { - log.error("Could not find instances attached load balancer " - + loadBalancerName, e); - } - - return null; - } - - /** - * Returns all the listeners attached to the load balancer. Useful while - * deciding if all the listeners are necessary or some should be removed. - * - * @param loadBalancerName - * @param region - * @return list of instances attached to load balancer - */ - public List<Listener> getAttachedListeners(String loadBalancerName, - String region) { - try { - LoadBalancerDescription lbDescription = getLoadBalancerDescription( - loadBalancerName, region); - - if (lbDescription == null) { - log.warn("Could not find description of load balancer " - + loadBalancerName); - return null; - } - - List<Listener> listeners = new ArrayList<Listener>(); - - List<ListenerDescription> listenerDescriptions = lbDescription - .getListenerDescriptions(); - - for (ListenerDescription listenerDescription : listenerDescriptions) { - listeners.add(listenerDescription.getListener()); - } - - return listeners; - - } catch (AmazonClientException e) { - log.error("Could not find description of load balancer " - + loadBalancerName); - return null; - } - - } - - /** - * Checks if the security group is already present in the given region. If - * yes, then returns its group id. If not, present the returns null. - * - * @param groupName - * to be checked for presence. - * @param region - * @return id of the security group - */ - public String getSecurityGroupId(String groupName, String region) { - if (groupName == null || groupName.isEmpty()) { - return null; - } - - DescribeSecurityGroupsRequest describeSecurityGroupsRequest = new DescribeSecurityGroupsRequest(); - - List<String> groupNames = new ArrayList<String>(); - groupNames.add(groupName); - - describeSecurityGroupsRequest.setGroupNames(groupNames); - - try { - ec2Client.setEndpoint(String.format( - Constants.EC2_ENDPOINT_URL_FORMAT, region)); - - DescribeSecurityGroupsResult describeSecurityGroupsResult = ec2Client - .describeSecurityGroups(describeSecurityGroupsRequest); - - List<SecurityGroup> securityGroups = describeSecurityGroupsResult - .getSecurityGroups(); - - if (securityGroups != null && securityGroups.size() > 0) { - return securityGroups.get(0).getGroupId(); - } - } catch (AmazonClientException e) { - log.debug("Could not describe security groups.", e); - } - - return null; - } - - /** - * Creates security group with the given name in the given region - * - * @param groupName - * to be created - * @param description - * @param region - * in which the security group to be created - * @return Id of the security group created - * @throws LoadBalancerExtensionException - */ - public String createSecurityGroup(String groupName, String description, - String region) throws LoadBalancerExtensionException { - if (groupName == null || groupName.isEmpty()) { - throw new LoadBalancerExtensionException( - "Invalid Security Group Name."); - } - - CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest(); - createSecurityGroupRequest.setGroupName(groupName); - createSecurityGroupRequest.setDescription(description); - - try { - ec2Client.setEndpoint(String.format( - Constants.EC2_ENDPOINT_URL_FORMAT, region)); - - CreateSecurityGroupResult createSecurityGroupResult = ec2Client - .createSecurityGroup(createSecurityGroupRequest); - - return createSecurityGroupResult.getGroupId(); - - } catch (AmazonClientException e) { - log.error("Could not create security group.", e); - throw new LoadBalancerExtensionException( - "Could not create security group.", e); - } - - } - - /** - * Adds inbound rule to the security group which allows users to access load - * balancer at specified port and using the specified protocol. Port - * specified should be a proxy port mentioned in the port mappings of the - * cartridge. - * - * @param groupId - * to which this rule to be added - * @param region - * of the security group - * @param protocol - * with which load balancer can be accessed - * @param port - * at which load balancer can be accessed - * @throws LoadBalancerExtensionException - */ - public void addInboundRuleToSecurityGroup(String groupId, String region, - String protocol, int port) throws LoadBalancerExtensionException { - if (groupId == null || groupId.isEmpty()) { - throw new LoadBalancerExtensionException( - "Invalid security group Id for addInboundRuleToSecurityGroup."); - } - - boolean ruleAlreadyPresent = false; - - DescribeSecurityGroupsRequest describeSecurityGroupsRequest = new DescribeSecurityGroupsRequest(); - - List<String> groupIds = new ArrayList<String>(); - groupIds.add(groupId); - - describeSecurityGroupsRequest.setGroupIds(groupIds); - - SecurityGroup secirutyGroup = null; - - try { - ec2Client.setEndpoint(String.format( - Constants.EC2_ENDPOINT_URL_FORMAT, region)); - - DescribeSecurityGroupsResult describeSecurityGroupsResult = ec2Client - .describeSecurityGroups(describeSecurityGroupsRequest); - - List<SecurityGroup> securityGroups = describeSecurityGroupsResult - .getSecurityGroups(); - - if (securityGroups != null && securityGroups.size() > 0) { - secirutyGroup = securityGroups.get(0); - } - } catch (AmazonClientException e) { - log.error("Could not describe security groups.", e); - } - - if (secirutyGroup != null) { - List<IpPermission> existingPermissions = secirutyGroup - .getIpPermissions(); - - IpPermission neededPermission = new IpPermission(); - neededPermission.setFromPort(port); - neededPermission.setToPort(port); - neededPermission.setIpProtocol(protocol); - - Collection<String> ipRanges = new HashSet<String>(); - ipRanges.add(this.allowedCidrIpForLBSecurityGroup); - - neededPermission.setIpRanges(ipRanges); - - if (existingPermissions.contains(neededPermission)) { - ruleAlreadyPresent = true; - } - } - - if (!ruleAlreadyPresent) { - AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest(); - authorizeSecurityGroupIngressRequest.setGroupId(groupId); - authorizeSecurityGroupIngressRequest - .setCidrIp(this.allowedCidrIpForLBSecurityGroup); - authorizeSecurityGroupIngressRequest.setFromPort(port); - authorizeSecurityGroupIngressRequest.setToPort(port); - authorizeSecurityGroupIngressRequest.setIpProtocol(protocol); - - try { - ec2Client.setEndpoint(String.format( - Constants.EC2_ENDPOINT_URL_FORMAT, region)); - - ec2Client - .authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest); - - } catch (AmazonClientException e) { - throw new LoadBalancerExtensionException( - "Could not add inbound rule to security group " - + groupId + ".", e); - } - } - } - - /** - * Returns the security group id for the given region if it is already - * present. If it is not already present then creates a new security group - * in that region. - * - * @param region - * @return Id of the security group - * @throws LoadBalancerExtensionException - */ - public String getSecurityGroupIdForRegion(String region) - throws LoadBalancerExtensionException { - if (region == null) - return null; - - if (this.regionToSecurityGroupIdMap.contains(region)) { - return this.regionToSecurityGroupIdMap.get(region); - } else { - // Get the the security group id if it is already present. - String securityGroupId = getSecurityGroupId( - this.lbSecurityGroupName, region); - - if (securityGroupId == null) { - securityGroupId = createSecurityGroup(this.lbSecurityGroupName, - this.lbSecurityGroupDescription, region); - } - - this.regionToSecurityGroupIdMap.put(region, securityGroupId); - - return securityGroupId; - } - } - - /** - * Retrieves the total number of requests that were made to the load - * balancer during the given time interval in the past - * - * @param loadBalancerName - * @param region - * @param timeInterval - * in seconds which must be multiple of 60 - * @return number of requests made - */ - public int getRequestCount(String loadBalancerName, String region, - int timeInterval) { - int count = 0; - - try { - GetMetricStatisticsRequest request = new GetMetricStatisticsRequest(); - request.setMetricName(Constants.REQUEST_COUNT_METRIC_NAME); - request.setNamespace(Constants.CLOUD_WATCH_NAMESPACE_NAME); - - Date currentTime = new DateTime(DateTimeZone.UTC).toDate(); - Date pastTime = new DateTime(DateTimeZone.UTC).minusSeconds( - timeInterval).toDate(); - - request.setStartTime(pastTime); - request.setEndTime(currentTime); - - request.setPeriod(timeInterval); - - HashSet<String> statistics = new HashSet<String>(); - statistics.add(Constants.SUM_STATISTICS_NAME); - request.setStatistics(statistics); - - HashSet<Dimension> dimensions = new HashSet<Dimension>(); - Dimension loadBalancerDimension = new Dimension(); - loadBalancerDimension - .setName(Constants.LOAD_BALANCER_DIMENTION_NAME); - loadBalancerDimension.setValue(loadBalancerName); - dimensions.add(loadBalancerDimension); - request.setDimensions(dimensions); - - cloudWatchClient.setEndpoint(String.format( - Constants.CLOUD_WATCH_ENDPOINT_URL_FORMAT, region)); - - GetMetricStatisticsResult result = cloudWatchClient - .getMetricStatistics(request); - - List<Datapoint> dataPoints = result.getDatapoints(); - - if (dataPoints != null && dataPoints.size() > 0) { - count = dataPoints.get(0).getSum().intValue(); - } - - } catch (AmazonClientException e) { - log.error( - "Could not get request count statistics of load balancer " - + loadBalancerName, e); - } - - return count; - } - - /** - * Retrieves total number of responses generated by all instances attached - * to the load balancer during the time interval in the past. - * - * @param loadBalancerName - * @param region - * @param timeInterval - * in seconds which must be multiple of 60 - * @return number of responses generated - */ - public int getAllResponsesCount(String loadBalancerName, String region, - int timeInterval) { - int total = 0; - - Date currentTime = new DateTime(DateTimeZone.UTC).toDate(); - Date pastTime = new DateTime(DateTimeZone.UTC).minusSeconds( - timeInterval).toDate(); - - total += getResponseCountForMetric(loadBalancerName, region, - Constants.HTTP_RESPONSE_2XX, pastTime, currentTime, - timeInterval); - total += getResponseCountForMetric(loadBalancerName, region, - Constants.HTTP_RESPONSE_3XX, pastTime, currentTime, - timeInterval); - total += getResponseCountForMetric(loadBalancerName, region, - Constants.HTTP_RESPONSE_4XX, pastTime, currentTime, - timeInterval); - total += getResponseCountForMetric(loadBalancerName, region, - Constants.HTTP_RESPONSE_5XX, pastTime, currentTime, - timeInterval); - - return total; - } - - /** - * Retrieves the number of responses generated for a particular response - * code like 2XX, 3XX, 4XX, 5XX - * - * @param loadBalancerName - * @param region - * @param metricName - * which is one among HTTPCode_Backend_2XX or - * HTTPCode_Backend_3XX or HTTPCode_Backend_4XX or - * HTTPCode_Backend_5XX - * @param startTime - * of the window to be scanned - * @param endTime - * of the window to be scanned - * @param timeInterval - * in seconds - * @return number for response for this metric - */ - public int getResponseCountForMetric(String loadBalancerName, - String region, String metricName, Date startTime, Date endTime, - int timeInterval) { - int count = 0; - - try { - GetMetricStatisticsRequest request = new GetMetricStatisticsRequest(); - request.setMetricName(metricName); - request.setNamespace(Constants.CLOUD_WATCH_NAMESPACE_NAME); - - request.setStartTime(startTime); - request.setEndTime(endTime); - - request.setPeriod(timeInterval); - - HashSet<String> statistics = new HashSet<String>(); - statistics.add(Constants.SUM_STATISTICS_NAME); - request.setStatistics(statistics); - - HashSet<Dimension> dimensions = new HashSet<Dimension>(); - Dimension loadBalancerDimension = new Dimension(); - loadBalancerDimension - .setName(Constants.LOAD_BALANCER_DIMENTION_NAME); - loadBalancerDimension.setValue(loadBalancerName); - dimensions.add(loadBalancerDimension); - request.setDimensions(dimensions); - - cloudWatchClient.setEndpoint(String.format( - Constants.CLOUD_WATCH_ENDPOINT_URL_FORMAT, region)); - - GetMetricStatisticsResult result = cloudWatchClient - .getMetricStatistics(request); - - List<Datapoint> dataPoints = result.getDatapoints(); - - if (dataPoints != null && dataPoints.size() > 0) { - count = dataPoints.get(0).getSum().intValue(); - } - - } catch (AmazonClientException e) { - log.error("Could not get the statistics for metric " + metricName - + " of load balancer " + loadBalancerName, e); - } - - return count; - } - - /** - * Returns the Listeners required for the service. Listeners are derived - * from the proxy port, port and protocol values of the service. - * - * @param service - * @return list of listeners required for the service - */ - public List<Listener> getRequiredListeners(Member member) throws LoadBalancerExtensionException { - List<Listener> listeners = new ArrayList<Listener>(); - - Collection<Port> ports = member.getPorts(); - - for (Port port : ports) { - int instancePort = port.getValue(); - int proxyPort = port.getProxy(); - String protocol = port.getProtocol().toUpperCase(); - String instanceProtocol = protocol; - - Listener listener = new Listener(protocol, proxyPort, instancePort); - listener.setInstanceProtocol(instanceProtocol); - if ("HTTPS".equalsIgnoreCase(protocol) || "SSL".equalsIgnoreCase(protocol)) { - // if the SSL certificate is not configured in the aws.properties file, can't continue - if (getSslCertificateId() == null || getSslCertificateId().isEmpty()) { - String errorMsg = "Required property " + Constants.LOAD_BALANCER_SSL_CERTIFICATE_ID + " not provided in configuration"; - log.error(errorMsg); - throw new LoadBalancerExtensionException(errorMsg); - } - // TODO: make debug? - if (log.isInfoEnabled()) { - log.info("Listener protocol = " + protocol + ", hence setting the SSL Certificate Id: " + getSslCertificateId()); - } - listener.setSSLCertificateId(getSslCertificateId()); - } - - listeners.add(listener); - } - - return listeners; - } - - /** - * Constructs name of the load balancer to be associated with the cluster - * - * @param clusterId - * @return name of the load balancer - * @throws LoadBalancerExtensionException - */ - public String generateLoadBalancerName(String serviceName) - throws LoadBalancerExtensionException { - String name = null; - - //name = lbPrefix + getNextLBSequence(); - name = lbPrefix + serviceName; - - if (name.length() > Constants.LOAD_BALANCER_NAME_MAX_LENGTH) - throw new LoadBalancerExtensionException( - "Load balanacer name length (32 characters) exceeded"); - - return name; - } - - /** - * Extract instance id in IaaS side from member instance name - * - * @param memberInstanceName - * @return instance id in IaaS - */ - public String getAWSInstanceName(String memberInstanceName) { - if (memberInstanceName.contains("/")) { - return memberInstanceName - .substring(memberInstanceName.indexOf("/") + 1); - } else { - return memberInstanceName; - } - } - - /** - * Extract IaaS region from member instance name - * - * @param memberInstanceName - * @return IaaS region to which member belongs - */ - public String getAWSRegion(String memberInstanceName) { - if (memberInstanceName.contains("/")) { - return memberInstanceName.substring(0, - memberInstanceName.indexOf("/")); - } else { - return null; - } - } - - /** - * Get availability zone from region - * - * @param region - * @return Availability zone of IaaS - */ - public String getAvailabilityZoneFromRegion(String region) { - if (region != null) { - return region + "a"; - } else - return null; - } - - public CreateAppCookieStickinessPolicyResult createStickySessionPolicy(String lbName, String cookieName, String policyName, String region) { - - elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - CreateAppCookieStickinessPolicyRequest stickinessPolicyReq = new CreateAppCookieStickinessPolicyRequest(). - withLoadBalancerName(lbName).withCookieName(cookieName).withPolicyName(policyName); - - CreateAppCookieStickinessPolicyResult stickinessPolicyResult = null; - try { - stickinessPolicyResult = elbClient.createAppCookieStickinessPolicy(stickinessPolicyReq); - - } catch (AmazonServiceException e) { - log.error(e.getMessage(), e); - - } catch (AmazonClientException e) { - log.error(e.getMessage(), e); - } - - if (stickinessPolicyResult == null) { - log.error("Error in creating Application Stickiness policy for for cookie name: " + cookieName + ", policy: " + policyName); - } else { - log.info("Enabled Application stickiness using: " + cookieName + ", policy: " + policyName + " for LB " + lbName); - } - - return stickinessPolicyResult; - } - - public void applyPolicyToLBListenerPorts(Collection<Port> ports, String loadBalancerName, String policyName, String region) { - - for (Port port : ports) { - if ("HTTP".equalsIgnoreCase(port.getProtocol()) || "HTTPS".equalsIgnoreCase(port.getProtocol())) { - applyPolicyToListener(loadBalancerName, port.getProxy(), policyName, region); - // hack to stop too many calls to AWS API :( - try { - Thread.sleep(2000); - } catch (InterruptedException e) {} - } - } - } - - private void applyPolicyToListener (String loadBalancerName, int listenerPort, String policyName, String region) { - - SetLoadBalancerPoliciesOfListenerRequest loadBalancerPoliciesOfListenerReq = new SetLoadBalancerPoliciesOfListenerRequest(). - withLoadBalancerName(loadBalancerName).withLoadBalancerPort(listenerPort).withPolicyNames(policyName); - - elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - SetLoadBalancerPoliciesOfListenerResult setLBPoliciesOfListenerRes = null; - try { - setLBPoliciesOfListenerRes = elbClient.setLoadBalancerPoliciesOfListener(loadBalancerPoliciesOfListenerReq); - - } catch (AmazonServiceException e) { - log.error(e.getMessage(), e); - - } catch (AmazonClientException e) { - log.error(e.getMessage(), e); - } - - if (setLBPoliciesOfListenerRes == null) { - log.error("Unable to apply policy " + policyName + " for Listener port: " + listenerPort + " for LB: " + loadBalancerName); - } else { - log.info("Successfully applied policy " + policyName + " for Listener port: " + listenerPort + " for LB: " + loadBalancerName); - } - } - - public List<String> getAvailabilityZonesFromRegion (final String region) { - - DescribeAvailabilityZonesRequest availabilityZonesReq = new DescribeAvailabilityZonesRequest(); - List<Filter> availabilityZoneFilters = new ArrayList<Filter>(); - availabilityZoneFilters.add(new Filter("region-name", new ArrayList<String>() {{ - add(region); - }})); - availabilityZoneFilters.add(new Filter("state", new ArrayList<String>() {{ - add("available"); - }})); - - ec2Client.setEndpoint(String.format(Constants.EC2_ENDPOINT_URL_FORMAT, region)); - DescribeAvailabilityZonesResult availabilityZonesRes = null; - - try { - availabilityZonesRes = ec2Client.describeAvailabilityZones(availabilityZonesReq); - - } catch (AmazonServiceException e) { - log.error(e.getMessage(), e); - - } catch (AmazonClientException e) { - log.error(e.getMessage(), e); - } - - List<String> availabilityZones = null; - - if (availabilityZonesRes != null) { - availabilityZones = new ArrayList<>(); - for (AvailabilityZone zone : availabilityZonesRes.getAvailabilityZones()) { - availabilityZones.add(zone.getZoneName()); - } - } else { - log.error("Unable to retrieve the active availability zones for region " + region); - } - - return availabilityZones; - } - - public void addAvailabilityZonesForLoadBalancer (String loadBalancerName, List<String> availabilityZones, String region) { - - EnableAvailabilityZonesForLoadBalancerRequest enableAvailabilityZonesReq = new EnableAvailabilityZonesForLoadBalancerRequest() - .withLoadBalancerName(loadBalancerName).withAvailabilityZones(availabilityZones); - - elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - EnableAvailabilityZonesForLoadBalancerResult enableAvailabilityZonesRes = null; - - try { - enableAvailabilityZonesRes = elbClient.enableAvailabilityZonesForLoadBalancer(enableAvailabilityZonesReq); - - } catch (AmazonServiceException e) { - log.error(e.getMessage(), e); - - } catch (AmazonClientException e) { - log.error(e.getMessage(), e); - } - - if (enableAvailabilityZonesRes != null) { - log.info("Availability zones successfully added to LB " + loadBalancerName + ". Updated zone list: "); - for (String zone : enableAvailabilityZonesRes.getAvailabilityZones()) { - log.info(zone); - } - } else { - log.error("Updating availability zones failed for LB " + loadBalancerName); - } - } - - public void modifyLBAttributes (String loadBalancerName, String region, boolean enableCrossZoneLbing, boolean enableConnDraining) { - - if (!enableCrossZoneLbing && !enableConnDraining) { - log.info("No attributes specified to modify in the LB " + loadBalancerName); - return; - } + Set<String> availabilityZones = new HashSet<String>(); + availabilityZones.add(availabilityZone); + createLoadBalancerRequest.setAvailabilityZones(availabilityZones); + + try { + if (inVPC) { + String securityGroupId = getSecurityGroupIdForRegion(region); + List<String> securityGroups = new ArrayList<String>(); + securityGroups.add(securityGroupId); + + createLoadBalancerRequest.setSecurityGroups(securityGroups); + } + + elbClient.setEndpoint(String.format( + Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + CreateLoadBalancerResult clbResult = elbClient + .createLoadBalancer(createLoadBalancerRequest); + + return clbResult.getDNSName(); + + } catch (AmazonClientException e) { + String errorMsg = "Could not create load balancer " + name; + log.error(errorMsg, e); + throw new LoadBalancerExtensionException(errorMsg, e); + } + } + + /** + * Deletes the load balancer with the name provided. Useful when a cluster, + * with which this load balancer was associated, is removed. + * + * @param loadBalancerName to be deleted + * @param region of the laod balancer + */ + public void deleteLoadBalancer(String loadBalancerName, String region) { + + log.info("Deleting load balancer " + loadBalancerName); + + DeleteLoadBalancerRequest deleteLoadBalancerRequest = new DeleteLoadBalancerRequest(); + deleteLoadBalancerRequest.setLoadBalancerName(loadBalancerName); + + try { + elbClient.setEndpoint(String.format( + Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + elbClient.deleteLoadBalancer(deleteLoadBalancerRequest); + log.info("Deleted load balancer " + loadBalancerName); + } catch (AmazonClientException e) { + log.error("Could not delete load balancer : " + loadBalancerName, e); + } + } + + /** + * Attaches provided instances to the load balancer. Useful when new + * instances get added to the cluster with which this load balancer is + * associated. + * + * @param loadBalancerName + * @param instances to attached to the load balancer + * @param region of the load balancer + */ + public void registerInstancesToLoadBalancer(String loadBalancerName, + List<Instance> instances, String region) { + + log.info("Registering following instance(s) to load balancer " + + loadBalancerName); + + for (Instance instance : instances) { + log.info(instance.getInstanceId()); + } + + RegisterInstancesWithLoadBalancerRequest registerInstancesWithLoadBalancerRequest = new RegisterInstancesWithLoadBalancerRequest( + loadBalancerName, instances); + + try { + elbClient.setEndpoint(String.format( + Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + elbClient + .registerInstancesWithLoadBalancer(registerInstancesWithLoadBalancerRequest); + + } catch (AmazonClientException e) { + log.error("Could not register instances to load balancer " + + loadBalancerName, e); + } + } + + /** + * Detaches provided instances from the load balancer, associated with some + * cluster. Useful when instances are removed from the cluster with which + * this load balancer is associated. + * + * @param loadBalancerName + * @param instances to be de-registered from load balancer + * @param region of the load balancer + */ + public void deregisterInstancesFromLoadBalancer(String loadBalancerName, List<Instance> instances, String region) { + + log.info("De-registering following instance(s) from load balancer " + + loadBalancerName); + + for (Instance instance : instances) { + log.info(instance.getInstanceId()); + } + + DeregisterInstancesFromLoadBalancerRequest deregisterInstancesFromLoadBalancerRequest = new DeregisterInstancesFromLoadBalancerRequest( + loadBalancerName, instances); + + try { + elbClient.setEndpoint(String.format( + Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + elbClient + .deregisterInstancesFromLoadBalancer(deregisterInstancesFromLoadBalancerRequest); + + } catch (AmazonClientException e) { + log.error("Could not de-register instances from load balancer " + + loadBalancerName, e); + } + } + + /** + * Returns description of the load balancer which is helpful in determining + * instances, listeners associated with load balancer + * + * @param loadBalancerName + * @param region of the load balancer + * @return description of the load balancer + */ + public LoadBalancerDescription getLoadBalancerDescription( + String loadBalancerName, String region) { + + List<String> loadBalancers = new ArrayList<String>(); + loadBalancers.add(loadBalancerName); + + DescribeLoadBalancersRequest describeLoadBalancersRequest = new DescribeLoadBalancersRequest( + loadBalancers); + + try { + elbClient.setEndpoint(String.format( + Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + DescribeLoadBalancersResult result = elbClient + .describeLoadBalancers(describeLoadBalancersRequest); + + if (result.getLoadBalancerDescriptions() != null + && result.getLoadBalancerDescriptions().size() > 0) + return result.getLoadBalancerDescriptions().get(0); + } catch (AmazonClientException e) { + log.error("Could not find description of load balancer " + + loadBalancerName, e); + } + + return null; + } + + /** + * Returns instances attached to the load balancer. Useful when deciding if + * all attached instances are required or some should be detached. + * + * @param loadBalancerName + * @param region + * @return list of instances attached + */ + public List<Instance> getAttachedInstances(String loadBalancerName, + String region) { + try { + LoadBalancerDescription lbDescription = getLoadBalancerDescription( + loadBalancerName, region); + + if (lbDescription == null) { + log.warn("Could not find description of load balancer " + + loadBalancerName); + return null; + } + + return lbDescription.getInstances(); + + } catch (AmazonClientException e) { + log.error("Could not find instances attached load balancer " + + loadBalancerName, e); + } + + return null; + } + + /** + * Returns all the listeners attached to the load balancer. Useful while + * deciding if all the listeners are necessary or some should be removed. + * + * @param loadBalancerName + * @param region + * @return list of instances attached to load balancer + */ + public List<Listener> getAttachedListeners(String loadBalancerName, + String region) { + try { + LoadBalancerDescription lbDescription = getLoadBalancerDescription( + loadBalancerName, region); + + if (lbDescription == null) { + log.warn("Could not find description of load balancer " + + loadBalancerName); + return null; + } + + List<Listener> listeners = new ArrayList<Listener>(); + + List<ListenerDescription> listenerDescriptions = lbDescription + .getListenerDescriptions(); + + for (ListenerDescription listenerDescription : listenerDescriptions) { + listeners.add(listenerDescription.getListener()); + } + + return listeners; + + } catch (AmazonClientException e) { + log.error("Could not find description of load balancer " + + loadBalancerName); + return null; + } + + } + + /** + * Checks if the security group is already present in the given region. If + * yes, then returns its group id. If not, present the returns null. + * + * @param groupName to be checked for presence. + * @param region + * @return id of the security group + */ + public String getSecurityGroupId(String groupName, String region) { + if (groupName == null || groupName.isEmpty()) { + return null; + } + + DescribeSecurityGroupsRequest describeSecurityGroupsRequest = new DescribeSecurityGroupsRequest(); + + List<String> groupNames = new ArrayList<String>(); + groupNames.add(groupName); + + describeSecurityGroupsRequest.setGroupNames(groupNames); + + try { + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); + + DescribeSecurityGroupsResult describeSecurityGroupsResult = ec2Client + .describeSecurityGroups(describeSecurityGroupsRequest); + + List<SecurityGroup> securityGroups = describeSecurityGroupsResult + .getSecurityGroups(); + + if (securityGroups != null && securityGroups.size() > 0) { + return securityGroups.get(0).getGroupId(); + } + } catch (AmazonClientException e) { + log.debug("Could not describe security groups.", e); + } + + return null; + } + + /** + * Creates security group with the given name in the given region + * + * @param groupName to be created + * @param description + * @param region in which the security group to be created + * @return Id of the security group created + * @throws LoadBalancerExtensionException + */ + public String createSecurityGroup(String groupName, String description, + String region) throws LoadBalancerExtensionException { + if (groupName == null || groupName.isEmpty()) { + throw new LoadBalancerExtensionException( + "Invalid Security Group Name."); + } + + CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest(); + createSecurityGroupRequest.setGroupName(groupName); + createSecurityGroupRequest.setDescription(description); + + try { + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); + + CreateSecurityGroupResult createSecurityGroupResult = ec2Client + .createSecurityGroup(createSecurityGroupRequest); + + return createSecurityGroupResult.getGroupId(); + + } catch (AmazonClientException e) { + log.error("Could not create security group.", e); + throw new LoadBalancerExtensionException( + "Could not create security group.", e); + } + + } + + /** + * Adds inbound rule to the security group which allows users to access load + * balancer at specified port and using the specified protocol. Port + * specified should be a proxy port mentioned in the port mappings of the + * cartridge. + * + * @param groupId to which this rule to be added + * @param region of the security group + * @param protocol with which load balancer can be accessed + * @param port at which load balancer can be accessed + * @throws LoadBalancerExtensionException + */ + public void addInboundRuleToSecurityGroup(String groupId, String region, + String protocol, int port) throws LoadBalancerExtensionException { + if (groupId == null || groupId.isEmpty()) { + throw new LoadBalancerExtensionException( + "Invalid security group Id for addInboundRuleToSecurityGroup."); + } + + boolean ruleAlreadyPresent = false; + + DescribeSecurityGroupsRequest describeSecurityGroupsRequest = new DescribeSecurityGroupsRequest(); + + List<String> groupIds = new ArrayList<String>(); + groupIds.add(groupId); + + describeSecurityGroupsRequest.setGroupIds(groupIds); + + SecurityGroup secirutyGroup = null; + + try { + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); + + DescribeSecurityGroupsResult describeSecurityGroupsResult = ec2Client + .describeSecurityGroups(describeSecurityGroupsRequest); + + List<SecurityGroup> securityGroups = describeSecurityGroupsResult + .getSecurityGroups(); + + if (securityGroups != null && securityGroups.size() > 0) { + secirutyGroup = securityGroups.get(0); + } + } catch (AmazonClientException e) { + log.error("Could not describe security groups.", e); + } + + if (secirutyGroup != null) { + List<IpPermission> existingPermissions = secirutyGroup + .getIpPermissions(); + + IpPermission neededPermission = new IpPermission(); + neededPermission.setFromPort(port); + neededPermission.setToPort(port); + neededPermission.setIpProtocol(protocol); + + Collection<String> ipRanges = new HashSet<String>(); + ipRanges.add(this.allowedCidrIpForLBSecurityGroup); + + neededPermission.setIpRanges(ipRanges); + + if (existingPermissions.contains(neededPermission)) { + ruleAlreadyPresent = true; + } + } + + if (!ruleAlreadyPresent) { + AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest(); + authorizeSecurityGroupIngressRequest.setGroupId(groupId); + authorizeSecurityGroupIngressRequest + .setCidrIp(this.allowedCidrIpForLBSecurityGroup); + authorizeSecurityGroupIngressRequest.setFromPort(port); + authorizeSecurityGroupIngressRequest.setToPort(port); + authorizeSecurityGroupIngressRequest.setIpProtocol(protocol); + + try { + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); + + ec2Client + .authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest); + + } catch (AmazonClientException e) { + throw new LoadBalancerExtensionException( + "Could not add inbound rule to security group " + + groupId + ".", e); + } + } + } + + /** + * Returns the security group id for the given region if it is already + * present. If it is not already present then creates a new security group + * in that region. + * + * @param region + * @return Id of the security group + * @throws LoadBalancerExtensionException + */ + public String getSecurityGroupIdForRegion(String region) + throws LoadBalancerExtensionException { + if (region == null) + return null; + + if (this.regionToSecurityGroupIdMap.contains(region)) { + return this.regionToSecurityGroupIdMap.get(region); + } else { + // Get the the security group id if it is already present. + String securityGroupId = getSecurityGroupId( + this.lbSecurityGroupName, region); + + if (securityGroupId == null) { + securityGroupId = createSecurityGroup(this.lbSecurityGroupName, + this.lbSecurityGroupDescription, region); + } + + this.regionToSecurityGroupIdMap.put(region, securityGroupId); + + return securityGroupId; + } + } + + /** + * Retrieves the total number of requests that were made to the load + * balancer during the given time interval in the past + * + * @param loadBalancerName + * @param region + * @param timeInterval in seconds which must be multiple of 60 + * @return number of requests made + */ + public int getRequestCount(String loadBalancerName, String region, + int timeInterval) { + int count = 0; + + try { + GetMetricStatisticsRequest request = new GetMetricStatisticsRequest(); + request.setMetricName(Constants.REQUEST_COUNT_METRIC_NAME); + request.setNamespace(Constants.CLOUD_WATCH_NAMESPACE_NAME); + + Date currentTime = new DateTime(DateTimeZone.UTC).toDate(); + Date pastTime = new DateTime(DateTimeZone.UTC).minusSeconds( + timeInterval).toDate(); + + request.setStartTime(pastTime); + request.setEndTime(currentTime); + + request.setPeriod(timeInterval); + + HashSet<String> statistics = new HashSet<String>(); + statistics.add(Constants.SUM_STATISTICS_NAME); + request.setStatistics(statistics); + + HashSet<Dimension> dimensions = new HashSet<Dimension>(); + Dimension loadBalancerDimension = new Dimension(); + loadBalancerDimension + .setName(Constants.LOAD_BALANCER_DIMENTION_NAME); + loadBalancerDimension.setValue(loadBalancerName); + dimensions.add(loadBalancerDimension); + request.setDimensions(dimensions); + + cloudWatchClient.setEndpoint(String.format( + Constants.CLOUD_WATCH_ENDPOINT_URL_FORMAT, region)); + + GetMetricStatisticsResult result = cloudWatchClient + .getMetricStatistics(request); + + List<Datapoint> dataPoints = result.getDatapoints(); + + if (dataPoints != null && dataPoints.size() > 0) { + count = dataPoints.get(0).getSum().intValue(); + } + + } catch (AmazonClientException e) { + log.error( + "Could not get request count statistics of load balancer " + + loadBalancerName, e); + } + + return count; + } + + /** + * Retrieves total number of responses generated by all instances attached + * to the load balancer during the time interval in the past. + * + * @param loadBalancerName + * @param region + * @param timeInterval in seconds which must be multiple of 60 + * @return number of responses generated + */ + public int getAllResponsesCount(String loadBalancerName, String region, + int timeInterval) { + int total = 0; + + Date currentTime = new DateTime(DateTimeZone.UTC).toDate(); + Date pastTime = new DateTime(DateTimeZone.UTC).minusSeconds( + timeInterval).toDate(); + + total += getResponseCountForMetric(loadBalancerName, region, + Constants.HTTP_RESPONSE_2XX, pastTime, currentTime, + timeInterval); + total += getResponseCountForMetric(loadBalancerName, region, + Constants.HTTP_RESPONSE_3XX, pastTime, currentTime, + timeInterval); + total += getResponseCountForMetric(loadBalancerName, region, + Constants.HTTP_RESPONSE_4XX, pastTime, currentTime, + timeInterval); + total += getResponseCountForMetric(loadBalancerName, region, + Constants.HTTP_RESPONSE_5XX, pastTime, currentTime, + timeInterval); + + return total; + } + + /** + * Retrieves the number of responses generated for a particular response + * code like 2XX, 3XX, 4XX, 5XX + * + * @param loadBalancerName + * @param region + * @param metricName which is one among HTTPCode_Backend_2XX or + * HTTPCode_Backend_3XX or HTTPCode_Backend_4XX or + * HTTPCode_Backend_5XX + * @param startTime of the window to be scanned + * @param endTime of the window to be scanned + * @param timeInterval in seconds + * @return number for response for this metric + */ + public int getResponseCountForMetric(String loadBalancerName, + String region, String metricName, Date startTime, Date endTime, + int timeInterval) { + int count = 0; + + try { + GetMetricStatisticsRequest request = new GetMetricStatisticsRequest(); + request.setMetricName(metricName); + request.setNamespace(Constants.CLOUD_WATCH_NAMESPACE_NAME); + + request.setStartTime(startTime); + request.setEndTime(endTime); + + request.setPeriod(timeInterval); + + HashSet<String> statistics = new HashSet<String>(); + statistics.add(Constants.SUM_STATISTICS_NAME); + request.setStatistics(statistics); + + HashSet<Dimension> dimensions = new HashSet<Dimension>(); + Dimension loadBalancerDimension = new Dimension(); + loadBalancerDimension + .setName(Constants.LOAD_BALANCER_DIMENTION_NAME); + loadBalancerDimension.setValue(loadBalancerName); + dimensions.add(loadBalancerDimension); + request.setDimensions(dimensions); + + cloudWatchClient.setEndpoint(String.format( + Constants.CLOUD_WATCH_ENDPOINT_URL_FORMAT, region)); + + GetMetricStatisticsResult result = cloudWatchClient + .getMetricStatistics(request); + + List<Datapoint> dataPoints = result.getDatapoints(); + + if (dataPoints != null && dataPoints.size() > 0) { + count = dataPoints.get(0).getSum().intValue(); + } + + } catch (AmazonClientException e) { + log.error("Could not get the statistics for metric " + metricName + + " of load balancer " + loadBalancerName, e); + } + + return count; + } + + /** + * Returns the Listeners required for the service. Listeners are derived + * from the proxy port, port and protocol values of the service. + * + * @param service + * @return list of listeners required for the service + */ + public List<Listener> getRequiredListeners(Member member) throws LoadBalancerExtensionException { + List<Listener> listeners = new ArrayList<Listener>(); + + Collection<Port> ports = member.getPorts(); + + for (Port port : ports) { + int instancePort = port.getValue(); + int proxyPort = port.getProxy(); + String protocol = port.getProtocol().toUpperCase(); + String instanceProtocol = protocol; + + Listener listener = new Listener(protocol, proxyPort, instancePort); + listener.setInstanceProtocol(instanceProtocol); + if ("HTTPS".equalsIgnoreCase(protocol) || "SSL".equalsIgnoreCase(protocol)) { + // if the SSL certificate is not configured in the aws.properties file, can't continue + if (getSslCertificateId() == null || getSslCertificateId().isEmpty()) { + String errorMsg = "Required property " + Constants.LOAD_BALANCER_SSL_CERTIFICATE_ID + " not provided in configuration"; + log.error(errorMsg); + throw new LoadBalancerExtensionException(errorMsg); + } + // TODO: make debug? + if (log.isInfoEnabled()) { + log.info("Listener protocol = " + protocol + ", hence setting the SSL Certificate Id: " + getSslCertificateId()); + } + listener.setSSLCertificateId(getSslCertificateId()); + } + + listeners.add(listener); + } + + return listeners; + } + + /** + * Constructs name of the load balancer to be associated with the cluster + * + * @param clusterId + * @return name of the load balancer + * @throws LoadBalancerExtensionException + */ + public String generateLoadBalancerName(String serviceName) + throws LoadBalancerExtensionException { + String name = null; + + //name = lbPrefix + getNextLBSequence(); + name = lbPrefix + serviceName; + + if (name.length() > Constants.LOAD_BALANCER_NAME_MAX_LENGTH) + throw new LoadBalancerExtensionException( + "Load balanacer name length (32 characters) exceeded"); + + return name; + } + + /** + * Extract instance id in IaaS side from member instance name + * + * @param memberInstanceName + * @return instance id in IaaS + */ + public String getAWSInstanceName(String memberInstanceName) { + if (memberInstanceName.contains("/")) { + return memberInstanceName + .substring(memberInstanceName.indexOf("/") + 1); + } else { + return memberInstanceName; + } + } + + /** + * Extract IaaS region from member instance name + * + * @param memberInstanceName + * @return IaaS region to which member belongs + */ + public String getAWSRegion(String memberInstanceName) { + if (memberInstanceName.contains("/")) { + return memberInstanceName.substring(0, + memberInstanceName.indexOf("/")); + } else { + return null; + } + } + + /** + * Get availability zone from region + * + * @param region + * @return Availability zone of IaaS + */ + public String getAvailabilityZoneFromRegion(String region) { + if (region != null) { + return region + "a"; + } else + return null; + } + + public CreateAppCookieStickinessPolicyResult createStickySessionPolicy(String lbName, String cookieName, String policyName, String region) { + + elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + CreateAppCookieStickinessPolicyRequest stickinessPolicyReq = new CreateAppCookieStickinessPolicyRequest(). + withLoadBalancerName(lbName).withCookieName(cookieName).withPolicyName(policyName); + + CreateAppCookieStickinessPolicyResult stickinessPolicyResult = null; + try { + stickinessPolicyResult = elbClient.createAppCookieStickinessPolicy(stickinessPolicyReq); + + } catch (AmazonServiceException e) { + log.error(e.getMessage(), e); + + } catch (AmazonClientException e) { + log.error(e.getMessage(), e); + } + + if (stickinessPolicyResult == null) { + log.error("Error in creating Application Stickiness policy for for cookie name: " + cookieName + ", policy: " + policyName); + } else { + log.info("Enabled Application stickiness using: " + cookieName + ", policy: " + policyName + " for LB " + lbName); + } + + return stickinessPolicyResult; + } + + public void applyPolicyToLBListenerPorts(Collection<Port> ports, String loadBalancerName, String policyName, String region) { + + for (Port port : ports) { + if ("HTTP".equalsIgnoreCase(port.getProtocol()) || "HTTPS".equalsIgnoreCase(port.getProtocol())) { + applyPolicyToListener(loadBalancerName, port.getProxy(), policyName, region); + // hack to stop too many calls to AWS API :( + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + } + } + } + } + + private void applyPolicyToListener(String loadBalancerName, int listenerPort, String policyName, String region) { + + SetLoadBalancerPoliciesOfListenerRequest loadBalancerPoliciesOfListenerReq = new SetLoadBalancerPoliciesOfListenerRequest(). + withLoadBalancerName(loadBalancerName).withLoadBalancerPort(listenerPort).withPolicyNames(policyName); + + elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + SetLoadBalancerPoliciesOfListenerResult setLBPoliciesOfListenerRes = null; + try { + setLBPoliciesOfListenerRes = elbClient.setLoadBalancerPoliciesOfListener(loadBalancerPoliciesOfListenerReq); + + } catch (AmazonServiceException e) { + log.error(e.getMessage(), e); + + } catch (AmazonClientException e) { + log.error(e.getMessage(), e); + } + + if (setLBPoliciesOfListenerRes == null) { + log.error("Unable to apply policy " + policyName + " for Listener port: " + listenerPort + " for LB: " + loadBalancerName); + } else { + log.info("Successfully applied policy " + policyName + " for Listener port: " + listenerPort + " for LB: " + loadBalancerName); + } + } + + public List<String> getAvailabilityZonesFromRegion(final String region) { + + DescribeAvailabilityZonesRequest availabilityZonesReq = new DescribeAvailabilityZonesRequest(); + List<Filter> availabilityZoneFilters = new ArrayList<Filter>(); + availabilityZoneFilters.add(new Filter("region-name", new ArrayList<String>() {{ + add(region); + }})); + availabilityZoneFilters.add(new Filter("state", new ArrayList<String>() {{ + add("available"); + }})); + + ec2Client.setEndpoint(String.format(Constants.EC2_ENDPOINT_URL_FORMAT, region)); + DescribeAvailabilityZonesResult availabilityZonesRes = null; + + try { + availabilityZonesRes = ec2Client.describeAvailabilityZones(availabilityZonesReq); + + } catch (AmazonServiceException e) { + log.error(e.getMessage(), e); + + } catch (AmazonClientException e) { + log.error(e.getMessage(), e); + } + + List<String> availabilityZones = null; + + if (availabilityZonesRes != null) { + availabilityZones = new ArrayList<>(); + for (AvailabilityZone zone : availabilityZonesRes.getAvailabilityZones()) { + availabilityZones.add(zone.getZoneName()); + } + } else { + log.error("Unable to retrieve the active availability zones for region " + region); + } + + return availabilityZones; + } + + public void addAvailabilityZonesForLoadBalancer(String loadBalancerName, List<String> availabilityZones, String region) { + + EnableAvailabilityZonesForLoadBalancerRequest enableAvailabilityZonesReq = new EnableAvailabilityZonesForLoadBalancerRequest() + .withLoadBalancerName(loadBalancerName).withAvailabilityZones(availabilityZones); + + elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + EnableAvailabilityZonesForLoadBalancerResult enableAvailabilityZonesRes = null; + + try { + enableAvailabilityZonesRes = elbClient.enableAvailabilityZonesForLoadBalancer(enableAvailabilityZonesReq); + + } catch (AmazonServiceException e) { + log.error(e.getMessage(), e); + + } catch (AmazonClientException e) { + log.error(e.getMessage(), e); + } + + if (enableAvailabilityZonesRes != null) { + log.info("Availability zones successfully added to LB " + loadBalancerName + ". Updated zone list: "); + for (String zone : enableAvailabilityZonesRes.getAvailabilityZones()) { + log.info(zone); + } + } else { + log.error("Updating availability zones failed for LB " + loadBalancerName); + } + } + + public void modifyLBAttributes(String loadBalancerName, String region, boolean enableCrossZoneLbing, boolean enableConnDraining) { + + if (!enableCrossZoneLbing && !enableConnDraining) { + log.info("No attributes specified to modify in the LB " + loadBalancerName); + return; + } - ModifyLoadBalancerAttributesRequest modifyLBAttributesReq = new ModifyLoadBalancerAttributesRequest().withLoadBalancerName(loadBalancerName); - LoadBalancerAttributes modifiedLbAttributes = new LoadBalancerAttributes(); - if (enableCrossZoneLbing) { - modifiedLbAttributes.setCrossZoneLoadBalancing(new CrossZoneLoadBalancing().withEnabled(true)); - } - if (enableConnDraining) { - modifiedLbAttributes.setConnectionDraining(new ConnectionDraining().withEnabled(true)); - } - - modifyLBAttributesReq.setLoadBalancerAttributes(modifiedLbAttributes); - - elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); - - ModifyLoadBalancerAttributesResult modifyLBAttributesRes = elbClient.modifyLoadBalancerAttributes(modifyLBAttributesReq); - if (modifyLBAttributesRes != null) { - log.info("Successfully enabled cross zone load balancing and connection draining for " + loadBalancerName); - } else { - log.error("Failed to enable cross zone load balancing and connection draining for " + loadBalancerName); - } - } - - public String getSslCertificateId() { - return sslCertificateId; - } - - public String getAppStickySessionCookie() { - return appStickySessionCookie; - } + ModifyLoadBalancerAttributesRequest modifyLBAttributesReq = new ModifyLoadBalancerAttributesRequest().withLoadBalancerName(loadBalancerName); + LoadBalancerAttributes modifiedLbAttributes = new LoadBalancerAttributes(); + if (enableCrossZoneLbing) { + modifiedLbAttributes.setCrossZoneLoadBalancing(new CrossZoneLoadBalancing().withEnabled(true)); + } + if (enableConnDraining) { + modifiedLbAttributes.setConnectionDraining(new ConnectionDraining().withEnabled(true)); + } + + modifyLBAttributesReq.setLoadBalancerAttributes(modifiedLbAttributes); + + elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region)); + + ModifyLoadBalancerAttributesResult modifyLBAttributesRes = elbClient.modifyLoadBalancerAttributes(modifyLBAttributesReq); + if (modifyLBAttributesRes != null) { + log.info("Successfully enabled cross zone load balancing and connection draining for " + loadBalancerName); + } else { + log.error("Failed to enable cross zone load balancing and connection draining for " + loadBalancerName); + } + } + + public String getSslCertificateId() { + return sslCertificateId; + } + + public String getAppStickySessionCookie() { + return appStickySessionCookie; + } }
