netscaler-cli 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/Gemfile +7 -3
  2. data/Gemfile.lock +17 -8
  3. data/README.markdown +6 -3
  4. data/Rakefile +4 -6
  5. data/bin/{netscaler-server → netscaler} +2 -2
  6. data/etc/Version +1 -1
  7. data/lib/netscaler/{baseexecutor.rb → base_request.rb} +3 -4
  8. data/lib/netscaler/cli.rb +201 -0
  9. data/lib/netscaler/config.rb +20 -15
  10. data/lib/netscaler/executor.rb +34 -0
  11. data/lib/netscaler/extensions.rb +47 -0
  12. data/lib/netscaler/server/request.rb +35 -0
  13. data/lib/netscaler/server/response.rb +67 -0
  14. data/lib/netscaler/service/request.rb +42 -0
  15. data/lib/netscaler/service/response.rb +44 -0
  16. data/lib/netscaler/vserver/request.rb +67 -0
  17. data/lib/netscaler/vserver/response.rb +125 -0
  18. data/spec/netscaler/cli_spec.rb +140 -0
  19. data/spec/{config_spec.rb → netscaler/config_spec.rb} +23 -9
  20. data/spec/{configs → netscaler/configs}/bad-yaml.yml +0 -0
  21. data/spec/{configs → netscaler/configs}/missing-username.yml +0 -0
  22. data/spec/{configs → netscaler/configs}/simple-config.yml +2 -1
  23. data/spec/netscaler/extenstions_spec.rb +26 -0
  24. data/spec/{helpers.rb → spec_helpers.rb} +0 -0
  25. metadata +108 -53
  26. data/bin/netscaler-service +0 -5
  27. data/bin/netscaler-vserver +0 -5
  28. data/lib/netscaler/clitemplate.rb +0 -147
  29. data/lib/netscaler/server/cli.rb +0 -60
  30. data/lib/netscaler/server/executor.rb +0 -115
  31. data/lib/netscaler/service/cli.rb +0 -49
  32. data/lib/netscaler/service/executor.rb +0 -82
  33. data/lib/netscaler/vserver/cli.rb +0 -92
  34. data/lib/netscaler/vserver/executor.rb +0 -194
  35. data/spec/server/cli_spec.rb +0 -33
  36. data/spec/service/cli_spec.rb +0 -45
  37. data/spec/vserver/cli_spec.rb +0 -75
data/Gemfile CHANGED
@@ -1,9 +1,13 @@
1
1
  source :rubygems
2
2
 
3
3
  gem 'log4r', '~> 1.1'
4
- gem 'savon', '~> 0.7'
4
+ gem 'savon', '~> 0.7.0'
5
5
  gem 'highline', '>= 1.6'
6
+ gem 'choosy', '~> 0.2'
6
7
 
7
- group :test do
8
- gem 'rspec'
8
+ group :development do
9
+ gem 'rspec', :require => "spec"
10
+ gem 'autotest'
11
+ gem 'autotest-notification'
9
12
  end
13
+
data/Gemfile.lock CHANGED
@@ -1,19 +1,25 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ ZenTest (4.5.0)
5
+ autotest (4.4.6)
6
+ ZenTest (>= 4.4.1)
7
+ autotest-notification (2.3.1)
8
+ autotest (~> 4.3)
4
9
  builder (3.0.0)
10
+ choosy (0.2.3)
5
11
  crack (0.1.8)
6
12
  diff-lcs (1.1.2)
7
13
  highline (1.6.1)
8
14
  log4r (1.1.9)
9
- rspec (2.2.0)
10
- rspec-core (~> 2.2)
11
- rspec-expectations (~> 2.2)
12
- rspec-mocks (~> 2.2)
13
- rspec-core (2.2.1)
14
- rspec-expectations (2.2.0)
15
+ rspec (2.5.0)
16
+ rspec-core (~> 2.5.0)
17
+ rspec-expectations (~> 2.5.0)
18
+ rspec-mocks (~> 2.5.0)
19
+ rspec-core (2.5.1)
20
+ rspec-expectations (2.5.0)
15
21
  diff-lcs (~> 1.1.2)
16
- rspec-mocks (2.2.0)
22
+ rspec-mocks (2.5.0)
17
23
  savon (0.7.9)
18
24
  builder (>= 2.1.2)
19
25
  crack (>= 0.1.4)
@@ -22,7 +28,10 @@ PLATFORMS
22
28
  ruby
23
29
 
24
30
  DEPENDENCIES
31
+ autotest
32
+ autotest-notification
33
+ choosy (~> 0.2)
25
34
  highline (>= 1.6)
26
35
  log4r (~> 1.1)
27
36
  rspec
28
- savon (~> 0.7)
37
+ savon (~> 0.7.0)
data/README.markdown CHANGED
@@ -12,9 +12,9 @@ The command line tools can be installed with:
12
12
 
13
13
  The following commands are currently a part of the system:
14
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.
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
18
 
19
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
20
 
@@ -30,5 +30,8 @@ Each load balancer requires an entry in the file in the form:
30
30
  username: 'some.username'
31
31
  password: 'super!duper!secret!'
32
32
  alias: prod
33
+ version: '9.2'
33
34
 
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.
data/Rakefile CHANGED
@@ -12,17 +12,14 @@ include FileUtils
12
12
  task :default => :spec
13
13
 
14
14
  desc "Run the RSpec tests"
15
- RSpec::Core::RakeTask.new do |t|
16
- t.rspec_opts = ['-b', '-c', '-f', 'p']
17
- t.fail_on_error = false
18
- end
15
+ RSpec::Core::RakeTask.new :spec
19
16
 
20
17
  begin
21
18
  require 'jeweler'
22
19
  Jeweler::Tasks.new do |gem|
23
20
  gem.name = 'netscaler-cli'
24
21
  gem.version = Netscaler::Version.to_s
25
- gem.executables = %W{netscaler-vserver netscaler-service netscaler-server}
22
+ gem.executables = %W{netscaler}
26
23
  gem.summary = 'Simple command line utilities for interacting remotely with a Netscaler load balancer.'
27
24
  gem.description = 'This gem installs several simple command line utilities locally. It uses the NSConfig.wsdl SOAP interface for remote access.'
28
25
  gem.email = ['madeonamac@gmail.com']
@@ -33,8 +30,9 @@ begin
33
30
  gem.add_dependency 'log4r', '>=1.1.9'
34
31
  gem.add_dependency 'savon', '>=0.7.9'
35
32
  gem.add_dependency 'highline', '>=1.6'
33
+ gem.add_dependency 'choosy', '>=0.2.3'
36
34
 
37
- gem.add_development_dependency 'rspec', '>=2.2.0'
35
+ gem.add_development_dependency 'rspec', '>=2.5.0'
38
36
  end
39
37
  rescue LoadError
40
38
  puts "Jeweler or dependencies are not available. Install it with: sudo gem install jeweler"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
3
 
4
- require 'netscaler/server/cli'
5
- Netscaler::Server::CLI.new(ARGV).execute!
4
+ require 'netscaler/cli'
5
+ Netscaler::CLI.new(ARGV).execute!
data/etc/Version CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.4.0
@@ -1,13 +1,12 @@
1
1
  require 'netscaler/logging'
2
2
 
3
3
  module Netscaler
4
- class BaseExecutor
4
+ class BaseRequest
5
5
  include Netscaler::Logging
6
6
 
7
- attr_reader :host, :client, :json
7
+ attr_reader :client
8
8
 
9
- def initialize(host, client)
10
- @host = host
9
+ def initialize(client)
11
10
  @client = client
12
11
  end
13
12
 
@@ -0,0 +1,201 @@
1
+ require 'netscaler/errors'
2
+ require 'netscaler/version'
3
+ require 'netscaler/config'
4
+ require 'netscaler/executor'
5
+ require 'netscaler/server/request'
6
+ require 'netscaler/vserver/request'
7
+ require 'netscaler/service/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 = [servers, vservers, services]
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
+ header '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
+ header 'Commands:'
53
+ cmds.each do |cmd|
54
+ command cmd
55
+ end
56
+ para ''
57
+ help
58
+
59
+ # OPTIONS
60
+ header '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
+ header 'Informative:'
80
+ boolean_ :debug, "Print extra debug information"
81
+ boolean_ :json, "Prints out JSON instead of textual data"
82
+ version Netscaler::Version.to_s
83
+ end
84
+ end#command
85
+
86
+ def servers
87
+ Choosy::Command.new :server do |s|
88
+ executor Netscaler::Executor.new(Netscaler::Server::Request)
89
+ summary "Enables, disbles, or lists servers in the load balancer"
90
+ header 'Description:'
91
+ 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."
92
+ para "By default, this command will tell you what the current status of the server is."
93
+ para "If you want to list all of the services, use the --list flag."
94
+
95
+ header 'Options:'
96
+ enum :action, [:enable, :disable, :list, :status], "Either [enable, disable, list]. 'list' will ignore additional arguments. Default action is 'status'" do
97
+ default :status
98
+ end
99
+ arguments do
100
+ count 0..1 #:at_least => 0, :at_most => 1
101
+ metaname 'SERVER'
102
+ validate do |args, options|
103
+ if args.length == 0
104
+ die "no server given to act upon" unless options[:action] == :list
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def vservers
112
+ Choosy::Command.new :vserver do
113
+ executor Netscaler::Executor.new(Netscaler::VServer::Request)
114
+ summary "Enables, disables, binds or unbinds policies, or lists virtual servers."
115
+ header 'Description:'
116
+ para "This is a tool for acting upon virtual servers (VIPs) in a Netscaler load balancer. The name of the virtual server is required."
117
+ para "By default, this command will tell you what the current status of the server is."
118
+ para "If you want to list all of the virtual servers, use the --list flag."
119
+
120
+ header 'Options:'
121
+ 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
122
+ default :status
123
+ end
124
+ string :policy, "The name of the policy to bind/unbind." do
125
+ depends_on :action
126
+ default :unset
127
+ validate do |arg, options|
128
+ if [:bind, :unbind].include?(options[:action])
129
+ die "required by the 'bind/unbind' actions" if arg == :unset
130
+ else
131
+ die "only used with bind/unbind" unless arg == :unset
132
+ end
133
+ end
134
+ end
135
+ integer :Priority, "The integer priority of the policy to bind with. Default is 100." do
136
+ depends_on :action, :policy
137
+ default -1
138
+ validate do |arg, options|
139
+ if options[:action] == :bind
140
+ if arg == -1
141
+ options[:Priority] = 100
142
+ end
143
+ elsif arg != -1
144
+ die "only used with the bind action"
145
+ end
146
+ end
147
+ end
148
+ arguments do
149
+ count 0..1 #:at_least => 0, :at_most => 1
150
+ metaname 'SERVER'
151
+ validate do |args, options|
152
+ if args.length == 0
153
+ die "no virtual server given to act upon" unless options[:action] == :list
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ def services
161
+ Choosy::Command.new :service do
162
+ executor Netscaler::Executor.new(Netscaler::Service::Request)
163
+ summary "Enables, disables, binds or unbinds from a virtual server, a given service."
164
+ header 'Description:'
165
+ 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."
166
+
167
+ header 'Options:'
168
+ 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
169
+ default :status
170
+ end
171
+ string :vserver, "The virtual server to bind/unbind this service to/from." do
172
+ depends_on :action
173
+ default :unset
174
+ validate do |arg, options|
175
+ if [:bind, :unbind].include?(options[:action])
176
+ die "requires the -v/--vserver flag" if arg == :unset
177
+ else
178
+ die "only used with bind/unbind" unless arg == :unset
179
+ end
180
+ end
181
+ end
182
+ arguments do
183
+ count 0..1 #:at_least => 0, :at_most => 1
184
+ metaname 'SERVICE'
185
+ validate do |args, options|
186
+ if args.length == 0
187
+ die "no services given to act on" unless options[:action] == :list
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ private
195
+ def print_error(e)
196
+ STDERR.puts "#{File.basename($0)}: #{e}"
197
+ STDERR.puts "Try '#{File.basename($0)} help' for more information"
198
+ exit 1
199
+ end
200
+ end
201
+ end
@@ -6,8 +6,8 @@ require 'highline/import'
6
6
  module Netscaler
7
7
 
8
8
  class ConfigurationReader
9
- def initialize(file=nil)
10
- @servers = read_config_file(file)
9
+ def initialize(yaml)
10
+ @servers = yaml
11
11
  end
12
12
 
13
13
  def [](name)
@@ -32,16 +32,7 @@ module Netscaler
32
32
  @servers.keys
33
33
  end
34
34
 
35
- private
36
- def create_config(lbname, yaml)
37
- if yaml['username'].nil?
38
- raise Netscaler::ConfigurationError.new("No username was specified for the given Netscaler host")
39
- end
40
-
41
- Configuration.new(lbname, yaml['username'], yaml['password'], yaml['alias'])
42
- end
43
-
44
- def read_config_file(file)
35
+ def self.read_config_file(file)
45
36
  if file.nil?
46
37
  file = File.expand_path(".netscaler-cli.yml", Etc.getpwuid.dir)
47
38
  end
@@ -52,21 +43,35 @@ module Netscaler
52
43
 
53
44
  begin
54
45
  yaml = File.read(file)
55
- return YAML::load(yaml)
46
+ ConfigurationReader.new(YAML::load(yaml))
56
47
  rescue Exception => e
57
48
  raise Netscaler::ConfigurationError.new("Unable to load the netscaler-cli configuration file")
58
49
  end
59
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
60
  end
61
61
 
62
62
  class Configuration
63
- attr_reader :host, :username, :password, :alias
63
+ attr_reader :host, :username, :password, :alias, :version
64
64
 
65
- def initialize(host, username, password=nil, nalias=nil)
65
+ def initialize(host, username, password=nil, nalias=nil, version=nil)
66
66
  @host = host
67
67
  @username = username
68
68
  @password = password
69
69
  @alias = nalias
70
+ @version = if version
71
+ version.to_s
72
+ else
73
+ "9.2"
74
+ end
70
75
 
71
76
  query_password
72
77
  end
@@ -0,0 +1,34 @@
1
+ require 'netscaler/errors'
2
+ require 'netscaler/logging'
3
+ require 'netscaler/transaction'
4
+ require 'netscaler/extensions'
5
+
6
+ module Netscaler
7
+ class Executor
8
+
9
+ def initialize(request_class)
10
+ @request_class = request_class
11
+ end
12
+
13
+ def execute!(args, options)
14
+ Netscaler::Logging.configure(options[:debug])
15
+
16
+ Netscaler::Transaction.new options[:netscaler] do |client|
17
+ @request_class.new(client).send(options[:action], args[0], options) do |response|
18
+ if options[:json]
19
+ puts response.to_json
20
+ else
21
+ if response.is_a?(Array)
22
+ if response.length > 0
23
+ puts response[0].header
24
+ end
25
+ else
26
+ puts response.header
27
+ end
28
+ puts response.to_s
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end