stingray-exec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +2 -0
  3. data/.simplecov +7 -0
  4. data/AUTHORS.md +2 -0
  5. data/CONTRIBUTING.md +8 -0
  6. data/Gemfile +12 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +66 -0
  9. data/Rakefile +22 -0
  10. data/bin/stingray-exec +3 -0
  11. data/examples/add-pool +10 -0
  12. data/examples/bork +6 -0
  13. data/examples/credentials.conf +4 -0
  14. data/examples/delete-pool +10 -0
  15. data/examples/list-pools +8 -0
  16. data/examples/list-virtual-servers +8 -0
  17. data/generate-actions.rb +119 -0
  18. data/lib/stingray-exec.rb +5 -0
  19. data/lib/stingray/control_api.rb +112 -0
  20. data/lib/stingray/control_api/actions.rb +49 -0
  21. data/lib/stingray/control_api/catalog_rule_methods.rb +31 -0
  22. data/lib/stingray/control_api/endpoint.rb +23 -0
  23. data/lib/stingray/control_api/generated-actions-9.0.yml +9036 -0
  24. data/lib/stingray/control_api/generated-actions-9.1.yml +9172 -0
  25. data/lib/stingray/control_api/pool_methods.rb +156 -0
  26. data/lib/stingray/control_api/soap_helper_methods.rb +69 -0
  27. data/lib/stingray/exec.rb +16 -0
  28. data/lib/stingray/exec/cli.rb +134 -0
  29. data/lib/stingray/exec/dsl.rb +48 -0
  30. data/lib/stingray/exec/version.rb +5 -0
  31. data/lib/stingray/junk.rb +16 -0
  32. data/spec/integration/catalog_rule_spec.rb +116 -0
  33. data/spec/integration/pool_spec.rb +61 -0
  34. data/spec/integration/users_spec.rb +21 -0
  35. data/spec/lib/stingray/control_api_spec.rb +51 -0
  36. data/spec/lib/stingray/exec/cli_spec.rb +7 -0
  37. data/spec/lib/stingray/exec/version_spec.rb +5 -0
  38. data/spec/spec_helper.rb +26 -0
  39. data/stingray-exec.gemspec +29 -0
  40. metadata +131 -0
@@ -0,0 +1,156 @@
1
+ require 'stingray/control_api'
2
+ require 'stingray/control_api/soap_helper_methods'
3
+
4
+ module Stingray::ControlApi::PoolMethods
5
+ include Stingray::ControlApi::SoapHelperMethods
6
+
7
+ %w(
8
+ add_pool
9
+ get_nodes_priority_value
10
+ get_nodes_weightings
11
+ ).map(&:to_sym).each do |op|
12
+ define_method(:"_custom_#{op}") do |node_configs|
13
+ body = _build_many_keyed_string_arrays(node_configs, :names, :nodes)
14
+ _make_soap_request('Pool', op, body)
15
+ end
16
+ end
17
+
18
+ %w(
19
+ delete_pool
20
+ get_autoscale_cloudcredentials
21
+ get_autoscale_cluster
22
+ get_autoscale_datacenter
23
+ get_autoscale_datastore
24
+ get_autoscale_enabled
25
+ get_autoscale_external
26
+ get_autoscale_hysteresis
27
+ get_autoscale_imageid
28
+ get_autoscale_ipstouse
29
+ get_autoscale_lastnode_idletime
30
+ get_autoscale_max_nodes
31
+ get_autoscale_min_nodes
32
+ get_autoscale_names
33
+ get_autoscale_port
34
+ get_autoscale_refractory
35
+ get_autoscale_response_time
36
+ get_autoscale_scaledown_level
37
+ get_autoscale_scaleup_level
38
+ get_autoscale_sizeid
39
+ get_bandwidth_class
40
+ get_disabled_nodes
41
+ get_draining_nodes
42
+ get_ftp_support_rfc2428
43
+ get_failpool
44
+ get_keepalive
45
+ get_keepalive_non_idempotent
46
+ get_load_balancing_algorithm
47
+ get_max_connect_time
48
+ get_max_connections_pernode
49
+ get_max_idle_connections_per_node
50
+ get_max_keepalives_per_node
51
+ get_max_queue_size
52
+ get_max_reply_time
53
+ get_monitors
54
+ get_node_conn_close
55
+ get_node_connection_attempts
56
+ get_node_fail_time
57
+ get_node_use_nagle
58
+ get_nodes
59
+ get_nodes_connection_counts
60
+ get_nodes_last_used
61
+ get_note
62
+ get_passive_monitoring
63
+ get_persistence
64
+ get_priority_enabled
65
+ get_priority_nodes
66
+ get_priority_values
67
+ get_queue_timeout
68
+ get_smtp_send_start_tls
69
+ get_ssl_client_auth
70
+ get_ssl_encrypt
71
+ get_ssl_enhance
72
+ get_ssl_send_close_alerts
73
+ get_ssl_server_name_extension
74
+ get_ssl_strict_verify
75
+ get_transparent
76
+ get_udp_accept_from
77
+ get_udp_accept_from_ip_mask
78
+ get_weightings
79
+ ).map(&:to_sym).each do |op|
80
+ define_method(:"_custom_#{op}") do |*names|
81
+ _make_names_soap_request(names, 'Pool', op)
82
+ end
83
+ end
84
+
85
+ %w(
86
+ add_draining_nodes
87
+ add_monitors
88
+ add_nodes
89
+ disable_nodes
90
+ enable_nodes
91
+ remove_draining_nodes
92
+ remove_monitors
93
+ remove_nodes
94
+ set_autoscale_cloudcredentials
95
+ set_autoscale_cluster
96
+ set_autoscale_datacenter
97
+ set_autoscale_datastore
98
+ set_autoscale_enabled
99
+ set_autoscale_external
100
+ set_autoscale_hysteresis
101
+ set_autoscale_imageid
102
+ set_autoscale_ipstouse
103
+ set_autoscale_lastnode_idletime
104
+ set_autoscale_max_nodes
105
+ set_autoscale_min_nodes
106
+ set_autoscale_name
107
+ set_autoscale_port
108
+ set_autoscale_refractory
109
+ set_autoscale_response_time
110
+ set_autoscale_scaledown_level
111
+ set_autoscale_scaleup_level
112
+ set_autoscale_sizeid
113
+ set_bandwidth_class
114
+ set_disabled_nodes
115
+ set_draining_nodes
116
+ set_ftp_support_rfc2428
117
+ set_failpool
118
+ set_keepalive
119
+ set_keepalive_non_idempotent
120
+ set_load_balancing_algorithm
121
+ set_max_connect_time
122
+ set_max_connections_pernode
123
+ set_max_idle_connections_pernode
124
+ set_max_keepalives_pernode
125
+ set_max_queue_size
126
+ set_max_reply_time
127
+ set_monitors
128
+ set_node_conn_close
129
+ set_node_connection_attempts
130
+ set_node_fail_time
131
+ set_node_use_nagle
132
+ set_nodes
133
+ set_nodes_priority_value
134
+ set_nodes_weightings
135
+ set_note
136
+ set_passive_monitoring
137
+ set_persistence
138
+ set_priority_enabled
139
+ set_priority_nodes
140
+ set_queue_timeout
141
+ set_smtp_send_start_tls
142
+ set_ssl_client_auth
143
+ set_ssl_encrypt
144
+ set_ssl_enhance
145
+ set_ssl_send_close_alerts
146
+ set_ssl_server_name_extension
147
+ set_ssl_strict_verify
148
+ set_transparent
149
+ set_udp_accept_from
150
+ set_udp_accept_from_ip_mask
151
+ ).map(&:to_sym).each do |op|
152
+ define_method(:"_custom_#{op}") do |names_values|
153
+ _make_names_values_soap_request(names_values, 'Pool', op)
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,69 @@
1
+ require 'stingray/control_api'
2
+
3
+ module Stingray::ControlApi::SoapHelperMethods
4
+ def _make_soap_request(ns, method, soap_body)
5
+ self.client.request(ns, method) do
6
+ soap.namespaces['xmlns:soapenc'] = 'http://schemas.xmlsoap.org/soap/encoding/'
7
+ soap.body = soap_body
8
+ end
9
+ end
10
+
11
+ def _make_names_values_soap_request(names_values_hash, ns, operation)
12
+ raise ArgumentError.new('No names -> values given!') if names_values_hash.empty?
13
+ body = _build_many_keyed_string_arrays(names_values_hash, :names, :values)
14
+ _make_soap_request(ns, operation, body)
15
+ end
16
+
17
+ def _make_names_soap_request(names_array, ns, operation)
18
+ raise ArgumentError.new('No names given!') if names_array.empty?
19
+ body = _build_string_array(names_array, :names)
20
+ _make_soap_request(ns, operation, body)
21
+ end
22
+
23
+ def _build_string_array(strings, key_name)
24
+ body = {
25
+ key_name => {},
26
+ :attributes! => {
27
+ key_name => {'soapenc:arrayType' => "xsd:string[#{strings.length}]"}
28
+ }
29
+ }
30
+
31
+ strings.each_with_index do |s,i|
32
+ body[key_name][:"s#{i}"] = s
33
+ end
34
+
35
+ body
36
+ end
37
+
38
+ def _build_many_keyed_string_arrays(key_array_hash, keys_name, arrays_name)
39
+ body = {
40
+ keys_name => {},
41
+ arrays_name => {
42
+ :attributes! => {},
43
+ },
44
+ :attributes! => {
45
+ keys_name => {'soapenc:arrayType' => "xsd:string[#{key_array_hash.length}]"},
46
+ arrays_name => {'soapenc:arrayType' => "xsd:list[#{key_array_hash.length}]"},
47
+ },
48
+ }
49
+
50
+ i = 0
51
+ key_array_hash.each do |k,arr|
52
+ body[keys_name][:"k#{i}"] = k
53
+
54
+ k_arr = {:attributes! => {}}
55
+ arr.each_with_index do |node,j|
56
+ k_arr[:"node#{j}"] = node
57
+ end
58
+
59
+ body[arrays_name][:attributes!][:"k#{i}"] = {
60
+ 'soapenc:arrayType' => "xsd:string[#{arr.length}]"
61
+ }
62
+
63
+ body[arrays_name][:"k#{i}"] = k_arr
64
+ i += 1
65
+ end
66
+
67
+ body
68
+ end
69
+ end
@@ -0,0 +1,16 @@
1
+ require 'savon'
2
+
3
+ module Stingray
4
+ module Exec
5
+ def self.configure
6
+ Savon.configure do |config|
7
+ unless ENV['DEBUG']
8
+ config.log = false
9
+ HTTPI.log = false
10
+ end
11
+
12
+ yield config if block_given?
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,134 @@
1
+ require 'optparse'
2
+ require 'stingray/exec'
3
+
4
+ class Stingray::Exec::Cli
5
+ BANNER = <<-EOB.gsub(/^ /, '')
6
+ Usage: stingray-exec [options] <script>
7
+
8
+ Executes scripts in the context of Stingray Traffic Manager configuration
9
+ models, allowing for access to all methods documented in the Control API. The
10
+ <script> argument may be a string expression or a filename (or "-" for stdin),
11
+ and if ommitted will cause stingray-exec to drop into a fancy DSL-tastic pry
12
+ console.
13
+
14
+ All of the command-line configuration flags may also be given as
15
+ environmental variables, as noted in the help text for each flag. The
16
+ "endpoint" flag/var deserves special attention as the expected value is buried
17
+ in the Stingray docs.
18
+ e.g.: STINGRAY_ENDPOINT='https://stingray-pool-master.example.com:9090/soap'
19
+
20
+ See the 'examples' directory in the stingray-exec gem tree for some
21
+ (surprise!) examples of how to do stuff.
22
+
23
+ ------- FAIR WARNING: -------
24
+ The vast majority of Control API methods have been wrapped in very dumb
25
+ generated code. Read-only methods work fine, but methods that take arguments
26
+ invariably require custom implementations -- the kind of thing that's typically
27
+ generated from a WSDL, which we can't legally redistribute. The Control API
28
+ makes things even more fun by requiring the use of soapenc arrays and lists of
29
+ arrays. If you want or need to implement such code, the "soap_helper_methods.rb"
30
+ file in the stingray-exec source may be of help. YMMV.
31
+
32
+
33
+ EOB
34
+
35
+ def self.main(argv = ARGV)
36
+ new(argv).run!
37
+ end
38
+
39
+ attr_reader :argv, :script, :filename
40
+
41
+ def initialize(argv)
42
+ @argv = argv
43
+ end
44
+
45
+ def run!
46
+ parse_options
47
+ prepare_script
48
+ configure
49
+ evaluate_script
50
+ end
51
+
52
+ private
53
+ def parse_options
54
+ OptionParser.new do |opts|
55
+ opts.banner = BANNER
56
+ opts.on('-v', '--verbose', 'Yelling. (DEBUG=1)') do
57
+ ENV['DEBUG'] = '1'
58
+ end
59
+ opts.on('-k', '--insecure', 'Allow "insecure" SSL connections ' <<
60
+ '(STINGRAY_SSL_VERIFY_NONE=1)') do
61
+ ENV['STINGRAY_SSL_VERIFY_NONE'] = '1'
62
+ end
63
+ opts.on('-u=', '--user-password=',
64
+ 'Stingray username:password (STINGRAY_AUTH=<user>:<pass>)') do |u|
65
+ ENV['STINGRAY_AUTH'] = u
66
+ end
67
+ opts.on('-C=', '--credentials=', 'Credentials file containing ' <<
68
+ 'username:password (STINGRAY_AUTH=<user>:<pass>)') do |c|
69
+ ENV['STINGRAY_AUTH'] = read_credentials_file(c)
70
+ end
71
+ opts.on('-E=', '--endpoint=',
72
+ 'Stingray server SOAP endpoint (STINGRAY_ENDPOINT=<uri>)') do |endpoint|
73
+ ENV['STINGRAY_ENDPOINT'] = endpoint
74
+ end
75
+ opts.on('-V=', '--stingray-version=', 'Stingray server version, ' <<
76
+ 'e.g. "9.0" or "9.1" (STINGRAY_VERSION="9.1")') do |ver|
77
+ ENV['STINGRAY_VERSION'] = ver
78
+ end
79
+ end.parse!(argv)
80
+ end
81
+
82
+ def read_credentials_file(filename)
83
+ File.read(filename).split($/).reject do |l|
84
+ l.strip =~ /^#/ || l.strip.empty?
85
+ end.first
86
+ end
87
+
88
+ def prepare_script
89
+ @script = argv.first || ''
90
+ @filename = ''
91
+ if File.exists?(@script)
92
+ @filename = @script
93
+ @script = File.read(@script)
94
+ elsif @script == '-'
95
+ @script = $stdin.read
96
+ end
97
+ end
98
+
99
+ def configure
100
+ Stingray::Exec.configure
101
+ end
102
+
103
+ def evaluate_script
104
+ require_relative 'dsl'
105
+
106
+ # reassign so that scoping is happy once we're inside the new class block
107
+ script_string = script
108
+ script_filename = filename
109
+ shebang_offset = script_string =~ /^#!/ ? 1 : 0
110
+
111
+ unless script_string.empty?
112
+ Class.new(Object) do
113
+ extend Stingray::Exec::DSL
114
+ begin
115
+ stingray_exec(script_string, script_filename, shebang_offset)
116
+ rescue => e
117
+ $stderr.puts e.message
118
+ $stderr.puts e.backtrace.join("\n") if ENV['DEBUG']
119
+ end
120
+ end
121
+ else
122
+ require 'pry'
123
+ Pry.config.prompt_name = 'stingray-exec'
124
+ TOPLEVEL_BINDING.eval('self').extend Stingray::Exec::DSL
125
+ Pry.start
126
+ end
127
+
128
+ return 0
129
+ end
130
+ end
131
+
132
+ if $0 == __FILE__
133
+ exit Stingray::Exec::Cli.main
134
+ end
@@ -0,0 +1,48 @@
1
+ require 'stingray/exec'
2
+ require 'stingray/control_api'
3
+
4
+ module Stingray::Exec::DSL
5
+ def stingray_exec(string = '', filename = '', lineno = 0, &block)
6
+ unless string.empty?
7
+ instance_eval(string, filename, lineno)
8
+ else
9
+ instance_eval(&block)
10
+ end
11
+ end
12
+
13
+ Stingray::ControlApi::CONFIGURATIONS.each do |cfg_ns,variations|
14
+ define_method(variations[:snaked]) do
15
+ ivar = :"@#{variations[:snaked].to_s}"
16
+
17
+ if inst = instance_variable_get(ivar)
18
+ return inst
19
+ end
20
+
21
+ inst = Stingray::ControlApi::const_get(variations[:consted]).new
22
+ inst.client.http.auth.ssl.verify_mode = ssl_verify_mode
23
+ instance_variable_set(ivar, inst)
24
+ inst
25
+ end
26
+ end
27
+
28
+ # Set the SSL verification mode for all SOAP communication. Valid values are
29
+ # really up to the HTTP backend, but some known good ones are ":none" and
30
+ # ":peer". Setting the STINGRAY_SSL_VERIFY_NONE environmental variable will
31
+ # result in this method defaulting to ":none". Once a configuration model
32
+ # has been initialized, its verify mode cannot be modified through this
33
+ # function. Instead, set the model's deeply-nested attribute of
34
+ # `.client.http.auth.ssl.verify_mode`.
35
+ def ssl_verify_mode(mode = nil)
36
+ unless mode.nil?
37
+ @ssl_verify_mode = mode
38
+ end
39
+ @ssl_verify_mode || ENV['STINGRAY_SSL_VERIFY_NONE'] ? :none : :peer
40
+ end
41
+
42
+ # A little helper that allows for iteration over SOAP results that may be
43
+ # singular or plural (or just plain missing.) A block must always be given.
44
+ def foreach(anything, &block)
45
+ raise SyntaxError.new('Block needed!') unless block_given?
46
+ [*(anything || [])].each(&block)
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Stingray
2
+ module Exec
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module Stingray
2
+ class Junk
3
+ def self.snakify(str)
4
+ str.gsub(/::/, '/').
5
+ gsub(/\./, '_').
6
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
7
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
8
+ tr("-", "_").
9
+ downcase
10
+ end
11
+
12
+ def self.constify(str)
13
+ str.gsub(/\./, '').gsub(/_/, '')
14
+ end
15
+ end
16
+ end