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 +2 -0
- data/Gemfile.lock +57 -0
- data/README.markdown +37 -0
- data/Rakefile +16 -0
- data/bin/netscaler +5 -0
- data/lib/VERSION.yml +6 -0
- data/lib/netscaler/base_request.rb +52 -0
- data/lib/netscaler/cli.rb +246 -0
- data/lib/netscaler/config.rb +89 -0
- data/lib/netscaler/errors.rb +7 -0
- data/lib/netscaler/executor.rb +28 -0
- data/lib/netscaler/logging.rb +47 -0
- data/lib/netscaler/server/request.rb +35 -0
- data/lib/netscaler/server/response.rb +114 -0
- data/lib/netscaler/service/request.rb +42 -0
- data/lib/netscaler/service/response.rb +36 -0
- data/lib/netscaler/servicegroup/request.rb +46 -0
- data/lib/netscaler/servicegroup/response.rb +78 -0
- data/lib/netscaler/transaction.rb +68 -0
- data/lib/netscaler/vserver/request.rb +67 -0
- data/lib/netscaler/vserver/response.rb +115 -0
- data/spec/netscaler/cli_spec.rb +204 -0
- data/spec/netscaler/config_spec.rb +63 -0
- data/spec/netscaler/configs/bad-yaml.yml +2 -0
- data/spec/netscaler/configs/missing-username.yml +2 -0
- data/spec/netscaler/configs/simple-config.yml +8 -0
- data/spec/spec_helpers.rb +9 -0
- metadata +228 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'netscaler/logging'
|
2
|
+
require 'netscaler/base_request'
|
3
|
+
require 'netscaler/vserver/response'
|
4
|
+
|
5
|
+
module Netscaler::VServer
|
6
|
+
class Request < Netscaler::BaseRequest
|
7
|
+
include Netscaler::Logging
|
8
|
+
|
9
|
+
def enable(vserver, options)
|
10
|
+
params = { :name => vserver }
|
11
|
+
send_request('enablelbvserver', params)
|
12
|
+
end
|
13
|
+
|
14
|
+
def disable(vserver, options)
|
15
|
+
params = { :name => vserver }
|
16
|
+
send_request('disablelbvserver', params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def list(vserver, options)
|
20
|
+
vservers = []
|
21
|
+
send_request('getlbvserver', {:empty => :ok}) do |response|
|
22
|
+
response[:return][:list][:item].each do |vserver|
|
23
|
+
vservers << Response.new(vserver).to_hash
|
24
|
+
end
|
25
|
+
end
|
26
|
+
yield vservers if block_given?
|
27
|
+
end
|
28
|
+
|
29
|
+
def status(vserver, options)
|
30
|
+
params = { :name => vserver }
|
31
|
+
send_request('getlbvserver', params) do |response|
|
32
|
+
yield Response.new(response).to_hash if block_given?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def bind(vserver, options)
|
37
|
+
params = {
|
38
|
+
:name => vserver,
|
39
|
+
:policyname => options[:policy],
|
40
|
+
:priority => options[:Priority],
|
41
|
+
:gotopriorityexpression => 'END'
|
42
|
+
}
|
43
|
+
|
44
|
+
method = if options[:netscaler].version == "9.2"
|
45
|
+
'bindlbvserver'
|
46
|
+
else
|
47
|
+
'bindlbvserver_policy'
|
48
|
+
end
|
49
|
+
send_request(method, params)
|
50
|
+
end
|
51
|
+
|
52
|
+
def unbind(vserver, options)
|
53
|
+
params = {
|
54
|
+
:name => vserver,
|
55
|
+
:policyname => options[:policy],
|
56
|
+
:type => 'REQUEST'
|
57
|
+
}
|
58
|
+
|
59
|
+
method = if options[:netscaler].version == "9.2"
|
60
|
+
'unbindlbvserver'
|
61
|
+
else
|
62
|
+
'unbindlbvserver_policy'
|
63
|
+
end
|
64
|
+
send_request(method, params)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Netscaler::VServer
|
2
|
+
class Response
|
3
|
+
def initialize(raw_response)
|
4
|
+
@info = if raw_response[:return]
|
5
|
+
raw_response[:return][:list][:item]
|
6
|
+
else
|
7
|
+
raw_response
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
@info[:name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def ip_address
|
16
|
+
if @info[:ipaddress] =~ /0\.0\.0\.0/
|
17
|
+
@info[:ipaddress2]
|
18
|
+
else
|
19
|
+
@info[:ipaddress]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def type
|
24
|
+
@info[:servicetype]
|
25
|
+
end
|
26
|
+
|
27
|
+
def port
|
28
|
+
@info[:port].to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def state
|
32
|
+
@info[:state]
|
33
|
+
end
|
34
|
+
|
35
|
+
def services
|
36
|
+
@parsed_services ||= []
|
37
|
+
return @parsed_services if !@parsed_services.empty? || @info[:servicename].nil?
|
38
|
+
|
39
|
+
if @info[:servicename][:item].is_a?(String)
|
40
|
+
@parsed_services << ServiceInfo.new(@info, nil)
|
41
|
+
else
|
42
|
+
@info[:servicename][:item].each_with_index do |name, i|
|
43
|
+
@parsed_services << ServiceInfo.new(@info, i)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@parsed_services
|
48
|
+
end
|
49
|
+
|
50
|
+
def service_groups
|
51
|
+
@service_groups ||= if @info[:servicegroupname] && @info[:servicegroupname][:item]
|
52
|
+
groups = @info[:servicegroupname][:item]
|
53
|
+
if groups.is_a?(Array)
|
54
|
+
groups
|
55
|
+
else
|
56
|
+
[groups]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
[]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_hash
|
64
|
+
hash = { :name => name,
|
65
|
+
:ip_address => ip_address,
|
66
|
+
:state => state,
|
67
|
+
:port => port,
|
68
|
+
:type => type,
|
69
|
+
}
|
70
|
+
|
71
|
+
if !services.empty?
|
72
|
+
hash[:services] = services.map {|s| s.to_hash}
|
73
|
+
end
|
74
|
+
|
75
|
+
if !service_groups.empty?
|
76
|
+
hash[:service_groups] = service_groups
|
77
|
+
end
|
78
|
+
|
79
|
+
hash
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class ServiceInfo
|
84
|
+
attr_accessor :name, :ip_address, :state, :type
|
85
|
+
|
86
|
+
def initialize(raw_response, index)
|
87
|
+
@name = raw_response[:servicename][:item]
|
88
|
+
@ip_address = raw_response[:svcipaddress][:item]
|
89
|
+
@state = raw_response[:svcstate][:item]
|
90
|
+
@port = raw_response[:svcport][:item]
|
91
|
+
@type = raw_response[:svctype][:item]
|
92
|
+
|
93
|
+
if !index.nil?
|
94
|
+
@name = @name[index]
|
95
|
+
@ip_address = @ip_address[index]
|
96
|
+
@state = @state[index]
|
97
|
+
@port = @port[index]
|
98
|
+
@type = @type[index]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def port
|
103
|
+
@port.to_i
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_hash
|
107
|
+
{ :name => name,
|
108
|
+
:ip_address => ip_address,
|
109
|
+
:state => state,
|
110
|
+
:port => port,
|
111
|
+
:type => type
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'spec_helpers'
|
2
|
+
require 'netscaler/cli'
|
3
|
+
|
4
|
+
module Netscaler
|
5
|
+
|
6
|
+
module CLIHelper
|
7
|
+
def parse(*args)
|
8
|
+
args << '-c'
|
9
|
+
args << File.join(File.dirname(__FILE__), 'configs', 'simple-config.yml')
|
10
|
+
cli = CLI.new(args)
|
11
|
+
cli.parse!(true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe CLI do
|
16
|
+
include CLIHelper
|
17
|
+
|
18
|
+
it "should fail when the netscaler alias doesn't exist" do
|
19
|
+
attempting {
|
20
|
+
parse('-n', 'asdf', 'server', '--action', 'list')
|
21
|
+
}.should raise_error(Netscaler::ConfigurationError, /host was not found/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be able to set the netscaler configuration correctly" do
|
25
|
+
res = parse('-n', 'else', 'server', '--action', 'list')
|
26
|
+
res.options[:netscaler].password.should eql('blah')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set the json flag correctly" do
|
30
|
+
res = parse('-n', 'else', 'server', '--action', 'list', '--json')
|
31
|
+
res.options[:json].should be(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should set the debug flag correctly" do
|
35
|
+
res = parse('-n', 'else', 'server', '-a', 'list', '--debug')
|
36
|
+
res.options[:debug].should be(true)
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "for servers" do
|
40
|
+
it "should fail when the server is not given to a non-list action" do
|
41
|
+
attempting {
|
42
|
+
parse('-n', 'else', 'server', '-a', 'status')
|
43
|
+
}.should raise_error(Choosy::ValidationError, /no server given/)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should succeed when given the list action with no arguments" do
|
47
|
+
res = parse('-n', 'else', 'server', '-a', 'list')
|
48
|
+
res.subresults[0][:action].should eql(:list)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should have the server argument on a non-list action" do
|
52
|
+
res = parse('-n', 'else', 'server', '-a', 'status', 'blarg')
|
53
|
+
res.subresults[0].args[0].should eql('blarg')
|
54
|
+
res.subresults[0][:action].should eql(:status)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "for vserver" do
|
59
|
+
it "should fail when the vserver is given to a non-list option" do
|
60
|
+
attempting {
|
61
|
+
parse('-n', 'else', 'vserver', '-a', 'disable')
|
62
|
+
}.should raise_error(Choosy::ValidationError, /no virtual server/)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should fail when the --policy flag is unset on a bind/unbind" do
|
66
|
+
attempting {
|
67
|
+
parse('-n', 'else', 'vserver', '-a', 'bind', 'vserv')
|
68
|
+
}.should raise_error(Choosy::ValidationError, /required by the 'bind\/unbind' actions/)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should fail when the --policy flag is used on anything other than bind/unbind" do
|
72
|
+
attempting {
|
73
|
+
parse('-n', 'else', 'vserver', '-a', 'disable', '-p', 'pol', 'vserv')
|
74
|
+
}.should raise_error(Choosy::ValidationError, /only used with bind/)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should fail when priority flag is used on anything other than a bind" do
|
78
|
+
attempting {
|
79
|
+
parse('-n', 'else', 'vserver', '-a', 'disable', '-P', '20', 'vserv')
|
80
|
+
}.should raise_error(Choosy::ValidationError, /only used with the bind action/)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should set the default value for the priority to 100" do
|
84
|
+
res = parse('-n', 'else', 'vserver', '-a', 'bind', '-p', 'pol', 'vserv')
|
85
|
+
res.subresults[0][:Priority].should eql(100)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should set the policy name" do
|
89
|
+
res = parse('-n', 'else', 'vserver', '-a', 'bind', '-p', 'pol', 'vserv')
|
90
|
+
res.subresults[0][:policy].should eql('pol')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should fail on a bad action" do
|
94
|
+
attempting {
|
95
|
+
parse('-n', 'else', 'vserver', '-a', 'asdf', 'vserv')
|
96
|
+
}.should raise_error(Choosy::ValidationError, /unrecognized value/)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "for services" do
|
101
|
+
it "should fail when the service is given to a non-list action" do
|
102
|
+
attempting {
|
103
|
+
parse('-n', 'else', 'service', '-a', 'disable')
|
104
|
+
}.should raise_error(Choosy::ValidationError, /no services given to act/)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should fail when --vserver flag is used with a non-bind/unbind action" do
|
108
|
+
attempting {
|
109
|
+
parse('-n', 'else', 'service', '-a', 'disable', '-v', 'blarg', 'a-service')
|
110
|
+
}.should raise_error(Choosy::ValidationError, /only used with bind/)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should fail when the --vserver flag is not present with the bind/unbind action" do
|
114
|
+
attempting {
|
115
|
+
parse('-n', 'else', 'service', '-a', 'bind', 'a-service')
|
116
|
+
}.should raise_error(Choosy::ValidationError, /requires the -v\/--vserver flag/)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should succeed in setting the service name as an argument" do
|
120
|
+
res = parse('-n', 'else', 'service', '-a', 'bind', '-v', 'blah', 'a-service')
|
121
|
+
res.subresults[0].args[0].should eql('a-service')
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should succed in setting the vserver name" do
|
125
|
+
res = parse('-n', 'else', 'service', '-a', 'bind', '-v', 'blah', 'a-service')
|
126
|
+
res.subresults[0][:vserver].should eql('blah')
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should succeed in setting the action" do
|
130
|
+
res = parse('-n', 'else', 'service', '-a', 'bind', '-v', 'blah', 'a-service')
|
131
|
+
res.subresults[0][:action].should eql(:bind)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should set the default action to status" do
|
135
|
+
res = parse('-n', 'else', 'service', 'a-service')
|
136
|
+
res.subresults[0][:action].should eql(:status)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "for servicegroups" do
|
141
|
+
it "should fail when the service is given to a non-list action" do
|
142
|
+
attempting {
|
143
|
+
parse('-n', 'else', 'servicegroup', '-a', 'disable')
|
144
|
+
}.should raise_error(Choosy::ValidationError, /no service group given to act/)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should fail when --vserver flag is used with a non-bind/unbind action" do
|
148
|
+
attempting {
|
149
|
+
parse('-n', 'else', 'servicegroup', '-a', 'disable', '-v', 'blarg', 'a-service-group')
|
150
|
+
}.should raise_error(Choosy::ValidationError, /only used with bind/)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should fail when the --vserver flag is not present with the bind/unbind action" do
|
154
|
+
attempting {
|
155
|
+
parse('-n', 'else', 'servicegroup', '-a', 'bind', 'a-service-group')
|
156
|
+
}.should raise_error(Choosy::ValidationError, /requires the -v\/--vserver flag/)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should succeed in setting the service name as an argument" do
|
160
|
+
res = parse('-n', 'else', 'servicegroup', '-a', 'bind', '-v', 'blah', 'a-service-group')
|
161
|
+
res.subresults[0].args[0].should eql('a-service-group')
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should succeed in setting the vserver name" do
|
165
|
+
res = parse('-n', 'else', 'servicegroup', '-a', 'bind', '-v', 'blah', 'a-service-group')
|
166
|
+
res.subresults[0][:vserver].should eql('blah')
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should succeed in setting the action" do
|
170
|
+
res = parse('-n', 'else', 'servicegroup', '-a', 'bind', '-v', 'blah', 'a-service-group')
|
171
|
+
res.subresults[0][:action].should eql(:bind)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should set the default action to status" do
|
175
|
+
res = parse('-n', 'else', 'servicegroup', 'a-service-group')
|
176
|
+
res.subresults[0][:action].should eql(:status)
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "scoping to an individual service" do
|
180
|
+
before :each do
|
181
|
+
@res = parse('-n', 'else', 'servicegroup', '-a', 'enable', 'a-service-group', '-s', 'a-server-name', '-p', '8080', '-d', '180')
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should set the servername to a-server-name" do
|
185
|
+
@res.subresults[0][:servername].should eql('a-server-name')
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should set the port to 8080" do
|
189
|
+
@res.subresults[0][:port].should eql('8080')
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should set the delay to 180" do
|
193
|
+
@res.subresults[0][:delay].should eql('180')
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should set the delay to 0 if not specified" do
|
197
|
+
@res = parse('-n', 'else', 'servicegroup', '-a', 'enable', 'a-service-group', '-s', 'a-server-name', '-p', '8080')
|
198
|
+
@res.subresults[0][:delay].should eql('0')
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helpers'
|
2
|
+
require 'netscaler/config'
|
3
|
+
require 'netscaler/errors'
|
4
|
+
|
5
|
+
module Netscaler
|
6
|
+
|
7
|
+
module ConfigurationHelper
|
8
|
+
def reading(file)
|
9
|
+
actual_file = File.expand_path("./configs/#{file}", File.dirname(__FILE__))
|
10
|
+
Netscaler::ConfigurationReader.read_config_file(actual_file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Configuration Reader" do
|
15
|
+
include ConfigurationHelper
|
16
|
+
|
17
|
+
before :each do
|
18
|
+
@config = reading('simple-config.yml')
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "when reading an existing file" do
|
22
|
+
it "should be able to load the basic config file" do
|
23
|
+
@config.load_balancers.length.should eql(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should set the username and password correctly when set in the file." do
|
27
|
+
ns = @config['something.goes.here']
|
28
|
+
ns.username.should eql('some_user')
|
29
|
+
ns.password.should eql('somepass')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should load via an alias" do
|
33
|
+
ns = @config['else']
|
34
|
+
ns.alias.should eql('else')
|
35
|
+
ns.username.should eql('here')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should set the default version to 9.2" do
|
39
|
+
ns = @config['something.goes.here']
|
40
|
+
ns.version.should eql("9.2")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should read the version if present" do
|
44
|
+
ns = @config['else']
|
45
|
+
ns.version.should eql("9.1")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "when reading a non-existent or bad file" do
|
50
|
+
it "should fail when the config doesn't exist" do
|
51
|
+
attempting { reading('non-config.yml') }.should raise_error(Netscaler::ConfigurationError)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should fail when the config is poorly formed" do
|
55
|
+
attempting { reading('bad-yaml.yml') }.should raise_error(Netscaler::ConfigurationError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should fail when the username is missing" do
|
59
|
+
attempting { reading('missing-username.yml')['load-balancer'] }.should raise_error(Netscaler::ConfigurationError)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|