rea-netscaler-cli 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|