netscaler-cli 0.1.1
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/README.markdown +28 -0
- data/Rakefile +56 -0
- data/bin/netscaler-service +5 -0
- data/bin/netscaler-vserver +5 -0
- data/lib/VERSION +1 -0
- data/lib/netscaler/baseexecutor.rb +44 -0
- data/lib/netscaler/clitemplate.rb +135 -0
- data/lib/netscaler/config.rb +70 -0
- data/lib/netscaler/errors.rb +7 -0
- data/lib/netscaler/logging.rb +34 -0
- data/lib/netscaler/service/cli.rb +47 -0
- data/lib/netscaler/service/executor.rb +54 -0
- data/lib/netscaler/transaction.rb +69 -0
- data/lib/netscaler/version.rb +12 -0
- data/lib/netscaler/vserver/cli.rb +50 -0
- data/lib/netscaler/vserver/executor.rb +56 -0
- data/spec/config_spec.rb +43 -0
- data/spec/configs/bad-yaml.yml +2 -0
- data/spec/configs/missing-username.yml +2 -0
- data/spec/configs/simple-config.yml +3 -0
- data/spec/helpers.rb +5 -0
- data/spec/vserver/cli_spec.rb +45 -0
- metadata +155 -0
data/README.markdown
ADDED
@@ -0,0 +1,28 @@
|
|
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-api
|
10
|
+
|
11
|
+
# Using
|
12
|
+
|
13
|
+
The following commands are currently a part of the system:
|
14
|
+
- *netscaler-vserver* -- An interface for enabling, disabling, and binding responder policies to a specific virtual server.
|
15
|
+
|
16
|
+
# Configuration
|
17
|
+
|
18
|
+
All of the commands rely upon a configuration file in the YAML format. By default, it looks for a file in your home directory
|
19
|
+
|
20
|
+
~/.netscape-cli.yml
|
21
|
+
|
22
|
+
Each load balancer requires an entry in the file in the form:
|
23
|
+
|
24
|
+
netscaler.loadbalancer.somecompany.com
|
25
|
+
username: 'some.username'
|
26
|
+
password: 'super!duper!secret!'
|
27
|
+
|
28
|
+
Multiple entries can be in the file; the password setting is not required. If it is not given in the file, the tool will ask you for it.
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
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 'spec/rake/spectask'
|
8
|
+
require 'netscaler/version'
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
|
12
|
+
desc "Run the RSpec tests"
|
13
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
14
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
15
|
+
t.spec_opts = ['-b', '-c', '-f', 'p']
|
16
|
+
t.fail_on_error = false
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'jeweler'
|
21
|
+
Jeweler::Tasks.new do |gem|
|
22
|
+
gem.name = 'netscaler-cli'
|
23
|
+
gem.version = Netscaler::Version.to_s
|
24
|
+
gem.executables = %W{netscaler-vserver netscaler-service}
|
25
|
+
gem.summary = 'Simple command line utilities for interacting remotely with a Netscaler load balancer.'
|
26
|
+
gem.description = 'This gem installs several simple command line utilities locally. It uses the NSConfig.wsdl SOAP interface for remote access.'
|
27
|
+
gem.email = ['madeonamac@gmail.com']
|
28
|
+
gem.authors = ['Gabe McArthur']
|
29
|
+
gem.homepage = 'http://github.com/gabemc/netscaler-cli'
|
30
|
+
gem.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
|
31
|
+
|
32
|
+
gem.add_dependency 'highline', '>=1.5.2'
|
33
|
+
gem.add_dependency 'log4r', '>=1.1.7'
|
34
|
+
gem.add_dependency 'savon', '>=0.7.9'
|
35
|
+
|
36
|
+
gem.add_development_dependency 'rspec', '>=1.3.0'
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
puts "Jeweler or dependencies are not available. Install it with: sudo gem install jeweler"
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Cleans the gem files up."
|
43
|
+
task :clean do
|
44
|
+
FileUtils.rm(Dir.glob('*.gemspec'))
|
45
|
+
FileUtils.rm(Dir.glob('*.gem'))
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Deploys the gem to rubygems.org"
|
49
|
+
task :gem => :release do
|
50
|
+
system("gem build netscaler-cli.gemspec")
|
51
|
+
system("gem push netscaler-cli-#{Netscaler::Version.to_s}.gem")
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Does the full release cycle."
|
55
|
+
task :deploy => [:gem, :clean] do
|
56
|
+
end
|
data/lib/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'netscaler/logging'
|
2
|
+
|
3
|
+
module Netscaler
|
4
|
+
class BaseExecutor
|
5
|
+
include Netscaler::Logging
|
6
|
+
|
7
|
+
attr_reader :host, :client
|
8
|
+
|
9
|
+
def initialize(host, client)
|
10
|
+
@host = host
|
11
|
+
@client = client
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def send_request(name, body_attrs=nil)
|
16
|
+
log.debug("Calling: #{name}")
|
17
|
+
|
18
|
+
result = client.send("#{name}!") do |soap|
|
19
|
+
soap.namespace = Netscaler::NSCONFIG_NAMESPACE
|
20
|
+
|
21
|
+
body = Hash.new
|
22
|
+
|
23
|
+
if !body_attrs.nil?
|
24
|
+
body_attrs.each do |k,v|
|
25
|
+
body[k] = v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
soap.body = body
|
30
|
+
end
|
31
|
+
|
32
|
+
log.debug(result)
|
33
|
+
|
34
|
+
response = result.to_hash["#{name.to_s}_response".to_sym]
|
35
|
+
if block_given?
|
36
|
+
yield response
|
37
|
+
else
|
38
|
+
log.info(response[:return][:message])
|
39
|
+
end
|
40
|
+
|
41
|
+
result
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'netscaler/errors'
|
3
|
+
require 'netscaler/version'
|
4
|
+
require 'netscaler/logging'
|
5
|
+
require 'netscaler/transaction'
|
6
|
+
require 'netscaler/config'
|
7
|
+
|
8
|
+
module Netscaler
|
9
|
+
class CLITemplate
|
10
|
+
attr_reader :options, :args, :host, :cli_type
|
11
|
+
|
12
|
+
def initialize(cli_type, args)
|
13
|
+
@cli_type = cli_type
|
14
|
+
@args = args
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute!
|
18
|
+
parse!(@args.dup)
|
19
|
+
Netscaler::Logging.configure(options[:debug])
|
20
|
+
|
21
|
+
Netscaler::Transaction.new(netscaler_configuration) do |client|
|
22
|
+
action = options[:action].keys[0]
|
23
|
+
args = options[:action][action]
|
24
|
+
executor = create_executor(client)
|
25
|
+
|
26
|
+
if args.nil?
|
27
|
+
executor.send(action)
|
28
|
+
else
|
29
|
+
executor.send(action, args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse!(args)
|
35
|
+
begin
|
36
|
+
parse_options(args)
|
37
|
+
validate_args(args)
|
38
|
+
rescue SystemExit => e
|
39
|
+
raise
|
40
|
+
rescue Netscaler::ConfigurationError => e
|
41
|
+
print_error(e.message)
|
42
|
+
rescue OptionParser::ParseError => e
|
43
|
+
print_error(e.message)
|
44
|
+
rescue Exception => e
|
45
|
+
STDERR.puts e.backtrace
|
46
|
+
print_error(e.message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_options(args)
|
51
|
+
@options ||= {}
|
52
|
+
if @options.empty?
|
53
|
+
@options[:action] = Hash.new
|
54
|
+
end
|
55
|
+
@parsed_options ||= OptionParser.new do |opts|
|
56
|
+
interface_header(opts)
|
57
|
+
interface_configuration(opts)
|
58
|
+
interface_actions(opts)
|
59
|
+
interface_information(opts)
|
60
|
+
end.parse!(args)
|
61
|
+
end
|
62
|
+
|
63
|
+
def interface_configuration(opts)
|
64
|
+
opts.separator " Configuration: "
|
65
|
+
opts.on('-n', '--netscaler NETSCALER_ADDRESS',
|
66
|
+
"The IP or hostname of the Netscaler load balancer.",
|
67
|
+
"This argument is required.") do |n|
|
68
|
+
options[:netscaler] = n
|
69
|
+
end
|
70
|
+
opts.on('-c', '--config CONFIG',
|
71
|
+
"The path to the netscaler-cli configuration file.",
|
72
|
+
"By default, it is ~/.netscaler-cli.yml") do |c|
|
73
|
+
options[:config] = c
|
74
|
+
end
|
75
|
+
opts.separator ""
|
76
|
+
end
|
77
|
+
|
78
|
+
def interface_information(opts)
|
79
|
+
opts.separator " Informative:"
|
80
|
+
opts.on('--debug',
|
81
|
+
"Prints extra debug information") do |d|
|
82
|
+
options[:debug] = d
|
83
|
+
end
|
84
|
+
opts.on('-v', '--version',
|
85
|
+
"Show the version information") do |v|
|
86
|
+
puts "#{File.basename($0)} version: #{Netscaler::Version.to_s}"
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
opts.on('-h', '--help',
|
90
|
+
"Show this help message") do
|
91
|
+
puts opts
|
92
|
+
exit
|
93
|
+
end
|
94
|
+
|
95
|
+
opts.separator ""
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_args(args)
|
99
|
+
if args.length == 0
|
100
|
+
raise Netscaler::ConfigurationError.new("No hosts specified to act on.")
|
101
|
+
elsif args.length != 1
|
102
|
+
raise Netscaler::ConfigurationError.new("Only one #{cli_type} can be acted on at a time.")
|
103
|
+
end
|
104
|
+
|
105
|
+
@host = args[0]
|
106
|
+
|
107
|
+
if options[:action].empty?
|
108
|
+
options[:action][:status] = nil
|
109
|
+
elsif options[:action].keys.length != 1
|
110
|
+
raise Netscaler::ConfigurationError.new("Multiple actions specified -- only one action is supported at a time.")
|
111
|
+
end
|
112
|
+
|
113
|
+
if options[:netscaler].nil?
|
114
|
+
raise Netscaler::ConfigurationError.new("No Netscaler IP/Hostname given.")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def netscaler_configuration
|
119
|
+
reader = Netscaler::ConfigurationReader.new(options[:config])
|
120
|
+
config = reader[options[:netscaler]]
|
121
|
+
if config.nil?
|
122
|
+
raise Netscaler::ConfigurationError.new("The Netscaler address '#{options[:netscaler]}' is not defined in the configuration file")
|
123
|
+
end
|
124
|
+
|
125
|
+
config
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
def print_error(e)
|
130
|
+
STDERR.puts "#{File.basename($0)}: #{e}"
|
131
|
+
STDERR.puts "Try '#{File.basename($0)} --help' for more information"
|
132
|
+
exit 1
|
133
|
+
end
|
134
|
+
end # CLI
|
135
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'etc'
|
4
|
+
require 'highline/import'
|
5
|
+
|
6
|
+
module Netscaler
|
7
|
+
|
8
|
+
class ConfigurationReader
|
9
|
+
def initialize(file=nil)
|
10
|
+
@servers = read_config_file(file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](host)
|
14
|
+
found = @servers[host]
|
15
|
+
if found.nil?
|
16
|
+
raise Netscaler::ConfigurationError.new("The specified Netscaler host was not found")
|
17
|
+
end
|
18
|
+
|
19
|
+
if found['username'].nil?
|
20
|
+
raise Netscaler::ConfigurationError.new("No username was specified for the given Netscaler host")
|
21
|
+
end
|
22
|
+
|
23
|
+
Configuration.new(host, found['username'], found['password'])
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_balancers
|
27
|
+
@servers.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def read_config_file(file)
|
32
|
+
if file.nil?
|
33
|
+
file = File.expand_path(".netscaler-cli.yml", Etc.getpwuid.dir)
|
34
|
+
end
|
35
|
+
|
36
|
+
if !File.exists?(file)
|
37
|
+
raise Netscaler::ConfigurationError.new("Unable to locate the netscaler-cli configuration file")
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
yaml = File.read(file)
|
42
|
+
return YAML::load(yaml)
|
43
|
+
rescue Exception => e
|
44
|
+
raise Netscaler::ConfigurationError.new("Unable to load the netscaler-cli configuration file")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Configuration
|
50
|
+
attr_reader :host, :username, :password
|
51
|
+
|
52
|
+
def initialize(host, username, password=nil)
|
53
|
+
@host = host
|
54
|
+
@username = username
|
55
|
+
@password = password
|
56
|
+
|
57
|
+
query_password
|
58
|
+
end
|
59
|
+
|
60
|
+
def query_password
|
61
|
+
if password.nil?
|
62
|
+
@password = ask("Netscaler password for host #{host}: ") {|q| q.echo = false }
|
63
|
+
end
|
64
|
+
|
65
|
+
if password.nil? || password.empty?
|
66
|
+
raise Netscaler::ConfigurationError.new("Unable to read the Netscaler password.")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'log4r'
|
3
|
+
require 'savon'
|
4
|
+
|
5
|
+
module Netscaler
|
6
|
+
# A convenient module for mixins that allow to
|
7
|
+
# share the logging configuration everywhere
|
8
|
+
# easily
|
9
|
+
module Logging
|
10
|
+
@@log = nil
|
11
|
+
|
12
|
+
def Logging.configure(debug)
|
13
|
+
if @@log.nil?
|
14
|
+
@@log = Log4r::Logger.new 'netscaler'
|
15
|
+
@@log.outputters = Log4r::Outputter.stderr
|
16
|
+
@@log.level = Log4r::WARN
|
17
|
+
Log4r::Outputter.stderr.formatter = Log4r::PatternFormatter.new(:pattern => "[%l] %M")
|
18
|
+
|
19
|
+
@@log.level = debug ? Log4r::DEBUG : Log4r::INFO
|
20
|
+
|
21
|
+
Savon::Request.logger = @@log
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def Logging.log
|
26
|
+
@@log ||= Log4r::Logger.root
|
27
|
+
end
|
28
|
+
|
29
|
+
# Meant for mixing into other classes for simplified logging
|
30
|
+
def log
|
31
|
+
@@log ||= Log4r::Logger.root
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'netscaler/clitemplate'
|
2
|
+
require 'netscaler/service/executor'
|
3
|
+
|
4
|
+
module Netscaler::Service
|
5
|
+
class CLI < Netscaler::CLITemplate
|
6
|
+
def initialize(args)
|
7
|
+
super('service', args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_executor(client)
|
11
|
+
Netscaler::Service::Executor.new(host, client)
|
12
|
+
end
|
13
|
+
|
14
|
+
def interface_header(opts)
|
15
|
+
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] SERVICE"
|
16
|
+
opts.separator <<DESC
|
17
|
+
Description:
|
18
|
+
This is a tool for enabling and disabling services in a Netscaler
|
19
|
+
load balancer. The name of the service is required, as is the
|
20
|
+
address of the Netscaler load balancer.
|
21
|
+
|
22
|
+
Options:
|
23
|
+
DESC
|
24
|
+
end
|
25
|
+
|
26
|
+
def interface_actions(opts)
|
27
|
+
opts.separator " Actions: "
|
28
|
+
opts.on('-e', '--enable',
|
29
|
+
"Enables the given service.") do |e|
|
30
|
+
options[:action][:enable] = nil
|
31
|
+
end
|
32
|
+
opts.on('-d', '--disable',
|
33
|
+
"Disables the given service.") do |d|
|
34
|
+
options[:action][:disable] = nil
|
35
|
+
end
|
36
|
+
opts.on('-b', '--bind VSERVER',
|
37
|
+
"Binds a service to a virtual server.") do |b|
|
38
|
+
options[:action][:bind] = b
|
39
|
+
end
|
40
|
+
opts.on('-u', '--unbind VSERVER',
|
41
|
+
"Unbinds a serivce to a virtual server.") do |u|
|
42
|
+
options[:action][:unbind] = u
|
43
|
+
end
|
44
|
+
opts.separator ""
|
45
|
+
end
|
46
|
+
end # CLI
|
47
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'netscaler/baseexecutor'
|
2
|
+
|
3
|
+
module Netscaler::Service
|
4
|
+
class Executor < Netscaler::BaseExecutor
|
5
|
+
def initialize(host, client)
|
6
|
+
super(host, client)
|
7
|
+
end
|
8
|
+
|
9
|
+
def enable
|
10
|
+
attrs = {
|
11
|
+
'name' => host
|
12
|
+
}
|
13
|
+
send_request('enableservice', attrs)
|
14
|
+
end
|
15
|
+
|
16
|
+
def disable
|
17
|
+
attrs = {
|
18
|
+
'name' => host,
|
19
|
+
'delay' => 0
|
20
|
+
}
|
21
|
+
send_request('disableservice', attrs)
|
22
|
+
end
|
23
|
+
|
24
|
+
def status
|
25
|
+
attrs = { 'name' => host }
|
26
|
+
send_request('getservice', attrs) do |response|
|
27
|
+
require 'pp'
|
28
|
+
pp response
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def bind(vserver)
|
33
|
+
attrs = {
|
34
|
+
'name' => vserver,
|
35
|
+
'servicename' => host
|
36
|
+
}
|
37
|
+
send_request('bindlbvserver_service', attrs) do |response|
|
38
|
+
require 'pp'
|
39
|
+
pp response
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def unbind(vserver)
|
44
|
+
attrs = {
|
45
|
+
'name' => vserver,
|
46
|
+
'servicename' => host
|
47
|
+
}
|
48
|
+
send_request('unbindlbvserver_service', attrs) do |response|
|
49
|
+
require 'pp'
|
50
|
+
pp response
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'netscaler/logging'
|
2
|
+
require 'savon'
|
3
|
+
|
4
|
+
module Netscaler
|
5
|
+
NSCONFIG_NAMESPACE = "urn:NSConfig"
|
6
|
+
|
7
|
+
class Transaction
|
8
|
+
include Logging
|
9
|
+
|
10
|
+
def initialize(config, &block)
|
11
|
+
@config = config
|
12
|
+
if block_given?
|
13
|
+
execute(&block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(&block)
|
18
|
+
if !block_given?
|
19
|
+
raise Netscaler::TransactionError.new("No execution block given.")
|
20
|
+
end
|
21
|
+
|
22
|
+
log.debug("Beginning the transaction execution: #{@config.host}")
|
23
|
+
|
24
|
+
client = Savon::Client.new(url) #"file://{File.expand_path('./etc/NSConfig.wsdl', File.dirname(__FILE__))}")
|
25
|
+
client.request.http.ssl_client_auth(:verify_mode => OpenSSL::SSL::VERIFY_NONE)
|
26
|
+
|
27
|
+
begin
|
28
|
+
log.debug("Logging in to the Netscaler host.")
|
29
|
+
|
30
|
+
response = client.login! do |soap|
|
31
|
+
soap.namespace = Netscaler::NSCONFIG_NAMESPACE
|
32
|
+
|
33
|
+
body = Hash.new
|
34
|
+
body['username'] = @config.username
|
35
|
+
body['password'] = @config.password
|
36
|
+
|
37
|
+
soap.body = body
|
38
|
+
end
|
39
|
+
auth_cookie = response.http['Set-Cookie']
|
40
|
+
client.request.headers['Cookie'] = auth_cookie
|
41
|
+
log.debug("Got authorization cookie: #{auth_cookie}")
|
42
|
+
|
43
|
+
log.debug("Yielding client control to the calling context")
|
44
|
+
yield client
|
45
|
+
rescue Exception => e
|
46
|
+
log.fatal(e)
|
47
|
+
log.fatal("Unable to execute transaction.")
|
48
|
+
raise Netscaler::TransactionError.new(e)
|
49
|
+
ensure
|
50
|
+
begin
|
51
|
+
log.debug("Logging out of the Netscaler host.")
|
52
|
+
client.logout! do |soap|
|
53
|
+
soap.namespace = Netscaler::NSCONFIG_NAMESPACE
|
54
|
+
end
|
55
|
+
rescue Exception => e
|
56
|
+
log.fatal(e)
|
57
|
+
log.fatal("Unable to logout.")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
log.debug("Ending the transaction execution: #{@config.host}")
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def url
|
66
|
+
"https://#{@config.host}/soap"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'netscaler/clitemplate'
|
2
|
+
require 'netscaler/vserver/executor'
|
3
|
+
|
4
|
+
module Netscaler::VServer
|
5
|
+
class CLI < Netscaler::CLITemplate
|
6
|
+
def initialize(args)
|
7
|
+
super('vserver', args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_executor(client)
|
11
|
+
Netscaler::VServer::Executor.new(host, client)
|
12
|
+
end
|
13
|
+
|
14
|
+
def interface_header(opts)
|
15
|
+
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] VSERVER"
|
16
|
+
opts.separator <<DESC
|
17
|
+
Description:
|
18
|
+
This is a tool for enabling and disabling virtual server in a Netscaler
|
19
|
+
load balancer. The name of the virtual server is required, as is the
|
20
|
+
address of the Netscaler load balancer.
|
21
|
+
|
22
|
+
By default, this script will tell you what its current status of the
|
23
|
+
virtual server is.
|
24
|
+
|
25
|
+
Options:
|
26
|
+
DESC
|
27
|
+
end
|
28
|
+
|
29
|
+
def interface_actions(opts)
|
30
|
+
opts.separator " Actions: "
|
31
|
+
opts.on('-e', '--enable',
|
32
|
+
"Enables the given virtual server.") do |e|
|
33
|
+
options[:action][:enable] = nil
|
34
|
+
end
|
35
|
+
opts.on('-d', '--disable',
|
36
|
+
"Disables the given virtual server.") do |d|
|
37
|
+
options[:action][:disable] = nil
|
38
|
+
end
|
39
|
+
opts.on('-b', '--bind POLICY_NAME',
|
40
|
+
"Binds a policy of a given name to a virtual server.") do |b|
|
41
|
+
options[:action][:bind] = b
|
42
|
+
end
|
43
|
+
opts.on('-u', '--unbind POLICY_NAME',
|
44
|
+
"Unbinds a policy of a given name to a virtual server.") do |u|
|
45
|
+
options[:action][:unbind] = u
|
46
|
+
end
|
47
|
+
opts.separator ""
|
48
|
+
end
|
49
|
+
end # CLI
|
50
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'netscaler/baseexecutor'
|
2
|
+
|
3
|
+
module Netscaler::VServer
|
4
|
+
class Executor < Netscaler::BaseExecutor
|
5
|
+
def initialize(host, client)
|
6
|
+
super(host, client)
|
7
|
+
end
|
8
|
+
|
9
|
+
def enable
|
10
|
+
attrs = { 'name' => host }
|
11
|
+
send_request('enablelbvserver', attrs)
|
12
|
+
end
|
13
|
+
|
14
|
+
def disable
|
15
|
+
attrs = { 'name' => host }
|
16
|
+
send_request('disablelbvserver', attrs)
|
17
|
+
end
|
18
|
+
|
19
|
+
def status
|
20
|
+
attrs = { 'name' => host }
|
21
|
+
send_request('getlbvserver', attrs) do |response|
|
22
|
+
puts "Name: #{response[:return][:list][:item][:name]}"
|
23
|
+
puts "IP Address: #{response[:return][:list][:item][:svcipaddress][:item]}"
|
24
|
+
puts "Port: #{response[:return][:list][:item][:svcport][:item]}"
|
25
|
+
puts "State: #{response[:return][:list][:item][:svcstate][:item]}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def bind(policy_name)
|
30
|
+
attrs = {
|
31
|
+
'name' => host,
|
32
|
+
'policyname' => policy_name,
|
33
|
+
'priority' => 1,
|
34
|
+
'gotopriorityexpression' => 'END'
|
35
|
+
}
|
36
|
+
|
37
|
+
send_request('bindlbvserver_policy', attrs) do |response|
|
38
|
+
require 'pp'
|
39
|
+
pp response
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def unbind(policy_name)
|
44
|
+
attrs = {
|
45
|
+
'name' => host,
|
46
|
+
'policyname' => policy_name,
|
47
|
+
'type' => 'REQUEST'
|
48
|
+
}
|
49
|
+
|
50
|
+
send_request('unbindlbvserver_policy', attrs) do |response|
|
51
|
+
require 'pp'
|
52
|
+
pp response
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require '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.new(actual_file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Configuration Reader" do
|
15
|
+
include ConfigurationHelper
|
16
|
+
|
17
|
+
describe "when reading an existing file" do
|
18
|
+
it "should be able to load the basic config file" do
|
19
|
+
reading('simple-config.yml').load_balancers.length.should eql(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should set the username and password correctly when set in the file." do
|
23
|
+
config = reading('simple-config.yml')['something.goes.here']
|
24
|
+
config.username.should eql('some_user')
|
25
|
+
config.password.should eql('somepass')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "when reading a non-existent or bad file" do
|
30
|
+
it "should fail when the config doesn't exist" do
|
31
|
+
attempting { reading('non-config.yml') }.should raise_error(Netscaler::ConfigurationError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should fail when the config is poorly formed" do
|
35
|
+
attempting { reading('bad-yaml.yml') }.should raise_error(Netscaler::ConfigurationError)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should fail when the username is missing" do
|
39
|
+
attempting { reading('missing-username.yml')['load-balancer'] }.should raise_error(Netscaler::ConfigurationError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/spec/helpers.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'helpers'
|
2
|
+
require 'netscaler/vserver/cli'
|
3
|
+
|
4
|
+
module Netscaler::VServer
|
5
|
+
|
6
|
+
module CLIHelper
|
7
|
+
def parse(*args)
|
8
|
+
cli = CLI.new(args)
|
9
|
+
cli.parse_options(args)
|
10
|
+
cli.options
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "The CLI interface" do
|
15
|
+
include CLIHelper
|
16
|
+
|
17
|
+
it "should set the --netscaler flag correctly." do
|
18
|
+
parse('--netscaler', 'localhost')[:netscaler].should eql('localhost')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should set the --debug flag correctly." do
|
22
|
+
parse('--debug')[:debug].should be(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should set the --enable flag correctly." do
|
26
|
+
parse('--enable')[:action].has_key?(:enable).should be(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set the --disable flag correctly." do
|
30
|
+
parse('--disable')[:action].has_key?(:disable).should be(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set the --bind flag correctly." do
|
34
|
+
parse('--bind', 'some-policy')[:action][:bind].should eql('some-policy')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should set the --unbind flag correctly." do
|
38
|
+
parse('--unbind', 'some-policy')[:action][:unbind].should eql('some-policy')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should set the --config flag correctly." do
|
42
|
+
parse('--config', 'CONFIG')[:config].should eql('CONFIG')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: netscaler-cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Gabe McArthur
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-12 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: highline
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 5
|
33
|
+
- 2
|
34
|
+
version: 1.5.2
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: log4r
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 29
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 1
|
49
|
+
- 7
|
50
|
+
version: 1.1.7
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: savon
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 17
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
- 7
|
65
|
+
- 9
|
66
|
+
version: 0.7.9
|
67
|
+
type: :runtime
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
prerelease: false
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 27
|
78
|
+
segments:
|
79
|
+
- 1
|
80
|
+
- 3
|
81
|
+
- 0
|
82
|
+
version: 1.3.0
|
83
|
+
type: :development
|
84
|
+
version_requirements: *id004
|
85
|
+
description: This gem installs several simple command line utilities locally. It uses the NSConfig.wsdl SOAP interface for remote access.
|
86
|
+
email:
|
87
|
+
- madeonamac@gmail.com
|
88
|
+
executables:
|
89
|
+
- netscaler-vserver
|
90
|
+
- netscaler-service
|
91
|
+
extensions: []
|
92
|
+
|
93
|
+
extra_rdoc_files:
|
94
|
+
- README.markdown
|
95
|
+
files:
|
96
|
+
- README.markdown
|
97
|
+
- Rakefile
|
98
|
+
- bin/netscaler-service
|
99
|
+
- bin/netscaler-vserver
|
100
|
+
- lib/VERSION
|
101
|
+
- lib/netscaler/baseexecutor.rb
|
102
|
+
- lib/netscaler/clitemplate.rb
|
103
|
+
- lib/netscaler/config.rb
|
104
|
+
- lib/netscaler/errors.rb
|
105
|
+
- lib/netscaler/logging.rb
|
106
|
+
- lib/netscaler/service/cli.rb
|
107
|
+
- lib/netscaler/service/executor.rb
|
108
|
+
- lib/netscaler/transaction.rb
|
109
|
+
- lib/netscaler/version.rb
|
110
|
+
- lib/netscaler/vserver/cli.rb
|
111
|
+
- lib/netscaler/vserver/executor.rb
|
112
|
+
- spec/config_spec.rb
|
113
|
+
- spec/configs/bad-yaml.yml
|
114
|
+
- spec/configs/missing-username.yml
|
115
|
+
- spec/configs/simple-config.yml
|
116
|
+
- spec/helpers.rb
|
117
|
+
- spec/vserver/cli_spec.rb
|
118
|
+
has_rdoc: true
|
119
|
+
homepage: http://github.com/gabemc/netscaler-cli
|
120
|
+
licenses: []
|
121
|
+
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options:
|
124
|
+
- --charset=UTF-8
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: 3
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
version: "0"
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
requirements: []
|
146
|
+
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 1.3.7
|
149
|
+
signing_key:
|
150
|
+
specification_version: 3
|
151
|
+
summary: Simple command line utilities for interacting remotely with a Netscaler load balancer.
|
152
|
+
test_files:
|
153
|
+
- spec/vserver/cli_spec.rb
|
154
|
+
- spec/helpers.rb
|
155
|
+
- spec/config_spec.rb
|