Add the aws lb extension
Project: http://git-wip-us.apache.org/repos/asf/stratos/repo Commit: http://git-wip-us.apache.org/repos/asf/stratos/commit/c59529a8 Tree: http://git-wip-us.apache.org/repos/asf/stratos/tree/c59529a8 Diff: http://git-wip-us.apache.org/repos/asf/stratos/diff/c59529a8 Branch: refs/heads/stratos-4.1.x Commit: c59529a897266c1ca8759ae7cbdb81d3ed7a55c8 Parents: 4eec2ff Author: gayangunarathne <[email protected]> Authored: Fri Oct 9 20:31:03 2015 +0530 Committer: gayangunarathne <[email protected]> Committed: Fri Oct 9 20:31:52 2015 +0530 ---------------------------------------------------------------------- .../load/balancer/common/domain/Member.java | 9 + .../load-balancer/aws-extension/INSTALL.md | 45 + .../load-balancer/aws-extension/README.md | 5 + extensions/load-balancer/aws-extension/pom.xml | 119 +++ .../aws-extension/src/main/assembly/bin.xml | 91 ++ .../aws-extension/src/main/bin/aws-extension.sh | 44 + .../aws-extension/src/main/conf/aws.properties | 15 + .../aws-extension/src/main/conf/jndi.properties | 22 + .../src/main/conf/log4j.properties | 40 + .../src/main/conf/thrift-client-config.xml | 27 + .../aws/extension/AWSExtensionContext.java | 101 ++ .../apache/stratos/aws/extension/AWSHelper.java | 926 +++++++++++++++++++ .../stratos/aws/extension/AWSLoadBalancer.java | 305 ++++++ .../aws/extension/AWSStatisticsReader.java | 89 ++ .../apache/stratos/aws/extension/Constants.java | 56 ++ .../org/apache/stratos/aws/extension/Main.java | 90 ++ .../aws-extension/src/main/license/LICENSE | 481 ++++++++++ .../aws-extension/src/main/notice/NOTICE | 395 ++++++++ .../src/main/security/client-truststore.jks | Bin 0 -> 35240 bytes 19 files changed, 2860 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/components/org.apache.stratos.load.balancer.common/src/main/java/org/apache/stratos/load/balancer/common/domain/Member.java ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.load.balancer.common/src/main/java/org/apache/stratos/load/balancer/common/domain/Member.java b/components/org.apache.stratos.load.balancer.common/src/main/java/org/apache/stratos/load/balancer/common/domain/Member.java index 953dabd..c0422da 100644 --- a/components/org.apache.stratos.load.balancer.common/src/main/java/org/apache/stratos/load/balancer/common/domain/Member.java +++ b/components/org.apache.stratos.load.balancer.common/src/main/java/org/apache/stratos/load/balancer/common/domain/Member.java @@ -33,6 +33,7 @@ public class Member { private String memberId; private String hostName; private Map<Integer, Port> portMap; + private String instanceId; public Member(String serviceName, String clusterId, String memberId, String hostName) { this.serviceName = serviceName; @@ -86,4 +87,12 @@ public class Member { public String getServiceName() { return serviceName; } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } } http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/INSTALL.md ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/INSTALL.md b/extensions/load-balancer/aws-extension/INSTALL.md new file mode 100644 index 0000000..0ab671f --- /dev/null +++ b/extensions/load-balancer/aws-extension/INSTALL.md @@ -0,0 +1,45 @@ + # + # Licensed to the Apache Software Foundation (ASF) under one + # or more contributor license agreements. See the NOTICE file + # distributed with this work for additional information + # regarding copyright ownership. The ASF licenses this file + # to you 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. + # + +# Installing Apache Stratos AWS Extension + +Apache Stratos AWS Extension could be used for integrating AWS load balancer with Apache Stratos. Please follow +below steps to proceed with the installation: + +1. Extract org.apache.stratos.aws.extension-<version>.zip to a desired location: <aws-extension-home>. + +2. Open <aws-extension-home>/conf/aws-credentials.conf file in text editor and update AWS access key and secret key information. + +3. Open <aws-extension-home>/bin/aws-extension.sh file in a text editor and update following system properties: + ``` + # Enable/disable cep statistics publisher: + -Dcep.stats.publisher.enabled=false + + # If cep statistics publisher is enabled define the following properties: + -Dthrift.receiver.ip=127.0.0.1 + -Dthrift.receiver.port=7615 + -Dnetwork.partition.id=network-partition-1 + ``` + +4. Open <aws-extension-home>/conf/jndi.properties file in a text editor and update message broker information: + ``` + java.naming.provider.url=tcp://localhost:61616 + ``` +5. Run <aws-extension-home>/bin/aws-extension.sh as the root user. + http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/README.md ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/README.md b/extensions/load-balancer/aws-extension/README.md new file mode 100644 index 0000000..75fa622 --- /dev/null +++ b/extensions/load-balancer/aws-extension/README.md @@ -0,0 +1,5 @@ +# Apache Stratos AWS Extension + +Apache Stratos AWS extension is a load balancer extension for Amazon Web Services (AWS). It is an executable program +which can manage AWS laod balancers according to the topology, composite application model, tenant application signups +and domain mapping information received from Stratos via the message broker. http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/pom.xml ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/pom.xml b/extensions/load-balancer/aws-extension/pom.xml new file mode 100644 index 0000000..65dc8fb --- /dev/null +++ b/extensions/load-balancer/aws-extension/pom.xml @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.stratos</groupId> + <artifactId>stratos-load-balancer-extensions</artifactId> + <version>4.1.4-SNAPSHOT</version> + </parent> + + <artifactId>org.apache.stratos.aws.extension</artifactId> + <name>Apache Stratos - AWS Extension</name> + <description>Apache Stratos AWS Extension for Load Balancing</description> + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>1.7.5</version> + </dependency> + <dependency> + <groupId>org.apache.stratos</groupId> + <artifactId>org.apache.stratos.common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.stratos</groupId> + <artifactId>org.apache.stratos.messaging</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.stratos</groupId> + <artifactId>org.apache.stratos.load.balancer.extension.api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.0</version> + </dependency> + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity</artifactId> + <version>1.7</version> + </dependency> + <dependency> + <groupId>org.wso2.andes.wso2</groupId> + <artifactId>andes-client</artifactId> + <version>0.13.wso2v8</version> + </dependency> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk</artifactId> + <version>1.8.8</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents.wso2</groupId> + <artifactId>httpclient</artifactId> + <version>4.2.5.wso2v1</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.4</version> + <configuration> + <archive> + <manifest> + <mainClass>org.apache.stratos.aws.extension.Main</mainClass> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptors> + <descriptor>src/main/assembly/bin.xml</descriptor> + </descriptors> + <archiverConfig> + <fileMode>420</fileMode> + <directoryMode>493</directoryMode> + <defaultDirectoryMode>493</defaultDirectoryMode> + </archiverConfig> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>attached</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/assembly/bin.xml ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/assembly/bin.xml b/extensions/load-balancer/aws-extension/src/main/assembly/bin.xml new file mode 100644 index 0000000..ba0ad12 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/assembly/bin.xml @@ -0,0 +1,91 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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. + --> + +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>bin</id> + <formats> + <format>zip</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/src/main/bin</directory> + <outputDirectory>/bin</outputDirectory> + <fileMode>0755</fileMode> + <includes> + <include>aws-extension.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.basedir}/src/main/conf</directory> + <outputDirectory>/conf</outputDirectory> + <fileMode>0600</fileMode> + <includes> + <include>jndi.properties</include> + <include>log4j.properties</include> + <include>thrift-client-config.xml</include> + <include>aws.properties</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.basedir}/src/main/security</directory> + <outputDirectory>/security</outputDirectory> + <fileMode>0600</fileMode> + <includes> + <include>client-truststore.jks</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.basedir}</directory> + <outputDirectory>/</outputDirectory> + <fileMode>0600</fileMode> + <includes> + <include>DISCLAIMER</include> + <include>README*</include> + <include>LICENSE*</include> + <include>INSTALL*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.basedir}/src/main/license</directory> + <outputDirectory>/</outputDirectory> + <fileMode>0600</fileMode> + </fileSet> + <fileSet> + <directory>${project.basedir}/src/main/notice</directory> + <outputDirectory>/</outputDirectory> + <fileMode>0600</fileMode> + </fileSet> + </fileSets> + <dependencySets> + <dependencySet> + <outputDirectory>/lib</outputDirectory> + <excludes> + <exclude>*:icu4j*</exclude> + <exclude>*:jaxen*</exclude> + <exclude>*:jboss-transaction-api*</exclude> + <exclude>*:wrapper*</exclude> + <exclude>*:xom*</exclude> + </excludes> + <useProjectArtifact>true</useProjectArtifact> + <scope>runtime</scope> + </dependencySet> + </dependencySets> +</assembly> http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/bin/aws-extension.sh ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/bin/aws-extension.sh b/extensions/load-balancer/aws-extension/src/main/bin/aws-extension.sh new file mode 100755 index 0000000..19936ae --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/bin/aws-extension.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# -------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# +# -------------------------------------------------------------- + +echo "Starting aws extension..." +script_path="$( cd -P "$( dirname "$SOURCE" )" && pwd )/`dirname $0`" +lib_path=${script_path}/../lib/ +class_path=`echo ${lib_path}/*.jar | tr ' ' ':'` +properties="-Djndi.properties.dir=${script_path}/../conf + -Dlog4j.properties.file.path=${script_path}/../conf/log4j.properties + -Daws.properties.file=${script_path}/../conf/aws.properties + -Djavax.net.ssl.trustStore=${script_path}/../security/client-truststore.jks + -Djavax.net.ssl.trustStorePassword=wso2carbon + -Dthrift.client.config.file.path=${script_path}/../conf/thrift-client-config.xml + -Dcep.stats.publisher.enabled=false + -Dthrift.receiver.ip=127.0.0.1 + -Dthrift.receiver.port=7615 + -Dnetwork.partition.id=network-partition-1 + -Dcluster.id=cluster-1 + -Dservice.name=service-1" + + +# Uncomment below line to enable remote debugging +#debug="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" + +java -cp "${class_path}" ${properties} ${debug} org.apache.stratos.aws.extension.Main $* http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/conf/aws.properties ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/conf/aws.properties b/extensions/load-balancer/aws-extension/src/main/conf/aws.properties new file mode 100644 index 0000000..2bb2879 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/conf/aws.properties @@ -0,0 +1,15 @@ +access-key= +secret-key= +# load-balancer-prefix should contain only alphabets and dashes and should not exceed 25 characters. +load-balancer-prefix=LB- +# security group will be created if does not exist. Should contain only ASCII characters and should not exceed 255 characters. +load-balancer-security-group-name=lb-security-group +# CIDR IP which can be set as allowed source IP of incoming requests for security group mentioned in 'load-balancer-security-group-name' +# 0.0.0.0/0 allows all IPs +allowed-cidr-ip=0.0.0.0/0 +# Internet Protocol allowed for incoming requests for security group mentioned in 'load-balancer-security-group-name'. +# Comma separated e.g. tcp,udp +allowed-protocols=tcp +# statistics-interval denotes the interval in seconds for which statistics are gathered to calculate request in flight count. +# This must be multiple of 60. +statistics-interval=60 http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/conf/jndi.properties ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/conf/jndi.properties b/extensions/load-balancer/aws-extension/src/main/conf/jndi.properties new file mode 100644 index 0000000..21d7420 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/conf/jndi.properties @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +connectionfactoryName=TopicConnectionFactory +java.naming.provider.url=tcp://localhost:61616 +java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/conf/log4j.properties ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/conf/log4j.properties b/extensions/load-balancer/aws-extension/src/main/conf/log4j.properties new file mode 100644 index 0000000..fe9ca61 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/conf/log4j.properties @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +# Set root logger level and appenders +log4j.rootLogger=INFO, CONSOLE_APPENDER, FILE_APPENDER + +# CONSOLE_APPENDER is set to be a ConsoleAppender. +log4j.appender.CONSOLE_APPENDER=org.apache.log4j.ConsoleAppender + +# The standard error log where all the warnings, errors and fatal errors will be logged +log4j.appender.FILE_APPENDER=org.apache.log4j.FileAppender +log4j.appender.FILE_APPENDER.File=logs/aws-extension.log +log4j.appender.FILE_APPENDER.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE_APPENDER.layout.ConversionPattern=%d{ISO8601} [%X{ip}-%X{host}] [%t] %5p %c{1} %m%n +log4j.appender.FILE_APPENDER.threshold=DEBUG + +# CONSOLE_APPENDER uses PatternLayout. +log4j.appender.CONSOLE_APPENDER.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE_APPENDER.layout.ConversionPattern=[%d{ISO8601}] %5p - [%c{1}] %m%n + +log4j.logger.org.apache.stratos.aws.extension=INFO +log4j.logger.org.apache.stratos.load.balancer.extension.api=INFO +log4j.logger.org.apache.stratos.messaging=INFO +log4j.logger.org.wso2.andes.client=ERROR \ No newline at end of file http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/conf/thrift-client-config.xml ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/conf/thrift-client-config.xml b/extensions/load-balancer/aws-extension/src/main/conf/thrift-client-config.xml new file mode 100644 index 0000000..5cacada --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/conf/thrift-client-config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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. + --> + +<!-- Apache thrift client configuration for publishing statistics to WSO2 CEP --> +<thriftClientConfiguration> + <username>admin</username> + <password>admin</password> + <ip>localhost</ip> + <port>7611</port> +</thriftClientConfiguration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java new file mode 100644 index 0000000..d3da969 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.stratos.aws.extension; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * AWS Load Balancer context to read and store system properties. + */ +public class AWSExtensionContext { + private static final Log log = LogFactory.getLog(AWSExtensionContext.class); + private static volatile AWSExtensionContext context; + + private boolean cepStatsPublisherEnabled; + private String thriftReceiverIp; + private String thriftReceiverPort; + private String networkPartitionId; + private String clusterId; + private String serviceName; + + private AWSExtensionContext() { + this.cepStatsPublisherEnabled = Boolean.getBoolean(Constants.CEP_STATS_PUBLISHER_ENABLED); + this.thriftReceiverIp = System.getProperty(Constants.THRIFT_RECEIVER_IP); + this.thriftReceiverPort = System.getProperty(Constants.THRIFT_RECEIVER_PORT); + this.networkPartitionId = System.getProperty(Constants.NETWORK_PARTITION_ID); + this.clusterId = System.getProperty(Constants.CLUSTER_ID); + this.serviceName = System.getProperty(Constants.SERVICE_NAME); + + if (log.isDebugEnabled()) { + log.debug(Constants.CEP_STATS_PUBLISHER_ENABLED + " = " + cepStatsPublisherEnabled); + log.debug(Constants.THRIFT_RECEIVER_IP + " = " + thriftReceiverIp); + log.debug(Constants.THRIFT_RECEIVER_PORT + " = " + thriftReceiverPort); + log.debug(Constants.NETWORK_PARTITION_ID + " = " + networkPartitionId); + log.debug(Constants.CLUSTER_ID + " = " + clusterId); + } + } + + public static AWSExtensionContext getInstance() { + if (context == null) { + synchronized (AWSExtensionContext.class) { + if (context == null) { + context = new AWSExtensionContext(); + } + } + } + return context; + } + + public void validate() { + validateSystemProperty(Constants.CEP_STATS_PUBLISHER_ENABLED); + validateSystemProperty(Constants.CLUSTER_ID); + + if (cepStatsPublisherEnabled) { + validateSystemProperty(Constants.THRIFT_RECEIVER_IP); + validateSystemProperty(Constants.THRIFT_RECEIVER_PORT); + validateSystemProperty(Constants.NETWORK_PARTITION_ID); + } + } + + private void validateSystemProperty(String propertyName) { + String value = System.getProperty(propertyName); + if (StringUtils.isEmpty(value)) { + throw new RuntimeException("System property was not found: " + propertyName); + } + } + + public boolean isCEPStatsPublisherEnabled() { + return cepStatsPublisherEnabled; + } + + public String getNetworkPartitionId() { + return networkPartitionId; + } + + public String getClusterId() { + return clusterId; + } + + public String getServiceName() { + return serviceName; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java new file mode 100644 index 0000000..a8164e7 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java @@ -0,0 +1,926 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.stratos.aws.extension; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.load.balancer.common.domain.*; +import org.apache.stratos.load.balancer.extension.api.exception.LoadBalancerExtensionException; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; + +import com.amazonaws.AmazonClientException; +import com.amazonaws.ClientConfiguration; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.cloudwatch.AmazonCloudWatchClient; +import com.amazonaws.services.cloudwatch.model.Datapoint; +import com.amazonaws.services.cloudwatch.model.Dimension; +import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsRequest; +import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsResult; +import com.amazonaws.services.ec2.AmazonEC2Client; +import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest; +import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest; +import com.amazonaws.services.ec2.model.CreateSecurityGroupResult; +import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest; +import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult; +import com.amazonaws.services.ec2.model.IpPermission; +import com.amazonaws.services.ec2.model.SecurityGroup; +import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient; +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 AtomicInteger lbSequence; + + private List<String> allowedProtocolsForLBSecurityGroup; + + private ConcurrentHashMap<String, String> regionToSecurityGroupIdMap; + + private BasicAWSCredentials awsCredentials; + private ClientConfiguration clientConfiguration; + + AmazonElasticLoadBalancingClient elbClient; + AmazonEC2Client ec2Client; + private AmazonCloudWatchClient cloudWatchClient; + + private static final Log log = LogFactory.getLog(AWSHelper.class); + + public AWSHelper() throws LoadBalancerExtensionException { + // Read values for awsAccessKey, awsSecretKey etc. from config file + + String awsPropertiesFile = System + .getProperty(Constants.AWS_PROPERTIES_FILE); + + Properties properties = new Properties(); + + InputStream inputStream = null; + + try { + inputStream = new FileInputStream(awsPropertiesFile); + + properties.load(inputStream); + + 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."); + } + + 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."); + } + + lbSequence = new AtomicInteger(1); + + 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."); + } + + this.allowedCidrIpForLBSecurityGroup = properties + .getProperty(Constants.ALLOWED_CIDR_IP_KEY); + + if (this.allowedCidrIpForLBSecurityGroup.isEmpty()) { + throw new LoadBalancerExtensionException( + "Invalid allowed CIDR IP."); + } + + String allowedProtocols = properties + .getProperty(Constants.ALLOWED_PROTOCOLS); + + if (allowedProtocols.isEmpty()) { + throw new LoadBalancerExtensionException( + "Please specify at least one Internet protocol."); + } + + String[] protocols = allowedProtocols.split(","); + + this.allowedProtocolsForLBSecurityGroup = new ArrayList<String>(); + + for (String protocol : protocols) { + this.allowedProtocolsForLBSecurityGroup.add(protocol); + } + + String interval = properties + .getProperty(Constants.STATISTICS_INTERVAL); + + if (interval == null || interval.isEmpty()) { + this.statisticsInterval = Constants.STATISTICS_INTERVAL_MULTIPLE_OF; + } else { + try { + this.statisticsInterval = Integer.parseInt(interval); + + 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; + } + } + + this.lbSecurityGroupDescription = Constants.LOAD_BALANCER_SECURITY_GROUP_DESCRIPTION; + + regionToSecurityGroupIdMap = new ConcurrentHashMap<String, String>(); + + 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) throws LoadBalancerExtensionException { + + log.info("Creating load balancer " + name); + + CreateLoadBalancerRequest createLoadBalancerRequest = new CreateLoadBalancerRequest( + name); + + createLoadBalancerRequest.setListeners(listeners); + + Set<String> availabilityZones = new HashSet<String>(); + availabilityZones.add(getAvailabilityZoneFromRegion(region)); + + createLoadBalancerRequest.setAvailabilityZones(availabilityZones); + + try { + 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) { + throw new LoadBalancerExtensionException( + "Could not create load balancer " + name, 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 + */ + private 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) { + 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); + + 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() + throws LoadBalancerExtensionException { + String name = null; + + name = lbPrefix + getNextLBSequence(); + + 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; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java new file mode 100644 index 0000000..4621339 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.stratos.aws.extension; + +import com.amazonaws.services.elasticloadbalancing.model.Instance; +import com.amazonaws.services.elasticloadbalancing.model.Listener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.load.balancer.common.domain.Cluster; +import org.apache.stratos.load.balancer.common.domain.Member; +import org.apache.stratos.load.balancer.common.domain.Service; +import org.apache.stratos.load.balancer.common.domain.Topology; +import org.apache.stratos.load.balancer.extension.api.LoadBalancer; +import org.apache.stratos.load.balancer.extension.api.exception.LoadBalancerExtensionException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class AWSLoadBalancer implements LoadBalancer { + + private static final Log log = LogFactory.getLog(AWSLoadBalancer.class); + + // A map <clusterId, load balancer info> to store load balancer information + // against the cluster id + private static ConcurrentHashMap<String, LoadBalancerInfo> clusterIdToLoadBalancerMap = new ConcurrentHashMap<String, LoadBalancerInfo>(); + + // Object used to invoke methods related to AWS API + private AWSHelper awsHelper; + + public AWSLoadBalancer() throws LoadBalancerExtensionException { + awsHelper = new AWSHelper(); + } + + /* + * configure method iterates over topology and configures the AWS load + * balancers needed. Configuration may involve creating a new load balancer + * for a cluster, updating existing load balancers or deleting unwanted load + * balancers. + */ + public boolean configure(Topology topology) + throws LoadBalancerExtensionException { + + log.info("AWS load balancer extension is being reconfigured."); + + HashSet<String> activeClusters = new HashSet<String>(); + + for (Service service : topology.getServices()) { + for (Cluster cluster : service.getClusters()) { + // Check if a load balancer is created for this cluster + if (clusterIdToLoadBalancerMap.containsKey(cluster + .getClusterId())) { + // A load balancer is already present for this cluster + // Get the load balancer and update it. + + if (log.isDebugEnabled()) { + log.debug("Load balancer for cluster " + + cluster.getClusterId() + + " is already present."); + } + + LoadBalancerInfo loadBalancerInfo = clusterIdToLoadBalancerMap + .get(cluster.getClusterId()); + + String loadBalancerName = loadBalancerInfo.getName(); + String region = loadBalancerInfo.getRegion(); + + // Get all the instances attached + // Attach newly added instances to load balancer + + // attachedInstances list is useful in finding out what + // all new instances which + // should be attached to this load balancer. + List<Instance> attachedInstances = awsHelper + .getAttachedInstances(loadBalancerName, region); + + // clusterMembers stores all the members of a cluster. + Collection<Member> clusterMembers = cluster.getMembers(); + + if (clusterMembers.size() > 0) { + activeClusters.add(cluster.getClusterId()); + + List<Instance> instancesToAddToLoadBalancer = new ArrayList<Instance>(); + + for (Member member : clusterMembers) { + // if instance id of member is not in + // attachedInstances + // add this to instancesToAddToLoadBalancer + Instance instance = new Instance( + awsHelper.getAWSInstanceName(member + .getInstanceId())); + + if (attachedInstances == null + || !attachedInstances.contains(instance)) { + instancesToAddToLoadBalancer.add(instance); + + if (log.isDebugEnabled()) { + log.debug("Instance " + + awsHelper + .getAWSInstanceName(member + .getInstanceId()) + + " needs to be registered to load balancer " + + loadBalancerName); + } + + } + } + + if (instancesToAddToLoadBalancer.size() > 0) + awsHelper.registerInstancesToLoadBalancer( + loadBalancerName, + instancesToAddToLoadBalancer, region); + } + + } else { + // Create a new load balancer for this cluster + Collection<Member> clusterMembers = cluster.getMembers(); + + if (clusterMembers.size() > 0) { + // a unique load balancer name with user-defined + // prefix and a sequence number. + String loadBalancerName = awsHelper + .generateLoadBalancerName(); + + String region = awsHelper.getAWSRegion(clusterMembers + .iterator().next().getInstanceId()); + + // list of AWS listeners obtained using port + // mappings of one of the members of the cluster. + List<Listener> listenersForThisCluster = awsHelper + .getRequiredListeners(clusterMembers.iterator() + .next()); + + // DNS name of load balancer which was created. + // This is used in the domain mapping of this + // cluster. + String loadBalancerDNSName = awsHelper + .createLoadBalancer(loadBalancerName, + listenersForThisCluster, region); + + // Add the inbound rule the security group of the load + // balancer + // For each listener, add a new rule with load + // balancer port as allowed protocol in the security + // group. + for (Listener listener : listenersForThisCluster) { + int port = listener.getLoadBalancerPort(); + + for (String protocol : awsHelper + .getAllowedProtocolsForLBSecurityGroup()) { + awsHelper + .addInboundRuleToSecurityGroup( + awsHelper.getSecurityGroupId( + awsHelper + .getLbSecurityGroupName(), + region), region, + protocol, port); + } + } + + log.info("Load balancer '" + loadBalancerDNSName + + "' created for cluster '" + + cluster.getClusterId()); + + // Register instances in the cluster to load balancer + List<Instance> instances = new ArrayList<Instance>(); + + for (Member member : clusterMembers) { + String instanceId = member.getInstanceId(); + + if (log.isDebugEnabled()) { + log.debug("Instance " + + awsHelper + .getAWSInstanceName(instanceId) + + " needs to be registered to load balancer " + + loadBalancerName); + } + + Instance instance = new Instance(); + instance.setInstanceId(awsHelper + .getAWSInstanceName(instanceId)); + + instances.add(instance); + } + + awsHelper.registerInstancesToLoadBalancer( + loadBalancerName, instances, region); + + LoadBalancerInfo loadBalancerInfo = new LoadBalancerInfo( + loadBalancerName, region); + + clusterIdToLoadBalancerMap.put(cluster.getClusterId(), + loadBalancerInfo); + activeClusters.add(cluster.getClusterId()); + } + } + } + } + + // Find out clusters which were present earlier but are not now. + List<String> clustersToRemoveFromMap = new ArrayList<String>(); + + for (String clusterId : clusterIdToLoadBalancerMap.keySet()) { + if (!activeClusters.contains(clusterId)) { + clustersToRemoveFromMap.add(clusterId); + + if (log.isDebugEnabled()) { + log.debug("Load balancer for cluster " + clusterId + + " needs to be removed."); + } + + } + } + + // Delete load balancers associated with these clusters. + for (String clusterId : clustersToRemoveFromMap) { + // Remove load balancer for this cluster. + awsHelper.deleteLoadBalancer( + clusterIdToLoadBalancerMap.get(clusterId).getName(), + clusterIdToLoadBalancerMap.get(clusterId).getRegion()); + clusterIdToLoadBalancerMap.remove(clusterId); + } + + activeClusters.clear(); + log.info("AWS load balancer extension was reconfigured as per the topology."); + return true; + } + + /* + * start method is called after extension if configured first time. Does + * nothing but logs the message. + */ + public void start() throws LoadBalancerExtensionException { + + log.info("AWS load balancer extension started."); + } + + /* + * reload method is called every time after extension if configured. Does + * nothing but logs the message. + */ + public void reload() throws LoadBalancerExtensionException { + // Check what is appropriate to do here. + log.info("AWS load balancer extension reloaded."); + } + + /* + * stop method deletes load balancers for all clusters in the topology. + */ + public void stop() throws LoadBalancerExtensionException { + // Remove all load balancers + for (LoadBalancerInfo loadBalancerInfo : clusterIdToLoadBalancerMap + .values()) { + // Remove load balancer + awsHelper.deleteLoadBalancer(loadBalancerInfo.getName(), + loadBalancerInfo.getRegion()); + } + } + + public static ConcurrentHashMap<String, LoadBalancerInfo> getClusterIdToLoadBalancerMap() { + return clusterIdToLoadBalancerMap; + } +} + +/** + * Used to store load balancer name and the region in which it is created. This + * helps in finding region while calling API methods to modify/delete a load + * balancer. + */ +class LoadBalancerInfo { + private String name; + private String region; + + public LoadBalancerInfo(String name, String region) { + this.name = name; + this.region = region; + } + + public String getName() { + return name; + } + + public String getRegion() { + return region; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSStatisticsReader.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSStatisticsReader.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSStatisticsReader.java new file mode 100644 index 0000000..55aca3d --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSStatisticsReader.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.stratos.aws.extension; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.common.constants.StratosConstants; +import org.apache.stratos.load.balancer.common.statistics.LoadBalancerStatisticsReader; +import org.apache.stratos.load.balancer.common.topology.TopologyProvider; +import org.apache.stratos.load.balancer.extension.api.exception.LoadBalancerExtensionException; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * AWS statistics reader. + */ +public class AWSStatisticsReader implements LoadBalancerStatisticsReader { + + private static final Log log = LogFactory.getLog(AWSStatisticsReader.class); + + private TopologyProvider topologyProvider; + private String clusterInstanceId; + + private AWSHelper awsHelper; + + public AWSStatisticsReader(TopologyProvider topologyProvider) + throws LoadBalancerExtensionException { + this.topologyProvider = topologyProvider; + this.clusterInstanceId = System.getProperty( + StratosConstants.CLUSTER_INSTANCE_ID, + StratosConstants.NOT_DEFINED); + + awsHelper = new AWSHelper(); + } + + @Override + public String getClusterInstanceId() { + return clusterInstanceId; + } + + @Override + public int getInFlightRequestCount(String clusterId) { + + int inFlightRequestCount = 0; + + ConcurrentHashMap<String, LoadBalancerInfo> clusterIdToLoadBalancerMap = AWSLoadBalancer + .getClusterIdToLoadBalancerMap(); + + // Check if load balancer info is available for this cluster. + // If yes, then find difference between total requests made to the load balancer and + // total responses generated by instances attached to it. + if (clusterIdToLoadBalancerMap.containsKey(clusterId)) { + LoadBalancerInfo loadBalancerInfo = clusterIdToLoadBalancerMap + .get(clusterId); + + String loadBalancerName = loadBalancerInfo.getName(); + String region = loadBalancerInfo.getRegion(); + + // In flight request count = total requests - total responses + inFlightRequestCount = awsHelper.getRequestCount(loadBalancerName, + region, awsHelper.getStatisticsInterval()) + - awsHelper.getAllResponsesCount(loadBalancerName, region, + awsHelper.getStatisticsInterval()); + + if (inFlightRequestCount < 0) + inFlightRequestCount = 0; + + } + + return inFlightRequestCount; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java new file mode 100644 index 0000000..30ada5c --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.stratos.aws.extension; + +/** + * AWS proxy extension constants. + */ +public class Constants { + public static final String CEP_STATS_PUBLISHER_ENABLED = "cep.stats.publisher.enabled"; + public static final String THRIFT_RECEIVER_IP = "thrift.receiver.ip"; + public static final String THRIFT_RECEIVER_PORT = "thrift.receiver.port"; + public static final String NETWORK_PARTITION_ID = "network.partition.id"; + public static final String CLUSTER_ID = "cluster.id"; + public static final String SERVICE_NAME = "service.name"; + public static final String AWS_PROPERTIES_FILE = "aws.properties.file"; + public static final String AWS_ACCESS_KEY = "access-key"; + public static final String AWS_SECRET_KEY = "secret-key"; + public static final String LB_PREFIX = "load-balancer-prefix"; + public static final String LOAD_BALANCER_SECURITY_GROUP_NAME = "load-balancer-security-group-name"; + public static final String LOAD_BALANCER_SECURITY_GROUP_DESCRIPTION = "Security group for load balancers created for Apache Stratos."; + public static final String ELB_ENDPOINT_URL_FORMAT = "elasticloadbalancing.%s.amazonaws.com"; + public static final String EC2_ENDPOINT_URL_FORMAT = "ec2.%s.amazonaws.com"; + public static final String CLOUD_WATCH_ENDPOINT_URL_FORMAT = "monitoring.%s.amazonaws.com"; + public static final String ALLOWED_CIDR_IP_KEY = "allowed-cidr-ip"; + public static final String ALLOWED_PROTOCOLS = "allowed-protocols"; + public static final int LOAD_BALANCER_NAME_MAX_LENGTH = 32; + public static final int LOAD_BALANCER_PREFIX_MAX_LENGTH = 25; + public static final int SECURITY_GROUP_NAME_MAX_LENGTH = 255; + public static final String REQUEST_COUNT_METRIC_NAME = "RequestCount"; + public static final String CLOUD_WATCH_NAMESPACE_NAME = "AWS/ELB"; + public static final String SUM_STATISTICS_NAME = "Sum"; + public static final String LOAD_BALANCER_DIMENTION_NAME = "LoadBalancerName"; + public static final String HTTP_RESPONSE_2XX = "HTTPCode_Backend_2XX"; + public static final String HTTP_RESPONSE_3XX = "HTTPCode_Backend_3XX"; + public static final String HTTP_RESPONSE_4XX = "HTTPCode_Backend_4XX"; + public static final String HTTP_RESPONSE_5XX = "HTTPCode_Backend_5XX"; + public static final String STATISTICS_INTERVAL = "statistics-interval"; + public static final int STATISTICS_INTERVAL_MULTIPLE_OF = 60; +} http://git-wip-us.apache.org/repos/asf/stratos/blob/c59529a8/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Main.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Main.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Main.java new file mode 100644 index 0000000..73fa971 --- /dev/null +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Main.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.stratos.aws.extension; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.log4j.PropertyConfigurator; +import org.apache.stratos.common.threading.StratosThreadPool; +import org.apache.stratos.load.balancer.common.topology.TopologyProvider; +import org.apache.stratos.load.balancer.extension.api.LoadBalancerExtension; + +import java.util.concurrent.ExecutorService; + +/** + * AWS extension main class. + */ + +public class Main { + private static final Log log = LogFactory.getLog(Main.class); + private static ExecutorService executorService; + + public static void main(String[] args) { + + LoadBalancerExtension extension = null; + try { + // Configure log4j properties + PropertyConfigurator.configure(System + .getProperty("log4j.properties.file.path")); + + if (log.isInfoEnabled()) { + log.info("AWS extension started"); + } + + executorService = StratosThreadPool.getExecutorService( + "aws.extension.thread.pool", 10); + // Validate runtime parameters + AWSExtensionContext.getInstance().validate(); + TopologyProvider topologyProvider = new TopologyProvider(); + AWSStatisticsReader statisticsReader = AWSExtensionContext + .getInstance().isCEPStatsPublisherEnabled() ? new AWSStatisticsReader( + topologyProvider) : null; + extension = new LoadBalancerExtension(new AWSLoadBalancer(), + statisticsReader, topologyProvider); + extension.setExecutorService(executorService); + extension.execute(); + + // Add shutdown hook + final Thread mainThread = Thread.currentThread(); + final LoadBalancerExtension finalExtension = extension; + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + try { + if (finalExtension != null) { + log.info("Shutting aws extension..."); + finalExtension.stop(); + } + mainThread.join(); + } catch (Exception e) { + log.error(e); + } + } + }); + } catch (Exception e) { + if (log.isErrorEnabled()) { + log.error(e); + } + if (extension != null) { + log.info("Shutting aws extension..."); + extension.stop(); + } + } + } +}
