Friday, July 5, 2013

Clustering WSO2 ESB - Part 2 - Distributed worker-manager setup with one manager and two workers

In the previous post I explained how you can cluster two WSO2 ESB servers where  one ESB node will be playing a dual role as a worker as well as a manager. The setup which I am going to explain in this post is similar to the above, but it has three ESB servers where one server will be dedicated only for management purposes while the other two will be dedicated workers.

As the previous one, this setup also can be used as a Active/Passive setup where the active-passiveness can be decided by the load balancer based on a predefined mechanism(echo test or a heartbeat mechanism). 

The overall setup will contain three ESB servers (nodes), in which one server will act as the Manager while other two will act as the workers. The Manager will be used for deploying artifacts (CAR files and proxies) and managing the cluster.

The  synchronization  of artifacts between the servers will be achieved through the SVN based Deployment Synchronizer.
The overall view of the cluster will be as in the following figure.



Configuring the Manager

Download and extract the WSO2 ESB distribution (referred as MANAGER_HOME ).

axis2.xml configuration

Clustering   should  be  enabled  at  axis2  level  in  order  for  management  node  to  communicate with  the   worker   nodes.  
Open  MANAGER_HOME/repository/conf/axis2/axis2.xml  and  update the clustering configuration as follows:

<clustering class="org.apache.axis2.clustering.tribes.TribesClusteringAgent"  enable="true">
<parameter name="membershipScheme">wka</parameter>

Specify the cluster domain as follows;

<parameter name="domain">wso2.esb.domain</parameter>

Uncomment localmemberhost element in axis2.xml and specify the IP address (or host name) to be exposed to members of the cluster. This address can be an internal address used only for clustering.

<parameter name="localMemberHost">127.0.0.1</parameter>

Define the port through which other nodes will contact this member. If several instances are running in the same host make sure to use ports which will not conflict.

<parameter name="localMemberPort">4001</parameter>

Comment out the static or well­-known members, because this will be the well­-known member. (i.e do not need to have a list of members)
Add a new property "subDomain" under properties and set it to "mgt" to denote that this node belongs to management subdomain.  

<property name="subDomain" value="mgt"/> 

carbon.xml configuration

If multiple WSO2 Carbon ­based products are running in same host, to avoid possible port conflicts, the port offset of MANAGER_HOME/repository/conf/carbon.xml should be changed as follows. Ignore this if you are using three separate hosts.

<Offset>1</Offset>

Configure the Deployment Synchronizer as follows. Make sure both AutoCommit and
AutoCheckout are ‘true’

<DeploymentSynchronizer>
     <Enabled>true</Enabled>
     <AutoCommit>true</AutoCommit>
     <AutoCheckout>true</AutoCheckout>
     <RepositoryType>svn</RepositoryType>
     <SvnUrl>http://svnrepo.example/repos/esb</SvnUrl>
     <SvnUser>USERNAME</SvnUser>
     <SvnPassword>PASSWORD</SvnPassword>
     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>
</DeploymentSynchronizer>

Start the ESB manager node

 ./bin/wso2server.sh

You can access the management console by: https://localhost:9444/carbon/ within the managers node. (Use the correct port according to the port offset which was defined earlier) 

Add a sample proxy though the console and check whether it is getting committed to the SVN correctly. Proxy will be committed to SvnUrl/-1234/synapse-configs/default/proxy-services/ if you created the proxy as the admin.

Configuring the Worker node 1

Download and extract the WSO2 ESB distribution(referred as WORKER_HOME).

axis2.xml configuration

Clustering   should  be  enabled  at  axis2  level  in  order  for  management  node  to  communicate with  the  worker  nodes. Open  WORKER_HOME/repository/conf/axis2/axis2.xml and update the clustering configuration as follows:

<clustering class="org.apache.axis2.clustering.tribes.TribesClusteringAgent" enable="true">
<parameter name="membershipScheme">wka</parameter>

Specify the cluster domain as follows;


<parameter name="domain">wso2.esb.domain</parameter>

Define  the  port  through  which  other  nodes  will  contact  this  member.  If several instances are running in the same host make sure to use ports which will not conflict.

<parameter name="localMemberPort">4002</parameter>

Add managers(Node 1) IP address (or host name) and the port as the well known member.
  • hostName: defined as localMemberHost in managers axis2.xml
  • port: defined as localMemberPort in managers axis2.xml.
Make  sure  this  address  can  be  accessed  through  the  workers  host. If  you  use  host name, map it to managers IP in the ‘etc/hosts’ file of the workers machine.

<members>
   <member>
   <hostName>127.0.0.1</hostName>
      <port>4001</port>
   </member>
</members> 


Add a new property "subDomain" under properties and set it to "worker" to denote that this node belongs to worker subdomain.  

<property name="subDomain" value="worker"/> 

carbon.xml configuration

If multiple WSO2 Carbon­ based products are running in same host, to avoid possible port conflicts, the port offset of WORKER_HOME/repository/conf/carbon.xml should be changed as follows. Ignore this if you are using three separate hosts.

<Offset>2</Offset>

Configure the Deployment Synchronizer as follows. Make sure AutoCommit is set to ‘false’ and AutoCheckout to ‘true’

<DeploymentSynchronizer>
     <Enabled>true</Enabled>
     <AutoCommit>false</AutoCommit>
     <AutoCheckout>true</AutoCheckout>
     <RepositoryType>svn</RepositoryType>
     <SvnUrl>http://svnrepo.example/repos/esb</SvnUrl>
     <SvnUser>USERNAME</SvnUser>
     <SvnPassword>PASSWORD</SvnPassword>
     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>
</DeploymentSynchronizer> 

Start the ESB worker node. The workerNode system property must be set to true when starting the workers. 
Therefore worker should be started as follows (in linux),

./bin/wso2server.sh -DworkerNode=true 

Configuring Worker node 2 

With the consideration of the following points, follow the exact steps as the configuration the worker node 1.

  • Decide on a port Offset value and update the port Offset element in WORKER_HOME/repository/conf/carbon.xml file. If you are using separate hosts ignore this.
  • Change the localMemberPort value of WORKER_HOME/repository/conf/axis2/axis2.xml to a port that is not used already.
Start the ESB worker node. The workerNode system property must be set to true when starting the workers in a cluster. Therefore worker should be started as follows,


./bin/wso2server.bat -DworkerNode=true

How to test the setup..

  • Start the servers as described above. 
  • Add a sample proxy and save it. Add a log mediator to the inSequence so that logs will be displayed in the workers terminals
  • Observe cluster messages(through the terminal or log) which is send by the manager and received by the worker. Worker will then synchronize with the SVN and deploy the proxy
  • Send a request to the end point through the load balancer. Load Balancer should point to the active nodes end point. For example, for external clients, the EP of the proxy should be as  
http://{Load_Balancer_Mapped_URL_for_worker}/services/{Sample_Proxy_Name}
  • In Active workers logs you will see the proxy being invoked (You need to add a log mediator as in number 3 in the proxy to see this)

Wednesday, July 3, 2013

Clustering WSO2 ESB - Part 1 - Distributed worker-manager setup with one node acting the dual role, as a manager as well as a worker

There are several ways of clustered deployment of WSO2 ESB (or any WSO2 server). You can find more about ESB clustering from here. The deployments introduced in that document is fronted by WSO2 ELB (Elastic Load Balancer). In this blog post I will explain the minimum configurations required to configure WSO2 ESB in a worker/manager distributed setup without having a WSO2 ELB at front so that any load balancer can be used. This setup can be also used as a Active/Passive setup where the active-passiveness can be decided by the load balancer based on a predefined mechanism(echo test or a heartbeat mechanism). 

In this setup one ESB node will be playing a dual role as a worker as well as a manager. The  overall  setup  will contain  two  ESB  servers  (nodes), in which  one  server (node 1) will act as  both  Manager  and  Worker while the other server(node 2) will act as only a worker. Node 1 will be used for deploying artifacts (CAR files and proxies) and managing the cluster.

The  synchronization  of artifacts between the servers will be achieved through the SVN based Deployment Synchronizer.
The overall view of the cluster will be as in the following figure.


Configuring the Manager/Worker Node (node 1)

Download and extract the WSO2 ESB distribution (referred as MANAGER_HOME ).

axis2.xml configuration

Clustering   should  be  enabled  at  axis2  level  in  order  for  management  node  to  communicate with  the   worker   nodes.  
Open  MANAGER_HOME/repository/conf/axis2/axis2.xml  and  update the clustering configuration as follows:

<clustering class="org.apache.axis2.clustering.tribes.TribesClusteringAgent"  enable="true">
<parameter name="membershipScheme">wka</parameter>

Specify the cluster domain as follows;

<parameter name="domain">wso2.esb.domain</parameter>

Uncomment localmemberhost element in axis2.xml and specify the IP address (or host name) to be exposed to members of the cluster. This address can be an internal address used only for clustering.

<parameter name="localMemberHost">127.0.0.1</parameter>

Define the port through which other nodes will contact this member. If several instances are running in the same host make sure to use ports which will not conflict.

<parameter name="localMemberPort">4001</parameter>

Comment out the static or well­-known members, because this will be the well­-known member. (i.e do not need to have a list of members)

carbon.xml configuration

If multiple WSO2 Carbon ­based products are running in same host, to avoid possible port conflicts, the port offset of MANAGER_HOME/repository/conf/carbon.xml should be changed as follows. Ignore this if you are using three separate hosts.

<Offset>1</Offset>

Configure the Deployment Synchronizer as follows. Make sure both AutoCommit and
AutoCheckout are ‘true’

<DeploymentSynchronizer>
     <Enabled>true</Enabled>
     <AutoCommit>true</AutoCommit>
     <AutoCheckout>true</AutoCheckout>
     <RepositoryType>svn</RepositoryType>
     <SvnUrl>http://svnrepo.example/repos/esb</SvnUrl>
     <SvnUser>USERNAME</SvnUser>
     <SvnPassword>PASSWORD</SvnPassword>
     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>
</DeploymentSynchronizer>

Start the ESB manager node(./bin/wso2server.sh ).

You can access the management console by: https://localhost:9444/carbon/ within the managers node. (Use the correct port according to the port offset which was defined earlier) 

Add a sample proxy though the console and check whether it is getting committed to the SVN correctly. Proxy will be committed to SvnUrl/-1234/synapse-configs/default/proxy-services/ if you created the proxy as the admin.

Configuring the worker node (Node 2)

Download and extract the WSO2 ESB distribution(referred as WORKER_HOME).

axis2.xml configuration

Clustering   should  be  enabled  at  axis2  level  in  order  for  management  node  to  communicate with  the  worker  nodes. Open  WORKER_HOME/repository/conf/axis2/axis2.xml and update the clustering configuration as follows:

<clustering class="org.apache.axis2.clustering.tribes.TribesClusteringAgent" enable="true">
<parameter name="membershipScheme">wka</parameter>

Specify the cluster domain as follows;


<parameter name="domain">wso2.esb.domain</parameter>

Define  the  port  through  which  other  nodes  will  contact  this  member.  If several instances are running in the same host make sure to use ports which will not conflict.

<parameter name="localMemberPort">4002</parameter>

Add managers(Node 1) IP address (or host name) and the port as the well known member.
  • hostName: defined as localMemberHost in managers axis2.xml
  • port: defined as localMemberPort in managers axis2.xml.
Make  sure  this  address  can  be  accessed  through  the  workers  host. If  you  use  host name, map it to managers IP in the ‘etc/hosts’ file of the workers machine.

<members>
   <member>
   <hostName>127.0.0.1</hostName>
      <port>4001</port>
   </member>
</members> 


carbon.xml configuration

If multiple WSO2 Carbon­ based products are running in same host, to avoid possible port conflicts, the port offset of WORKER_HOME/repository/conf/carbon.xml should be changed as follows. Ignore this if you are using three separate hosts.

<Offset>2</Offset>

Configure the Deployment Synchronizer as follows. Make sure AutoCommit is set to ‘false’ and AutoCheckout to ‘true’

<DeploymentSynchronizer>
     <Enabled>true</Enabled>
     <AutoCommit>false</AutoCommit>
     <AutoCheckout>true</AutoCheckout>
     <RepositoryType>svn</RepositoryType>
     <SvnUrl>http://svnrepo.example/repos/esb</SvnUrl>
     <SvnUser>USERNAME</SvnUser>
     <SvnPassword>PASSWORD</SvnPassword>
     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>
</DeploymentSynchronizer> 

Start the ESB worker node. The workerNode system property must be set to true when starting the workers. 
Therefore worker should be started as follows (in linux),

./bin/wso2server.sh -DworkerNode=true 

How to test the setup..

  • Start the servers as described above. 
  • Add a sample proxy and save it. Add a log mediator to the inSequence so that logs will be displayed in the workers terminals
  • Observe cluster messages(through the terminal or log) which is send by the manager and received by the worker. Worker will then synchronize with the SVN and deploy the proxy
  • Send a request to the end point through the load balancer. Load Balancer should point to the active nodes end point. For example, for external clients, the EP of the proxy should be as  
http://{Load_Balancer_Mapped_URL_for_worker}/services/{Sample_Proxy_Name}
  • In Active nodes logs you will see the proxy being invoked (You need to add a log mediator as in number 3 in the proxy to see this)


 

Tuesday, May 14, 2013

Setting up WSO2 Stratos 1.6 in your PC - The most complete, enterprise-grade and open PaaS


WSO2 Stratos is an open source PaaS which is complete, enterprise grade and which includes many services which can empower your businesses. WSO2 Stratos is the backbone behind WSO2 StratosLive, the PaaS operated by WSO2 itself.
With the following guide you can setup Stratos locally in your PC and try the features easily.
Prerequisites:
1.    MySQL Server
In order to run Stratos you will need MySQL server running on your PC.
        You can download it from: http://dev.mysql.com/downloads/mysql/
        In Ubuntu: sudo apt-get install mysql-server
Stratos assumes the password of your MySQL root to be 'root'. If you have not configured it, you can do it by the following command.
    mysqladmin -u root -p 'oldpassword' password root
2.    Download the Stratos Local setup from: http://wso2.com/cloud/stratos/
 After downloading the setup, extract it to a convenient location.
3.    Also you need to have Java on your machine in order to try this.
Steps (We will assume a Ubuntu environment)
1.    You need to modify the /etc/hosts file in order to redirect the Stratos specific URLs to localhost. Add the following entries to the file.    
      127.0.0.1        stratos-local.wso2.com
      127.0.0.1        management.appserver.stratos-local.wso2.com
      127.0.0.1        appserver.stratos-local.wso2.com
      127.0.0.1        management.esb.stratos-local.wso2.com
      127.0.0.1        esb.stratos-local.wso2.com
      127.0.0.1        management.data.stratos-local.wso2.com
      127.0.0.1        data.stratos-local.wso2.com
      127.0.0.1        monitor.stratos-local.wso2.com
      127.0.0.1        management.process.stratos-local.wso2.com
      127.0.0.1        process.stratos-local.wso2.com
      127.0.0.1        governance.stratos-local.wso2.com
      127.0.0.1        identity.stratos-local.wso2.com
      127.0.0.1        storage.stratos-local.wso2.com
      127.0.0.1        cep.stratos-local.wso2.com
      127.0.0.1        task.stratos-local.wso2.com
      127.0.0.1        messaging.stratos-local.wso2.com
      127.0.0.1        management.rule.stratos-local.wso2.com
      127.0.0.1        rule.stratos-local.wso2.com
      127.0.0.1        cloudgateway.stratos-local.wso2.com     

2.    Go inside to the extracted folder and run the initialization script as follows
      ./initialize.sh
      This will initiate the required data tables within the MySQL database.
3.    Then start the ‘elb’ (WSO2 Elastic Load Balancer)  and ‘manager’ (Stratos Manager) services as below
               elb:                     sudo ./stratos start elb
               manager:          ./stratos.sh start manager 
Note: You may need super user privileges to start or stop elb as it runs on standard http and https ports. Also the ports should be free to use.
You may get the following error when you try to start elb as supper user.

               Starting elb
       Error: JAVA_HOME is not defined correctly.
       CARBON cannot execute java


This might be because JAVA_HOME has not been set to the  super user environment. As a workaround you can use 'sudo -E ./stratos start elb' to start elb.              
4.    Then start the services of your preference
You can obtain the available list of services by the following command. Also it will provide details on starting services.
            ./stratos.sh
To start a service (for example WSO2 Appserver Management)
     ./stratos.sh start as_mgt
To stop
     ./stratos.sh stop as_mgt
To start multiple services
     ./stratos.sh start 'service names separated by spaces'
For example WSO2 Appserver Manager and Worker,  WSO2 ESB Manager and Worker
     ./stratos.sh start ‘as_mgt as_worker esb_mgt esb_worker’


Saturday, January 28, 2012

Writing a Gadget which uses a Google Spreadsheet as a data source

Introduction


Google spreadsheets are being used extensively by many organizations to store their business data. Google spreadsheets provide facilities to track budgets, run financial calculations and do many more things with data. Therefore Google spreadsheets have the ability to be used as data sources for business applications such as Gadgets which can be deployed into an enterprise gadget server like WSO2 Gadget Server. 

Things to have...

What is a Gadget
                                   
Gadgets are simple XML,HTML and JavaScript applications that can be embedded in web pages and other applications which presents information that is useful to the user in a small space. Any developer with a basic knowledge about XML, HTML and JavaScript can author a gadget and deploy it into an Enterprise Gadget server such as WSO2 Gadget Server or a Gadget portal such as iGoogle.

Google Spreadsheets

Google Spreadsheets are online spreadsheets which can be access by any place and also can be shared between various people. Therefore these are used heavily in organizations for many purposes such as to track budgets, run financial calculations and do many more things with data. You can find more details about Google Spreadsheets and how to use them form here.
  
How to use WSO2 Gadget Server

You can download WSO2 Gadget Server from WSO2 Oxygen Tank. For a complete installation guide please refer WSO2 Gadget Server - Installation Guide. For details about adding gadgets to the portal of WSO2 Gadget Server please refer Adding Gadgets to the Portal.
 
Using the Spreadsheet as the Data Source for Google Visualization API

The URL of the Spreadsheet is required if a developer is going to use a Google Spreadsheet as a Data Source. Depending on the view privileges, the access to the spreadsheet will be determined. Therefore when developing gadgets which interacts with Google Spreadsheets developers has to consider about the access level of the spreadsheet that is being used. That is if the spreadsheet has been published to the web anyone can access it through a gadget and if only a limited number of people have view privileges only those will be able to access the spreadsheet through a gadget.
In this article a published spreadsheet  (Gross Agricultural Production in Country X) which contains some sample Agricultural Production data about a country will be used.

First Step: Load the libraries

A gadget which uses Google Visualization API with a Spreadsheet data source require two libraries. They should be loaded before making requests for data. The libraries are loaded using two separate <script> tags as follows.
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
          google.load('visualization', '1', {packages: ['corechart']});
</script>

The first <script> tag loads Google JSAPI library which is used to load API’s associated with Google (in this example the Visualization API).

The second script loads the Visualization API(Google Visualization and chart libraries) which is used to query the Spreadsheet data source and to draw the charts. The line google.load() loads the Visualization library. As the parameters the version of the visualization library (1) and the required packages of Google Chart libraries are given. Only those libraries can be used within the gadget. The ‘corechart’ loads the basic chart libraries which is used to draw pie,bar and column charts. Please refer Loading the libraries for more details.

Second Step: Query the Spreadsheet

As the next step a query is made to retrieve the data from the spreadsheet as follows. This should be included into a separate <script> tag (third).
function querySpreadsheet() {
    var query = new google.visualization.Query(‘URL of the Spreadsheet’);          
     // Send the query with a callback function.
    query.send(handleQueryResponse);
}

google.visualization.Query() creates the query with the Data Source URL. The query can contain optional parameters such as the required sheet. More details can be found here.
After initiating the query it is send with the callback function which is responsible for handling the response.
This method should be called when the gadget is loaded. It is done as follows.
gadgets.util.registerOnLoadHandler(querySpreadsheet);

Third Step : Handling the response

When a response is returned it will be handled by the callback method (handleQueryResponse) defined in the query.send() method in the querySpreadsheet() function. 
function handleQueryResponse(response) {
    if (response.isError()) {
        alert('Error in query: ' + response.getMessage() + ' ' +    
            response.getDetailedMessage());
        return;
    }    
    var data = response.getDataTable();
    var visualization = new    google.visualization.ColumnChart(document.getElementById('visualization'));
    visualization.draw(data, {
        title:"Gross Aggricultural Production of Country X", 
        width:600, 
        height:400,
        hAxis: {
            title: "Year"
        }
    }
    );
}

First it will check for errors in the response and if there is an error it  will be displayed in an alert dialog.

If the response does not contain an error, the DataTable returned by the data source will be assigned to the variable ‘data’.
var data = response.getDataTable();

This DataTable object contains a two-dimensional table which can be formatted according to the users requirement using the methods of that object. Further details about DataTable class can be found here.

After creating the data table object, Google visualization library uses it to draw a Column Chart. First a ColumnChart object  is created with an ‘div’ element (visualization)  from the gadgets HTML body which will be used for drawing the chart.
var visualization = new google.visualization.ColumnChart(document.getElementById('visualization'));

After creating the object, ‘draw’ method is invoked with the data and parameters about the chart. This method will draw the chart inside the ‘div’ section defined earlier. Title of the chart, title for the horizontal axis and dimensions of the chart are the parameters given to the method.
visualization.draw(data,
    {
        title:"Gross Agricultural Production of Country X", 
        width:600, 
        height:400,
        hAxis: {
            title: "Year"
        }
    }
);

Note: If the above method is used DataTable object (data) should be compatible with chart type being used. Therefore Spreadsheet data has been formatted to be compatible with the Column Chart in Google Charts. So the first column contains years as plain text. Also the column headers are of string type. Also this can be achieved by creating a new DataTable object using the older object according to the required format, inside the Gadget Source.
  
Final Step: Creating the div element for the chart

Finally a div element should be defined to draw the chart as follows.
<body style="font-family: Arial;border: 0 none;">
    <div id="visualization" style="height: 400px; width: 400px;"></div>
</body>

The complete gadget source is as follows.
<?xml version="1.0" encoding="UTF-8"?>
<Module>
    <ModulePrefs title="Google Spredsheet Sample Gadget"
                 description="A Gadget which uses a Google Spreadsheet as a Data Source"
                 author="Sumedha" author_email="sumedhas@wso2.com"
                 author_link="http://www.wso2.org/"
                 title_url="http://www.wso2.org/"
                 height="400">
        <Require feature="dynamic-height"/>
    </ModulePrefs>
    <Content type="html"><![CDATA[
        <script type="text/javascript" src="http://www.google.com/jsapi"></script>
        <script type="text/javascript">
            google.load('visualization', '1', {packages: ['corechart']});
        </script>
        <script type="text/javascript">
            gadgets.util.registerOnLoadHandler(querySpreadsheet);

            function querySpreadsheet() {
                var query = new google.visualization.Query('https://docs.google.com/spreadsheet/ccc?key=0Aio3Y5QAMdBBdHU2R0hfcXkwSlNBbFhQeTMzX25VLVE&hl=en_US');
                // Send the query with a callback function.
                query.send(handleQueryResponse);
            }
    
            function handleQueryResponse(response) {
                if (response.isError()) {
                    alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
                    return;
                }
                var data = response.getDataTable();
                var visualization = new google.visualization.ColumnChart(document.getElementById('visualization'));
                visualization.draw(data,
                                    {title:"Gross Aggricultural Production of Country X",
                                    width:450, height:400,
                                    hAxis: {title: "Year"}}
                                );
            }      
        </script>
        <body style="font-family: Arial;border: 0 none;">
            <div id="visualization" style="height: 400px; width: 400px;"></div>
        </body>
  ]]>
    </Content>
</Module>

Using this link the gadget can be added directly to the portal.


The completed gadget looks as follows.