rea-netscaler-cli 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ netscaler-cli (0)
5
+ choosy (>= 0.4.8)
6
+ highline (>= 1.6)
7
+ json_pure (>= 1.5.1)
8
+ log4r (>= 1.1.9)
9
+ savon (>= 0.7.9)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ ZenTest (4.5.0)
15
+ autotest (4.4.6)
16
+ ZenTest (>= 4.4.1)
17
+ autotest-notification (2.3.1)
18
+ autotest (~> 4.3)
19
+ builder (3.0.0)
20
+ choosy (0.4.9)
21
+ diff-lcs (1.1.2)
22
+ gyoku (0.4.4)
23
+ builder (>= 2.1.2)
24
+ highline (1.6.2)
25
+ httpi (0.9.4)
26
+ pyu-ntlm-http (>= 0.1.3.1)
27
+ rack
28
+ json_pure (1.5.1)
29
+ log4r (1.1.9)
30
+ nokogiri (1.4.4)
31
+ nori (0.2.3)
32
+ pyu-ntlm-http (0.1.3.1)
33
+ rack (1.3.0)
34
+ rspec (2.5.0)
35
+ rspec-core (~> 2.5.0)
36
+ rspec-expectations (~> 2.5.0)
37
+ rspec-mocks (~> 2.5.0)
38
+ rspec-core (2.5.1)
39
+ rspec-expectations (2.5.0)
40
+ diff-lcs (~> 1.1.2)
41
+ rspec-mocks (2.5.0)
42
+ savon (0.9.2)
43
+ builder (>= 2.1.2)
44
+ gyoku (>= 0.4.0)
45
+ httpi (>= 0.7.8)
46
+ nokogiri (>= 1.4.0)
47
+ nori (>= 0.2.0)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ ZenTest
54
+ autotest
55
+ autotest-notification
56
+ netscaler-cli!
57
+ rspec
@@ -0,0 +1,37 @@
1
+ # Netscaler CLI
2
+
3
+ This is a simple command line interface for accessing a Netscaler load balancer. It is currently alpha software, so use with caution.
4
+
5
+ # Installing
6
+
7
+ The command line tools can be installed with:
8
+
9
+ gem install netscaler-cli
10
+
11
+ # Using
12
+
13
+ The following commands are currently a part of the system:
14
+
15
+ * *netscaler vserver* -- An interface for enabling, disabling, querying, and binding responder policies to a specific virtual server.
16
+ * *netscaler service* -- An interface for enabling, disabling, querying, and binding servers to specific services.
17
+ * *netscaler server* -- An interface for enabling, disabling, querying, and binding servers to virtual servers.
18
+
19
+ Each command requires at least the --netscaler flag (which can be the full netscaler host name in the configuration file, or its alias, see below).
20
+
21
+ # Configuration
22
+
23
+ All of the commands rely upon a configuration file in the YAML format. By default, it looks for a file in your home directory
24
+
25
+ ~/.netscaler-cli.yml
26
+
27
+ Each load balancer requires an entry in the file in the form:
28
+
29
+ netscaler.loadbalancer.somecompany.com:
30
+ username: 'some.username'
31
+ password: 'super!duper!secret!'
32
+ alias: prod
33
+ version: '9.2'
34
+
35
+ Multiple entries can be in the file; the password and the alias settings are not required. An alias can be used as a shortcut name on the command line for a particular netscaler server. However, if no password is given in the file for a given configuration, the tool will ask you for it.
36
+
37
+ The version information is optional, but breaking API changes were introduced in version 9.2 of Netscaler software, so some commands may fail if this isn't set for this Netscaler software version.
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift File.expand_path("../spec", __FILE__)
3
+
4
+ require 'fileutils'
5
+ require 'rake'
6
+ require 'rubygems'
7
+ require 'rspec/core/rake_task'
8
+ require 'choosy/rake'
9
+
10
+ task :default => :spec
11
+
12
+ desc "Run the RSpec tests"
13
+ RSpec::Core::RakeTask.new :spec
14
+
15
+ desc "Cleans the gem files up."
16
+ task :clean => ['gem:clean']
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'netscaler/cli'
5
+ Netscaler::CLI.new(ARGV).execute!
@@ -0,0 +1,6 @@
1
+ ---
2
+ date: 10/06/2011
3
+ version:
4
+ tiny: 8
5
+ major: 0
6
+ minor: 5
@@ -0,0 +1,52 @@
1
+ require 'netscaler/logging'
2
+
3
+ module Netscaler
4
+ class BaseRequest
5
+ include Netscaler::Logging
6
+
7
+ attr_reader :client
8
+
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ protected
14
+ def send_request(name, params, &block)
15
+ if params.nil? || params.empty?
16
+ raise Netscaler::TransactionError.new("The parameters were empty.")
17
+ end
18
+
19
+ params.delete(:empty)
20
+
21
+ log.debug("Calling: #{name}")
22
+
23
+ result = client.request name do
24
+ soap.namespace = Netscaler::NSCONFIG_NAMESPACE
25
+ soap.input = name
26
+ body = Hash.new
27
+ params.each do |k,v|
28
+ body[k.to_s] = v
29
+ end
30
+ soap.body = body
31
+ end
32
+
33
+ if log.debug?
34
+ require 'pp'
35
+ PP::pp(result.to_hash, $stderr, 80)
36
+ end
37
+
38
+ response = result.to_hash["#{name.to_s}_response".to_sym]
39
+ msg = response[:return][:message]
40
+ if msg !~ /^Done$/
41
+ log.error(response[:return][:message])
42
+ exit(1)
43
+ elsif block_given?
44
+ yield response
45
+ else
46
+ log.debug(msg)
47
+ end
48
+
49
+ result
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,246 @@
1
+ require 'netscaler/errors'
2
+ require 'netscaler/config'
3
+ require 'netscaler/executor'
4
+ require 'netscaler/server/request'
5
+ require 'netscaler/vserver/request'
6
+ require 'netscaler/service/request'
7
+ require 'netscaler/servicegroup/request'
8
+ require 'choosy'
9
+
10
+ module Netscaler
11
+ class CLI
12
+
13
+ def initialize(args)
14
+ @args = args.dup
15
+ end
16
+
17
+ def parse!(propagate=nil)
18
+ command.parse!(@args, propagate)
19
+ end
20
+
21
+ def execute!
22
+ begin
23
+ command.execute!(@args)
24
+ rescue SystemExit
25
+ raise
26
+ rescue Netscaler::ConfigurationError => e
27
+ print_error(e.message)
28
+ exit 1
29
+ rescue Exception => e
30
+ STDERR.puts e.backtrace
31
+ print_error(e.message)
32
+ exit 1
33
+ end
34
+ end
35
+
36
+ protected
37
+ def command
38
+ cmds = [vservers, servers, services, servicegroups]
39
+ @command ||= Choosy::SuperCommand.new :netscaler do
40
+ printer :standard, :color => true, :headers => [:bold, :blue], :max_width => 80
41
+
42
+ summary "This is a command line tool for interacting with Netscaler load balancer"
43
+ heading 'Description:'
44
+ para "There are several subcommands to do various things with the load balancer. Try 'netscaler help SUBCOMMAND' for more information about the particular command you want to use."
45
+ para "Note that you can supply a configuration file, which would normally be found under ~/.netscaler-cli.yml. That file describes the relationship between your Netscaler load balancers and the aliases, usernames, and passwords that you supply for them. The file is in the general format:"
46
+ para " netscaler.host.name.com:
47
+ alias: is_optional
48
+ usernamd: is_required
49
+ password: is_optional_but_querried_if_not_found"
50
+
51
+ # COMMANDS
52
+ heading 'Commands:'
53
+ cmds.each do |cmd|
54
+ command cmd
55
+ end
56
+ para
57
+ command :help
58
+
59
+ # OPTIONS
60
+ heading 'Global Options:'
61
+ string :netscaler, "The IP Address, hostname, or alias in the config file of the Netscaler load balancer. This is required." do
62
+ depends_on :config
63
+ required
64
+
65
+ validate do |arg, options|
66
+ reader = Netscaler::ConfigurationReader.new(options[:config])
67
+ config = reader[arg]
68
+ if config.nil?
69
+ die "the Netscaler address '#{arg}' is not defined in the configuration file"
70
+ else
71
+ options[:netscaler] = config
72
+ end
73
+ end
74
+ end
75
+ yaml :config, "The path to the netscaler configuration file. By default, it is ~/.netscaler-cli.yml" do
76
+ default File.join(ENV['HOME'], '.netscaler-cli.yml')
77
+ end
78
+
79
+ heading 'Informative:'
80
+ boolean_ :debug, "Print extra debug information"
81
+ boolean_ :json, "Prints out JSON instead of textual data"
82
+ help
83
+ version Choosy::Version.load_from_parent.to_s
84
+ end
85
+ end#command
86
+
87
+ def servers
88
+ Choosy::Command.new :server do |s|
89
+ executor Netscaler::Executor.new(Netscaler::Server::Request)
90
+ summary "Enables, disbles, or lists servers in the load balancer"
91
+ heading 'Description:'
92
+ para "This is a tool for enabling and disabling a server in a Netscaler load balancer. The name of the server is required, as is the address of the Netscaler load balancer."
93
+ para "By default, this command will tell you what the current status of the server is."
94
+ para "If you want to list all of the services, use the --list flag."
95
+
96
+ heading 'Options:'
97
+ enum :action, [:enable, :disable, :list, :status], "Either [enable, disable, list]. 'list' will ignore additional arguments. Default action is 'status'" do
98
+ default :status
99
+ end
100
+ arguments do
101
+ count 0..1 #:at_least => 0, :at_most => 1
102
+ metaname '[SERVER]'
103
+ validate do |args, options|
104
+ if args.length == 0
105
+ die "no server given to act upon" unless options[:action] == :list
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def vservers
113
+ Choosy::Command.new :vserver do
114
+ executor Netscaler::Executor.new(Netscaler::VServer::Request)
115
+ summary "Enables, disables, binds or unbinds policies, or lists virtual servers."
116
+ heading 'Description:'
117
+ para "This is a tool for acting upon virtual servers (VIPs) in a Netscaler load balancer. The name of the virtual server is required."
118
+ para "By default, this command will tell you what the current status of the server is."
119
+ para "If you want to list all of the virtual servers, use the --list flag."
120
+
121
+ heading 'Options:'
122
+ enum :action, [:enable, :disable, :list, :bind, :unbind, :status], "Either [enable, disable, list, bind, unbind, status]. 'bind' and 'unbind' require the additional '--policy' flag. 'list' will ignore additional arguments. Default action is 'status'." do
123
+ default :status
124
+ end
125
+ string :policy, "The name of the policy to bind/unbind." do
126
+ depends_on :action
127
+ default :unset
128
+ validate do |arg, options|
129
+ if [:bind, :unbind].include?(options[:action])
130
+ die "required by the 'bind/unbind' actions" if arg == :unset
131
+ else
132
+ die "only used with bind/unbind" unless arg == :unset
133
+ end
134
+ end
135
+ end
136
+ integer :Priority, "The integer priority of the policy to bind with. Default is 100." do
137
+ depends_on :action, :policy
138
+ default -1
139
+ validate do |arg, options|
140
+ if options[:action] == :bind
141
+ if arg == -1
142
+ options[:Priority] = 100
143
+ end
144
+ elsif arg != -1
145
+ die "only used with the bind action"
146
+ end
147
+ end
148
+ end
149
+ arguments do
150
+ count 0..1 #:at_least => 0, :at_most => 1
151
+ metaname '[SERVER]'
152
+ validate do |args, options|
153
+ if args.length == 0
154
+ die "no virtual server given to act upon" unless options[:action] == :list
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def services
162
+ Choosy::Command.new :service do
163
+ executor Netscaler::Executor.new(Netscaler::Service::Request)
164
+ summary "Enables, disables, binds or unbinds from a virtual server, a given service."
165
+ heading 'Description:'
166
+ para "This is a tool for enabling and disabling services in a Netscaler load balancer. The name of the service is required, as is the address of the Netscaler load balancer."
167
+
168
+ heading 'Options:'
169
+ enum :action, [:enable, :disable, :bind, :unbind, :status], "Either [enable, disable, bind, unbind, status] of a service. 'bind' and 'unbind' require the '--vserver' flag. Default is 'status'." do
170
+ default :status
171
+ end
172
+ string :vserver, "The virtual server to bind/unbind this service to/from." do
173
+ depends_on :action
174
+ default :unset
175
+ validate do |arg, options|
176
+ if [:bind, :unbind].include?(options[:action])
177
+ die "requires the -v/--vserver flag" if arg == :unset
178
+ else
179
+ die "only used with bind/unbind" unless arg == :unset
180
+ end
181
+ end
182
+ end
183
+ arguments do
184
+ count 0..1 #:at_least => 0, :at_most => 1
185
+ metaname '[SERVICE]'
186
+ validate do |args, options|
187
+ if args.length == 0
188
+ die "no services given to act on" unless options[:action] == :list
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ def servicegroups
196
+ Choosy::Command.new :servicegroup do
197
+ executor Netscaler::Executor.new(Netscaler::ServiceGroup::Request)
198
+ summary "Enables, disables, binds or unbinds from a virtual server, a given service group."
199
+ heading 'Description:'
200
+ para "This is a tool for enabling and disabling service groups in a Netscaler load balancer. The name of the service group is required, as is the address of the Netscaler load balancer."
201
+
202
+ heading 'Options:'
203
+ enum :action, [:enable, :disable, :bind, :unbind, :status], "Either [enable, disable, bind, unbind, status] of a service group. 'bind' and 'unbind' require the '--vserver' flag. Default is 'status'." do
204
+ default :status
205
+ end
206
+ string :vserver, "The virtual server to bind/unbind this service to/from." do
207
+ depends_on :action
208
+ default :unset
209
+ validate do |arg, options|
210
+ if [:bind, :unbind].include?(options[:action])
211
+ die "requires the -v/--vserver flag" if arg == :unset
212
+ else
213
+ die "only used with bind/unbind" unless arg == :unset
214
+ end
215
+ end
216
+ end
217
+ string :servername, "The name of the server that an individual service runs on (used when scoping the action to an individual service in a service group)." do
218
+ depends_on :action
219
+ end
220
+ string :port, "The port number that an individual service in bound to (used when scoping the action to an individual service in a service group)." do
221
+ depends_on :action
222
+ end
223
+ string :delay, "The delay (in seconds) to wait before disabled services transition to Out of Service. Default is 0 seconds (immediately)." do
224
+ depends_on :action
225
+ default "0"
226
+ end
227
+ arguments do
228
+ count 0..1 #:at_least => 0, :at_most => 1
229
+ metaname '[SERVICEGROUP]'
230
+ validate do |args, options|
231
+ if args.length == 0
232
+ die "no service group given to act on" unless options[:action] == :list
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ private
240
+ def print_error(e)
241
+ STDERR.puts "#{File.basename($0)}: #{e}"
242
+ STDERR.puts "Try '#{File.basename($0)} help' for more information"
243
+ exit 1
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,89 @@
1
+ require 'rubygems'
2
+ require 'yaml'
3
+ require 'etc'
4
+ require 'highline/import'
5
+
6
+ module Netscaler
7
+
8
+ class ConfigurationReader
9
+ def initialize(yaml)
10
+ @servers = yaml
11
+ end
12
+
13
+ def [](name)
14
+ # First, try the aliases
15
+ @servers.each_key do |lbname|
16
+ found = @servers[lbname]
17
+ if found['alias'] == name
18
+ return create_config(lbname, found)
19
+ end
20
+ end
21
+
22
+ # Next, check the actual server names
23
+ found = @servers[name]
24
+ if found.nil?
25
+ raise Netscaler::ConfigurationError.new("The specified Netscaler host was not found")
26
+ end
27
+
28
+ return create_config(name, found)
29
+ end
30
+
31
+ def load_balancers
32
+ @servers.keys
33
+ end
34
+
35
+ def self.read_config_file(file)
36
+ if file.nil?
37
+ file = File.expand_path(".netscaler-cli.yml", Etc.getpwuid.dir)
38
+ end
39
+
40
+ if !File.exists?(file)
41
+ raise Netscaler::ConfigurationError.new("Unable to locate the netscaler-cli configuration file")
42
+ end
43
+
44
+ begin
45
+ yaml = File.read(file)
46
+ ConfigurationReader.new(YAML::load(yaml))
47
+ rescue Exception => e
48
+ raise Netscaler::ConfigurationError.new("Unable to load the netscaler-cli configuration file")
49
+ end
50
+ end
51
+
52
+ private
53
+ def create_config(lbname, yaml)
54
+ if yaml['username'].nil?
55
+ raise Netscaler::ConfigurationError.new("No username was specified for the given Netscaler host")
56
+ end
57
+
58
+ Configuration.new(lbname, yaml['username'], yaml['password'], yaml['alias'], yaml['version'])
59
+ end
60
+ end
61
+
62
+ class Configuration
63
+ attr_reader :host, :username, :password, :alias, :version
64
+
65
+ def initialize(host, username, password=nil, nalias=nil, version=nil)
66
+ @host = host
67
+ @username = username
68
+ @password = password
69
+ @alias = nalias
70
+ @version = if version
71
+ version.to_s
72
+ else
73
+ "9.2"
74
+ end
75
+
76
+ query_password
77
+ end
78
+
79
+ def query_password
80
+ if password.nil?
81
+ @password = ask("Netscaler password for host #{host}: ") {|q| q.echo = false }
82
+ end
83
+
84
+ if password.nil? || password.empty?
85
+ raise Netscaler::ConfigurationError.new("Unable to read the Netscaler password.")
86
+ end
87
+ end
88
+ end
89
+ end