icontrol 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jose Fernandez (magec)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,9 @@
1
+ # IControl: F5 BigIP SOAP API Client
2
+
3
+ IControl allows you to easily connect to a BigIP F5 load balancer and by means of the SOAP API. You can programmatically do almost the same as in the Web Interface.
4
+
5
+ ## Installing
6
+
7
+ # Install the gem:
8
+ gem install icontrol
9
+
data/README.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ = icontrol
2
+
3
+
4
+ == Note on Patches/Pull Requests
5
+
6
+ * Fork the project.
7
+ * Make your feature addition or bug fix.
8
+ * Add tests for it. This is important so I don't break it in a
9
+ future version unintentionally.
10
+ * Commit, do not mess with rakefile, version, or history.
11
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
12
+ * Send me a pull request. Bonus points for topic branches.
13
+
14
+ == Copyright
15
+
16
+ Copyright (c) 2010 Jose Fernandez (magec). See LICENSE for details.
data/lib/icontrol.rb ADDED
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'icontrol/attributable'
3
+ require 'icontrol/base'
4
+ require 'icontrol/mappings'
5
+ require 'icontrol/common'
6
+ require 'icontrol/statistic_type'
7
+ require 'icontrol/local_lb/profile_http_class'
8
+ require 'icontrol/local_lb/profile_auth'
9
+ require 'icontrol/local_lb/rate_class'
10
+ require 'icontrol/local_lb/snat_pool'
11
+ require 'icontrol/local_lb/common'
12
+ require 'icontrol/local_lb/pool'
13
+ require 'icontrol/local_lb/pool_member'
14
+ require 'icontrol/local_lb/rule'
15
+ require 'icontrol/local_lb/virtual_server'
16
+ require 'icontrol/local_lb/monitor'
17
+ require 'icontrol/local_lb/monitor_rule'
@@ -0,0 +1,36 @@
1
+ module Attributable
2
+
3
+ def self.included(klass)
4
+ klass.class_eval do
5
+ extend ClassMethods
6
+ include InstanceMethods
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+ def set_id_name(id_name)
12
+ @id_name = id_name
13
+ end
14
+
15
+ def id_name
16
+ @id_name
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+ def initialize(attributes)
22
+ id = attributes.delete(self.class.id_name) if attributes && attributes[self.class.id_name]
23
+ @attributes = attributes || {}
24
+ @attributes[:id] ||= id
25
+ end
26
+
27
+ def method_missing(method_name,*args,&block)
28
+ if @attributes && @attributes.has_key?(method_name)
29
+ return @attributes[method_name]
30
+ else
31
+ super
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,197 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'savon'
3
+ require 'net/https'
4
+ require 'digest/md5'
5
+
6
+ # The idea is to create an object proxy to the web service client with the same structure
7
+ # than the IControl stuff
8
+
9
+ module IControl
10
+
11
+ class NotConfiguredException < Exception; end
12
+
13
+ module Common
14
+ class IPPortDefinition
15
+ attr_accessor :address,:port
16
+ def initialize(options)
17
+ @address = options[:address]
18
+ @port = options[:port]
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ class Base
25
+
26
+ def default_body
27
+ { self.class.id_name.to_s + "s" => {:value => [@attributes[:id]] } }
28
+ end
29
+
30
+ # Generic type mapping
31
+ def self.map_response(response)
32
+ response_key = response.keys.first
33
+ if response_key
34
+ if response[response_key].has_key? :return
35
+ return IControl::Mappings.map_object(response[response_key][:return])
36
+ else
37
+ return nil
38
+ end
39
+ else
40
+ raise "Invalid Response #{response.inspect}"
41
+ end
42
+ end
43
+
44
+ def self.find(name)
45
+ return self.find_all if name == :all
46
+ if name == :first
47
+ all = self.find_all
48
+ return all[0] if all.length >0
49
+ end
50
+ if self.get_list.include?(name)
51
+ return self.new(:id => name)
52
+ else
53
+ return nil
54
+ end
55
+ end
56
+
57
+ def self.find_all
58
+ self.get_list.map {|i| self.new(:id => i)}
59
+ end
60
+
61
+ def method_missing(method_name,*args,&block)
62
+
63
+ return super if @attributes.has_key? method_name
64
+
65
+ if self.class.wsdl.operations.keys.include?("get_#{method_name}".to_sym)
66
+ return self.class.send("get_#{method_name}".to_sym) do |soap|
67
+ soap.body = default_body
68
+ end
69
+ end
70
+
71
+ if self.class.wsdl.operations.keys.include?("#{method_name}".to_sym)
72
+ return self.class.send("#{method_name}".to_sym) do |soap|
73
+ soap.body = default_body
74
+ end
75
+ end
76
+
77
+ return super
78
+ end
79
+
80
+ include Attributable
81
+
82
+ end
83
+
84
+ class << self
85
+ attr_accessor :config
86
+ end
87
+
88
+ def self.configured?
89
+ return @config[:user] != "" && @config[:password] != "" && @config[:base_url] != ""
90
+ end
91
+
92
+ @config = {
93
+ :user => "", # username and password
94
+ :password => "",
95
+ :base_url => "", # base url for the web-service (https://example.com/iControl/iControlPortal.cgi)
96
+ :test_mode => false, # When test mode is set, the soap responses are saved (this is done to ease the testing fixtures generation)
97
+ :test_path => File.join(File.dirname(__FILE__),"..","..","spec","fixtures"),
98
+ :test_file_prefix => ""
99
+ }
100
+
101
+ def self.save_test_info(request,response,wsdl,class_name,method_name)
102
+
103
+ request_md5 = Digest::MD5.hexdigest(request)
104
+ request_file_name = request_raw_file_name = File.join(IControl.config[:test_path],"soap","xml","#{class_name}.#{method_name}_#{request_md5}_request")
105
+ response_file_name = response_raw_file_name = File.join(IControl.config[:test_path],"soap","xml","#{class_name}.#{method_name}_#{request_md5}_response")
106
+
107
+ timestamp = Time.now.strftime("%Y%m%d%m%S") + Time.now.usec.to_s
108
+
109
+ while File.exists?(response_file_name + ".xml") || File.exists?(request_file_name + ".xml")
110
+ response_file_name = response_raw_file_name + "." + timestamp
111
+ request_file_name = request_raw_file_name + "." + timestamp
112
+ end
113
+
114
+ File.open(response_file_name + ".xml","w") { |file| file << response.to_xml }
115
+ File.open(request_file_name + ".xml","w") { |file| file << request }
116
+
117
+ wsdl_file_name = File.join(IControl.config[:test_path],"wsdl","xml","#{class_name}.xml")
118
+ unless File.exists?(wsdl_file_name)
119
+ File.open(wsdl_file_name,"w") do |file|
120
+ file << wsdl
121
+ end
122
+ end
123
+ end
124
+
125
+
126
+
127
+ def IControl.const_missing(name)
128
+
129
+ # Whenever we find a new module subclassing IControl we create it
130
+
131
+ modulo = Module.new do
132
+
133
+ # This new module has the ability to automatically create classes when subclassing from it
134
+
135
+ (class << self; self; end).instance_eval do # We do it in the eigenclass
136
+
137
+ define_method("const_missing") do |class_name|
138
+
139
+ # Whenever we are called with a class name we create a new one based on the configuration we have
140
+
141
+ klass = Class.new(IControl::Base) do
142
+
143
+ (class << self; self; end).instance_eval do
144
+
145
+ define_method("client") do
146
+ return @client if @client
147
+ @client = nil
148
+ if IControl.configured?
149
+ @client = Savon::Client.new IControl.config[:base_url] + "?WSDL=#{name.to_s}.#{class_name.to_s}"
150
+ @client.request.basic_auth IControl.config[:user],IControl.config[:password]
151
+ @client.request.http.ssl_client_auth( :verify_mode => OpenSSL::SSL::VERIFY_NONE )
152
+ else
153
+ raise IControl::NotConfiguredException
154
+ end
155
+ return @client
156
+ end
157
+
158
+ # This is done this way cause I need access to name and class_name
159
+ # metaprogramming to cross the scope, don't really like it actually.
160
+ # TODO: Make use of the delegation patern much more clean I think
161
+
162
+ define_method("method_missing") do |method_name,*args,&block|
163
+
164
+ raise IControl::NotConfiguredException unless IControl.configured?
165
+ if client
166
+ if client.wsdl.operations.keys.include?(method_name)
167
+ # When calling a soap method we transparently add the ns
168
+ request = ""
169
+ response = client.send(method_name,*args) do |soap|
170
+ soap.namespaces["xmlns:wsdl"] = "urn:iControl:#{name}/#{class_name}"
171
+ block.call(soap) if block
172
+ request = soap.to_xml
173
+ end
174
+ # In case we save test fixtures
175
+ IControl.save_test_info(request,response, client.wsdl ,"IControl.#{name}.#{class_name}#{IControl.config[:test_file_prefix]}",method_name) if IControl.config[:test]
176
+ return self.map_response(response.to_hash)
177
+ else
178
+ client.send(method_name,*args,&block)
179
+ end
180
+ else
181
+ super(method_name,*args,&block)
182
+ end
183
+ end
184
+ end
185
+ end
186
+ self.const_set(class_name,klass)
187
+ end
188
+ end
189
+ end
190
+ self.const_set(name,modulo)
191
+ end
192
+ end
193
+
194
+ # If we are going to redefine any give class we need to force the const_missing for the
195
+ # initial declaration to be made
196
+
197
+
@@ -0,0 +1,109 @@
1
+
2
+ # This is a helper for defining constants
3
+ module IControl
4
+
5
+ class NoSuchPoolException < Exception; end
6
+ class MethodNotImplementedException < Exception; end
7
+
8
+ module ConstDefiner
9
+
10
+ def self.included(base)
11
+ base.extend(ClassMethods)
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def class_name
17
+ self.name.split("::").last
18
+ end
19
+
20
+ def declare_constants(constants,parent)
21
+ constants.each do |const_name|
22
+ klass = Class.new(parent)
23
+ self.const_set(const_name,klass)
24
+ end
25
+ end
26
+
27
+ def from_string(klass)
28
+ return eval("::#{self}::#{klass}")
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ module Common
35
+
36
+ class VLANFilterList
37
+ attr_accessor :state,:vlans
38
+ def initialize(attributes)
39
+ @state = IControl::Common::EnabledState.from_string(attributes[:state])
40
+ @vlans = [attributes[:vlans][:item]].flatten.compact
41
+ end
42
+
43
+ end
44
+
45
+ class ULong64
46
+ attr_accessor :high,:low
47
+
48
+ def initialize(options)
49
+ @high = options[:high].to_i
50
+ @low = options[:low].to_i
51
+ end
52
+
53
+ def to_f
54
+ retVal = 0.0
55
+ if @high >=0
56
+ retVal = @high << 32 & 0xffff0000
57
+ else
58
+ retVal = ((@high & 0x7fffffff) << 32) + (0x80000000 << 32)
59
+ end
60
+ if @low >=0
61
+ retVal += @low
62
+ else
63
+ retVal += ((@low & 0x7fffffff) + 0x7fffffff)
64
+ end
65
+ return retVal;
66
+ end
67
+
68
+ def to_hash
69
+ return {:high => @high,:low => @low}
70
+ end
71
+
72
+ end
73
+
74
+ class SourcePortBehavior
75
+ include ConstDefiner
76
+ declare_constants [:SOURCE_PORT_PRESERVE,:SOURCE_PORT_PRESERVE_STRICT,:SOURCE_PORT_CHANGE],SourcePortBehavior
77
+ end
78
+
79
+ class EnabledState
80
+ include ConstDefiner
81
+ declare_constants [:STATE_ENABLED,:STATE_DISABLED],EnabledState
82
+ end
83
+
84
+ class TMOSModule
85
+ include ConstDefiner
86
+ declare_constants [:TMOS_MODULE_ASM, :TMOS_MODULE_SAM, :TMOS_MODULE_WAM], TMOSModule
87
+ end
88
+
89
+ class ProtocolType
90
+
91
+ include ConstDefiner
92
+
93
+ valid_consts = [:PROTOCOL_ANY,:PROTOCOL_IPV6,:PROTOCOL_ROUTING,:PROTOCOL_NONE,
94
+ :PROTOCOL_FRAGMENT,:PROTOCOL_DSTOPTS,:PROTOCOL_TCP,:PROTOCOL_UDP,
95
+ :PROTOCOL_ICMP,:PROTOCOL_ICMPV6,:PROTOCOL_OSPF,:PROTOCOL_SCTP]
96
+
97
+ declare_constants valid_consts,ProtocolType
98
+
99
+ end
100
+
101
+ class IPPortDefinition
102
+ attr_accessor :address,:port
103
+ def initialize(options)
104
+ @address = options[:address]
105
+ @port = options[:port]
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,47 @@
1
+ module IControl
2
+ module LocalLB
3
+
4
+ class HardwareAccelerationMode
5
+ include IControl::ConstDefiner
6
+ declare_constants [:HW_ACCELERATION_MODE_NONE, :HW_ACCELERATION_ASSIST, :HW_ACCELERATION_MODE_FULL ], HardwareAccelerationMode
7
+ end
8
+
9
+ class ClonePoolType
10
+ include IControl::ConstDefiner
11
+ declare_constants [ :CLONE_POOL_TYPE_UNDEFINED, :CLONE_POOL_TYPE_CLIENTSIDE, :CLONE_POOL_TYPE_SERVERSIDE ], ClonePoolType
12
+ end
13
+
14
+ class ProfileContextType
15
+ include IControl::ConstDefiner
16
+ declare_constants [ :PROFILE_CONTEXT_TYPE_ALL, :PROFILE_CONTEXT_TYPE_CLIENT, :PROFILE_CONTEXT_TYPE_SERVER], ProfileContextType
17
+ end
18
+
19
+ class SnatType
20
+ include IControl::ConstDefiner
21
+ declare_constants [ :SNAT_TYPE_NONE, :SNAT_TYPE_TRANSLATION_ADDRESS, :SNAT_TYPE_SNATPOOL, :SNAT_TYPE_AUTOMAP ], SnatType
22
+ end
23
+
24
+ class ProfileType
25
+ include IControl::ConstDefiner
26
+
27
+ declare_constants [ :PROFILE_TYPE_TCP, :PROFILE_TYPE_UDP, :PROFILE_TYPE_FTP, :PROFILE_TYPE_FAST_L4,
28
+ :PROFILE_TYPE_HTTP, :PROFILE_TYPE_SERVER_SSL, :PROFILE_TYPE_CLIENT_SSL,
29
+ :PROFILE_TYPE_AUTH, :PROFILE_TYPE_PERSISTENCE, :PROFILE_TYPE_CONNECTION_POOL,
30
+ :PROFILE_TYPE_STREAM, :PROFILE_TYPE_FAST_HTTP, :PROFILE_TYPE_IIOP,
31
+ :PROFILE_TYPE_RTSP, :PROFILE_TYPE_STATISTICS, :PROFILE_TYPE_HTTPCLASS, :PROFILE_TYPE_SCTP,
32
+ :PROFILE_TYPE_INSTANCE, :PROFILE_TYPE_SIPP ], ProfileType
33
+ end
34
+
35
+ class PersistenceMode
36
+ include IControl::ConstDefiner
37
+
38
+ declare_constants [ :PERSISTENCE_MODE_NONE, :PERSISTENCE_MODE_SOURCE_ADDRESS_AFFINITY,
39
+ :PERSISTENCE_MODE_DESTINATION_ADDRESS_AFFINITY, :PERSISTENCE_MODE_COOKIE,
40
+ :PERSISTENCE_MODE_MSRDP, :PERSISTENCE_MODE_SSL_SID, :PERSISTENCE_MODE_SIP,
41
+ :PERSISTENCE_MODE_UIE, :PERSISTENCE_MODE_HASH ], PersistenceMode
42
+
43
+ end
44
+
45
+
46
+ end
47
+ end