ispunity 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -40,7 +40,6 @@ install the additional dependencies as mentioned.
40
40
 
41
41
  7. Usage
42
42
  ispunity clear_rules # Clear the rules setup by the routing policy
43
- ispunity configfile # Uses the config file provided/passed to the application
44
43
  ispunity help [TASK] # Describe available tasks or one specific task
45
44
  ispunity license # Displays the license
46
45
  ispunity monitor # Start monitoring the isp connections.
@@ -48,4 +47,14 @@ install the additional dependencies as mentioned.
48
47
  ispunity version # Displays the version of Ispunity
49
48
 
50
49
 
51
-
50
+ 8. Starting with Ispunity
51
+ - Follow the following process after successful installation of ispunity
52
+
53
+ i. ispunity setup : This will setup your load balancing using the ispunity configuration file.
54
+ Whenever you will change the configuration file, you need to run this command to take effect.
55
+
56
+ ii. ispunity monitor : This will check for the availability of isp connections. If any connection any network connection is down then it will load balance the network traffic on available connections.
57
+
58
+
59
+ Note : We recommend to add cron job for checking the available network connections. Add following into the crontab :
60
+ */5 * * * * bash -c 'source /etc/profile.d/rvm.sh && /usr/bin/env ruby /usr/local/rvm/gems/ruby-1.9.3-p125/bin/ispunity monitor'
@@ -2,6 +2,7 @@
2
2
  $LOAD_PATH << File.join(File.dirname(__FILE__),'..','lib')
3
3
  require 'thor'
4
4
  require 'isp_unity'
5
+ require 'fileutils'
5
6
 
6
7
  class Ispunity < Thor
7
8
 
@@ -12,16 +13,16 @@ class Ispunity < Thor
12
13
 
13
14
  desc "setup","Setup the application"
14
15
  def setup
15
- puts "Starting the setup application"
16
+ # puts "Starting the setup application"
16
17
  IspUnity.setup
17
18
  end
18
19
 
19
20
  desc "monitor","Start monitoring the isp connections."
20
21
  def monitor
21
- puts "Starting to monitor the application"
22
+ # puts "Starting to monitor the application"
22
23
  IspUnity.monitor
23
24
  end
24
-
25
+ =begin
25
26
  desc "configfile","Uses the config file provided/passed to the application"
26
27
  method_option :configfile, :aliases => "-c", :desc => "Config file"
27
28
  def configfile(file)
@@ -32,14 +33,27 @@ class Ispunity < Thor
32
33
  def clear_rules
33
34
  puts 'Clearing the rules.'
34
35
  end
35
-
36
+ =end
36
37
  desc "license","Displays the license"
37
38
  def license
38
- File.open("../license",'r') do |f|
39
+ File.open("license",'r') do |f|
39
40
  puts f.readlines
40
41
  end
41
42
  end
42
43
 
44
+ desc "copy", "Copies configuration.json.example file under /etc directory as ispunity.json"
45
+ def copy
46
+ puts "\t Configuration.json.example file copied under /etc directory as ispunity.json \n"
47
+ FileUtils.cp(File.join([File.expand_path(File.dirname(__FILE__)), '..', 'config', 'configuration.json.example']), File.join("/etc"))
48
+ File.rename(File.join('/etc', 'configuration.json.example'), File.join('/etc', 'ispunity.json'))
49
+ end
50
+
51
+ desc "cron", "Displays entry for cron tab"
52
+ def cron
53
+ path = `/usr/bin/which ispunity`.chomp
54
+ puts "#Add following line to your crontab to monitor your ISP's for every 5 minutes"
55
+ puts "*/5 * * * * bash -c 'source /etc/profile.d/rvm.sh && /usr/bin/env ruby #{path} monitor"
56
+ end
43
57
  end
44
58
 
45
59
  Ispunity.start
@@ -1,23 +1,23 @@
1
1
  {
2
- "no_of_isp":3,
3
- "status":"balancing",
4
- "interval":300,
5
2
  "public_dns":["8.8.8.8","8.8.4.4","4.2.2.2","4.2.2.1"],
6
3
  "log_level":1,
7
4
  "isp": [
8
5
  {
9
- "id":"isp1",
10
6
  "name":"tata",
11
7
  "interface":"eth0",
12
- "gateway":"61.17.193.1",
8
+ "gateway":"192.168.3.6",
13
9
  "subnet":"255.255.255.0",
14
10
  "network":"61.17.193.0/24",
15
11
  "weight":1,
16
12
  "enabled":"true",
17
13
  "online":"true"
14
+ "protocol":"tcp",
15
+ "port":"80",
16
+ "network_ip":"",
17
+ "skip_sticky_session":true,
18
+ "priority":1
18
19
  },
19
20
  {
20
- "id":"isp2",
21
21
  "name":"ttml",
22
22
  "interface":"eth2",
23
23
  "gateway":"192.168.0.2",
@@ -26,9 +26,13 @@
26
26
  "weight":1,
27
27
  "enabled":"true",
28
28
  "online":"true"
29
+ "protocol":"tcp",
30
+ "port":"80",
31
+ "network_ip":"",
32
+ "skip_sticky_session":true,
33
+ "priority":1
29
34
  },
30
35
  {
31
- "id":"isp3",
32
36
  "name":"bsnl",
33
37
  "interface":"wlan0",
34
38
  "gateway":"192.168.2.1",
@@ -37,6 +41,14 @@
37
41
  "weight":1,
38
42
  "enabled":"false",
39
43
  "online":"true"
44
+ "protocol":"tcp",
45
+ "port":"80",
46
+ "network_ip":"",
47
+ "skip_sticky_session":true,
48
+ "priority":1
49
+
40
50
  }
41
- ]
51
+ ],
52
+ "skip_sticky_session":false,
53
+ "priority_for_sticky":"tata,ttml"
42
54
  }
@@ -31,3 +31,21 @@ dev eth0 weight 1 nexthop via "ip gateway" dev "interface name" weight "weighta
31
31
  ip route flush table cache
32
32
  # If there is only one ISP
33
33
  ip route replace default via "ip gateway" dev "interface name"
34
+
35
+ Commands for Sticky Session:
36
+
37
+ 1) iptables -t mangle -A PREROUTING -s #{source network} -p #{protocol} --dport #{dport} -j MARK --set-mark #{dport}
38
+
39
+ mangle : Table will be used for packet aleternation
40
+ PREROUTING : altering outgoing packets before routing
41
+ source_network : To which network should we need to run the sticky session
42
+ protocol : sticky protocols or non-sticky protocols (either TCP or UDP)
43
+ dport : Destination port (on which destination port that sticky session is working) and we have mark the packet with some value(prefer to use to use dport value as they would be unique)
44
+
45
+ 2) ip rule add fwmark #{port} lookup #{table_name}
46
+
47
+ Depends on port value it tells which ISP will need to lookup
48
+
49
+ 3) ip rule del fwmark #{port} lookup #{table_name}
50
+
51
+ Deletes the rule. After delete the rule we have to add the rule again.
@@ -5,7 +5,7 @@ require "isp_unity/version"
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "ispunity"
8
- s.version = IspUnity::VERSION
8
+ s.version = IspUnity::VERSION
9
9
  s.authors = ["Pratik Shah", "Siva Gollapalli", "Arun Tomar"]
10
10
  s.email = ["pratik14shah@gmail.com", "sivagollapalli@yahoo.com", "arun@solutionenterprises.co.in"]
11
11
  s.homepage = "http://www.ispunity.com"
@@ -15,7 +15,8 @@ Gem::Specification.new do |s|
15
15
  s.add_dependency("i18n")
16
16
  s.add_dependency("json")
17
17
  s.add_dependency("thor")
18
-
18
+ # rspec dependency are added
19
+ s.add_dependency("rspec")
19
20
 
20
21
  s.rubyforge_project = "ispunity"
21
22
 
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env bash
2
+ #------------------------------------------------------------------------------------------
3
+ # Author : Swati A. Rananaware
4
+ # Date : 30-04-2012
5
+ # Purpose : Install Ispunity gem.
6
+ # Description : Install rvm and then ruby 1.9.3. Finally install Ispunity gem.
7
+ # For : Ispunity
8
+ #------------------------------------------------------------------------------------------
9
+
10
+ CYAN="\033[0;36m"
11
+ GREEN="\033[1;34m"
12
+ NOCOLOR="\033[0m"
13
+
14
+ echo -en "$CYAN Please run this script as root user so that all dependencies will be installed through script$NOCOLOR\n\n"
15
+
16
+ if [ -f /etc/redhat-release ]
17
+ then
18
+ yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison iconv-devel
19
+ else
20
+ apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion
21
+ fi
22
+
23
+ if [ "$1" != "--without-rvm" ]
24
+ then
25
+ echo -en "\n$CYAN Gem Ispunity requires ruby 1.9.3.\
26
+ \n By default, this script will install RVM with ruby 1.9.3\
27
+ \n If you have ruby 1.9.3 installed, you can chose to install gem ispunity directly.\
28
+ \n Using $GREEN./ispunity --without-rvm$NOCOLUR $CYAN or Say no for rvm installation below $NOCOLOR\n\n"
29
+ read -p "Do you want to continue to install rvm ?? (y|n) : " ch
30
+ case $ch in
31
+ 'y'|'Y')
32
+ # Install RVM
33
+ echo -en "\n\n$CYAN Installing rvm.........$NOCOLOR\n\n"
34
+ curl -L get.rvm.io | bash -s stable
35
+ source /etc/profile.d/rvm.sh
36
+ #Install ruby 1.9.3
37
+ rvm install 1.9.3-p125
38
+ rvm use 1.9.3-p125;;
39
+
40
+ 'n'|'N')
41
+ ;;
42
+ *)
43
+ echo -en "\n\n$CYAN Wrong Option. Should be 'y' or 'n'"
44
+ echo -en " Exiting the scipt execution$NOCOLOR\n"
45
+ exit;;
46
+ esac
47
+ fi
48
+
49
+ echo -en "\n\n$CYAN Installing ispunity $NOCOLOR\n\n"
50
+
51
+ # Install gem ispunity
52
+ gem install ispunity
53
+
@@ -2,6 +2,7 @@ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
2
2
  require 'json'
3
3
  require 'yaml'
4
4
  require 'isp_unity_log'
5
+ require 'sticky_session'
5
6
  require 'route/route'
6
7
  require 'load_balance/load_balance'
7
8
  require 'system_call'
@@ -38,33 +39,51 @@ module IspUnity
38
39
  IspUnityLog.debug("Route Command: #{route_command}")
39
40
  if SystemCall.execute(route_command)
40
41
  IspUnityLog.info(I18n.t('system_call.execute.route.success'))
42
+
43
+ #RULE COMMAND
41
44
  Rule.build_commands(isp_lists)
42
- rule_command = Rule.commands
45
+ rule_command = Rule.commands
43
46
  IspUnityLog.info(I18n.t('rule.build_commands'))
44
- IspUnityLog.debug("Rule Command: #{rule_command}")
47
+ IspUnityLog.debug("Rule Command: #{rule_command}")
45
48
  SystemCall.execute(rule_command)
46
49
  IspUnityLog.info(I18n.t('system_call.execute.rule.success'))
50
+
51
+ #LOAD BALANCE
47
52
  LoadBalance.build_commands(isp_lists)
48
- load_balance_command = LoadBalance.commands
53
+ load_balance_command = LoadBalance.commands
49
54
  IspUnityLog.info(I18n.t('load_balance.build_commands'))
50
- IspUnityLog.debug("Load Balance Command: #{load_balance_command}")
55
+ IspUnityLog.debug("Load Balance Command: #{load_balance_command}")
51
56
  SystemCall.execute(load_balance_command)
52
57
  IspUnityLog.info(I18n.t('system_call.execute.load_balance.success'))
58
+
59
+ #Sticky Session
60
+ StickySession.execute(isp_lists) if $skip_sticky_session
53
61
  end
54
62
  end
55
63
 
56
64
  def monitor
57
65
  IspUnity.config
58
- new_list = []
66
+ online_isps = []
59
67
  IspUnity.isp_config_list.each do |isp|
60
- new_list << isp if LoadBalance.is_alive(isp)
68
+ online_isps << isp if LoadBalance.is_alive(isp)
61
69
  end
62
- unless new_list == isp_config_list
70
+
71
+ #Failover case
72
+ unless online_isps == isp_config_list
73
+
74
+ #LOAD BALANCE
63
75
  LoadBalance.build_commands(IspUnity.isp_config_list)
64
76
  IspUnityLog.info(I18n.t('load_balance.build_commands'))
65
77
  SystemCall.execute(LoadBalance.commands)
66
78
  IspUnityLog.info(I18n.t('system_call.execute.load_balance.success'))
67
- SystemCall.execute('ip route flush cache')
79
+
80
+ #Flush route
81
+ SystemCall.execute('/sbin/ip route flush cache')
82
+
83
+ #Change sticky session
84
+ offline_isps = isp_lists - online_isps
85
+ StickySession.change_rule(offline_isps, online_isps)
86
+
68
87
  end
69
88
  end
70
89
  end
@@ -1,18 +1,21 @@
1
1
  class Isp
2
2
 
3
- attr_accessor :id, :name, :interface, :gateway, :subnet, :network, :online, :enabled, :ip_address, :weight
3
+ attr_accessor :name, :interface, :gateway, :subnet, :network, :online, :enabled, :ip_address, :weight, :protocol, :port, :network_ip, :priority
4
4
 
5
5
  def initialize(config_isp)
6
- @id = config_isp['id']
7
- @name = config_isp['name']
8
- @interface = config_isp['interface']
9
- @gateway = config_isp['gateway']
10
- @subnet = config_isp['subnet']
11
- @network = config_isp['network']
12
- @online = config_isp["online"]
13
- @enabled = config_isp['enabled']
6
+ @name = config_isp['name']
7
+ @interface = config_isp['interface']
8
+ @gateway = config_isp['gateway']
9
+ @subnet = config_isp['subnet']
10
+ @network = config_isp['network']
11
+ @online = config_isp["online"]
12
+ @enabled = config_isp['enabled']
14
13
  @ip_address = config_isp['ip_address']
15
- @weight = config_isp['weight']
14
+ @weight = config_isp['weight']
15
+ @protocol = config_isp['protocol']
16
+ @port = config_isp['port']
17
+ @network_ip = config_isp['network_ip']
18
+ @priority = config_isp['priority']
16
19
  end
17
20
 
18
21
  end
@@ -10,56 +10,61 @@ module IspUnity
10
10
  attr_reader :isp_config_list
11
11
 
12
12
  def config
13
- begin
14
- configurations = JSON.parse(File.read(ConfigFilePath))
15
- IspUnityLog.info(I18n.t('file.read.success'))
16
- rescue Exception => e
17
- IspUnityLog.debug("#{e}")
18
- IspUnityLog.error(I18n.t('file.read.error'))
19
- raise IspUnityException.new(I18n.t('file.read.error'))
20
- end
13
+ # If file is exists then it reads that otherwise log an error
14
+ if File.exist?(ConfigFilePath)
15
+ begin
16
+ configurations = JSON.parse(File.read(ConfigFilePath))
17
+ IspUnityLog.info(I18n.t('file.read.success'))
18
+ rescue Exception => e
19
+ IspUnityLog.debug("#{e}")
20
+ IspUnityLog.error(I18n.t('file.read.error'))
21
+ raise IspUnityException.new(I18n.t('file.read.error'))
22
+ end
21
23
 
22
- @isp_config_list = []
23
- no_of_isp = configurations['no_of_isp']
24
- isp_list = configurations['isp']
25
- $ip_cluster = configurations['public_dns']
24
+ @isp_config_list = []
25
+ isp_list = configurations['isp']
26
+ $ip_cluster = configurations['public_dns']
27
+ $skip_sticky_session = configurations['skip_sticky_session']
28
+ $priority_for_sticky = configurations['priority_for_sticky'].split(',') if configurations['priority_for_sticky']
26
29
 
27
- if no_of_isp
28
- isp_list.each do|data|
29
- if data['enabled'] == 'true'
30
- ip_addr = SystemCall.get_ip(data['interface'].to_s)
31
- if ip_addr
32
- data['ip_address'] = SystemCall.get_ip(data['interface'])
33
- @isp_config_list.push(Isp.new(data))
34
- else
35
- puts I18n.t('no_ip_addr') + data['name']
36
- IspUnityLog.error(I18n.t('no_ip_addr') + data['name'] )
30
+ if isp_list
31
+ isp_list.each do|data|
32
+ if data['enabled'] == 'true'
33
+ ip_addr = SystemCall.get_ip(data['interface'].to_s)
34
+ if ip_addr
35
+ data['ip_address'] = SystemCall.get_ip(data['interface'])
36
+ @isp_config_list.push(Isp.new(data))
37
+ else
38
+ puts I18n.t('no_ip_addr') + data['name']
39
+ IspUnityLog.error(I18n.t('no_ip_addr') + data['name'] )
40
+ end
37
41
  end
38
42
  end
43
+ IspUnityLog.info('Isp Object succesfully created!')
44
+ else
45
+ raise IspUnityException.new(I18n.t('file.enter_isp'))
46
+ IspUnityLog.error(I18n.t('file.read.no_isp_found'))
39
47
  end
40
- IspUnityLog.info('Isp Object succesfully created!')
41
- else
42
- raise IspUnityException.new(I18n.t('file.enter_isp'))
43
- IspUnityLog.error(I18n.t('file.read.no_isp_found'))
44
- end
45
-
46
48
 
47
- routing_table = File.read(RoutingTablePath)
48
- IspUnityLog.info(I18n.t('routing_table.read.success'))
49
- begin
50
- @isp_config_list.each do|isp_list|
51
- unless routing_table.include?(isp_list.name)
52
- File.open(RoutingTablePath, 'a') {|f| f.write("#{rand(100)} #{isp_list.name} \n")}
49
+ routing_table = File.read(RoutingTablePath)
50
+ IspUnityLog.info(I18n.t('routing_table.read.success'))
51
+ begin
52
+ @isp_config_list.each do|isp_list|
53
+ unless routing_table.include?(isp_list.name)
54
+ File.open(RoutingTablePath, 'a') {|f| f.write("#{rand(100)} #{isp_list.name} \n")}
55
+ end
56
+ IspUnityLog.info(I18n.t('isp.created'))
53
57
  end
54
- IspUnityLog.info(I18n.t('isp.created'))
58
+ rescue Exception => e
59
+ IspUnityLog.debug("#{e}")
60
+ IspUnityLog.error(I18n.t('routing_table.read.error'))
61
+ raise IspUnityException.new(I18n.t('routing_table.read.error'))
55
62
  end
56
- rescue Exception => e
57
- IspUnityLog.debug("#{e}")
58
- IspUnityLog.error(I18n.t('routing_table.read.error'))
59
- raise IspUnityException.new(I18n.t('routing_table.read.error'))
63
+ else
64
+ @isp_config_list = []
65
+ puts "Please make ensure that configuration file has copied on /etc dir"
66
+ IspUnityLog.error('Please make ensure that configuration file has copied on /etc dir')
60
67
  end
61
-
62
68
  end
63
69
  end
64
70
  end
65
-
@@ -1,3 +1,3 @@
1
1
  module IspUnity
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -33,11 +33,12 @@ class LoadBalance
33
33
  result = `/bin/ping -c 3 -I #{isp.ip_address} #{$ip_cluster.sample}`
34
34
  if result.match("100% packet loss")
35
35
  IspUnityLog.info("100% packet loss for #{isp.name}")
36
- return false
36
+ isp.online = false
37
37
  else
38
38
  IspUnityLog.info("0% packet loss for #{isp.name}")
39
- return true
39
+ isp.online = true
40
40
  end
41
+ return isp.online
41
42
  end
42
43
 
43
44
  end
@@ -0,0 +1,39 @@
1
+ class StickySession
2
+
3
+ class << self
4
+
5
+ def execute(isps=[])
6
+ isps.each do |isp|
7
+ if isp.skip_sticky_session
8
+ # Mark the outgoing packet with port value
9
+ command = "iptables -t mangle -A PREROUTING -s #{isp.network_ip} -p #{isp.protocol} --dport #{isp.dport} -j MARK --set-mark #{isp.dport}"
10
+ SystemCall.execute(command)
11
+ # Lookup the ISP depends on marked value
12
+ command = "ip rule add fwmark #{isp.port} lookup #{isp.name}"
13
+ SystemCall.execute(command)
14
+ end
15
+ end
16
+ end
17
+
18
+ def change_rule(offline_isps=[], online_isps=[])
19
+ #online_isps consist of online isps
20
+ online_isps.sort! { |a,b| a.priority <=> b.priority }
21
+
22
+ # Remove rule of failed(offline) isp
23
+ offline_isps.each do |isp|
24
+ if isp.skip_sticky_session
25
+ command = "ip rule del fwmark #{isp.port} lookup #{isp.name}"
26
+ end
27
+ end
28
+
29
+ # Add new rule to online isp with high priority
30
+ offline_isps.each do |isp|
31
+ if isp.skip_sticky_session
32
+ command = "ip rule add fwmark #{isp.port} lookup #{online_isps[0].name}"
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ispunity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-05-01 00:00:00.000000000 Z
14
+ date: 2012-06-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: log4r
@@ -77,6 +77,22 @@ dependencies:
77
77
  - - ! '>='
78
78
  - !ruby/object:Gem::Version
79
79
  version: '0'
80
+ - !ruby/object:Gem::Dependency
81
+ name: rspec
82
+ requirement: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
80
96
  description: With IspUnity, you can 1.Use multiple internet connections simultaneously
81
97
  and get all their throughput. 2.Automatic failover on working net connection if
82
98
  any on of the internet connection goes down.
@@ -100,6 +116,7 @@ files:
100
116
  - config/settings.yml
101
117
  - doc/algorithm.txt
102
118
  - isp_unity.gemspec
119
+ - ispunity.sh
103
120
  - lib/isp_unity.rb
104
121
  - lib/isp_unity/isp.rb
105
122
  - lib/isp_unity/routing_table.rb
@@ -108,6 +125,7 @@ files:
108
125
  - lib/load_balance/load_balance.rb
109
126
  - lib/route/route.rb
110
127
  - lib/rule/rule.rb
128
+ - lib/sticky_session.rb
111
129
  - lib/system_call.rb
112
130
  - license
113
131
  - log/isp_unity.log