stingray-exec 0.1.0

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.
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