You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by ga...@apache.org on 2015/10/09 17:07:37 UTC
[2/2] stratos git commit: Add the aws lb extension
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 <ga...@wso2.com>
Authored: Fri Oct 9 20:31:03 2015 +0530
Committer: gayangunarathne <ga...@wso2.com>
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();
+ }
+ }
+ }
+}