continuent-tools-core 0.1.0 → 0.1.5
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.
- checksums.yaml +4 -4
- data/bin/tungsten_create_load +180 -0
- data/lib/continuent-tools-core.rb +112 -0
- data/lib/tungsten/exec.rb +5 -13
- data/lib/tungsten/script.rb +0 -6
- data/lib/tungsten/util.rb +15 -5
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16efacbae7473d06eb2d66b15dc36930640ec849
|
4
|
+
data.tar.gz: 59927a7e2be2982ec8723e775d4314faed5ded72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c570c00e9dbaae8194c97981266a5e5e44183539e1c6a581f58ecc48fe195526db46b524fef3ac3472c1a1929ac3fd6bef5eb3a5f7b06bd4c0409c5bb1fd072
|
7
|
+
data.tar.gz: f84cc97f36b4df6d4bfcd1c01997a52f6185a12d7b6e5cd8860d1a05c2ce4b633f72717fb2376b71e84fe714ac5f420e6f513404fce77db77e98a5d28a34c46c
|
@@ -0,0 +1,180 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (C) 2014 Continuent, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
6
|
+
# a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations
|
14
|
+
# under the License.
|
15
|
+
#
|
16
|
+
# Initial developer(s): Jeff Mace
|
17
|
+
# Contributor(s):
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'rubygems'
|
21
|
+
gem 'continuent-tools-core'
|
22
|
+
rescue LoadError
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'continuent-tools-core'
|
26
|
+
|
27
|
+
class ContinuentCreateLoad
|
28
|
+
include TungstenScript
|
29
|
+
include MySQLServiceScript
|
30
|
+
private
|
31
|
+
|
32
|
+
@@interrupted = false
|
33
|
+
|
34
|
+
def main
|
35
|
+
old_trap = trap("INT") {
|
36
|
+
ContinuentCreateLoad.interrupted?(true);
|
37
|
+
}
|
38
|
+
|
39
|
+
# Create the schema we will load data into using the local connection
|
40
|
+
TU.cmd(get_mysql_command(), false, method(:initialize_schema), nil, method(:forward_mysql_errors))
|
41
|
+
sleep 2
|
42
|
+
|
43
|
+
# Create a list of all load generation threads that should be started
|
44
|
+
load_threads = []
|
45
|
+
opt(:hosts).each{
|
46
|
+
|host|
|
47
|
+
i = 0
|
48
|
+
while (i < opt(:threads).to_i())
|
49
|
+
load_threads << {:host => host}
|
50
|
+
i = i+1
|
51
|
+
end
|
52
|
+
}
|
53
|
+
# Spin up an independent thread for each configuration of the load
|
54
|
+
# generation thread.
|
55
|
+
load_threads.peach{
|
56
|
+
|load_thread|
|
57
|
+
TU.cmd(get_mysql_command() + " -h#{load_thread[:host]}", true, method(:create_schema_load), nil, method(:forward_mysql_errors))
|
58
|
+
}
|
59
|
+
|
60
|
+
puts("\n")
|
61
|
+
trap("INT", old_trap);
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize_schema(stdin)
|
65
|
+
[
|
66
|
+
"DROP SCHEMA IF EXISTS tungsten_create_load;",
|
67
|
+
"CREATE SCHEMA tungsten_create_load;",
|
68
|
+
"CREATE TABLE tungsten_create_load.values (id int NOT NULL auto_increment primary key, val int NOT NULL, origin varchar(32) NULL);"
|
69
|
+
].each{|sql|
|
70
|
+
stdin.puts(sql)
|
71
|
+
putc '.'
|
72
|
+
$stdout.flush()
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_schema_load(stdin)
|
77
|
+
sql = "INSERT INTO tungsten_create_load.values (val, origin) VALUES (5, @@hostname);"
|
78
|
+
while (ContinuentCreateLoad.interrupted?() == false)
|
79
|
+
stdin.puts(sql)
|
80
|
+
putc '.'
|
81
|
+
$stdout.flush()
|
82
|
+
sleep opt(:sleep).to_i()
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def forward_mysql_errors(msg)
|
87
|
+
TU.error(msg)
|
88
|
+
end
|
89
|
+
|
90
|
+
def configure
|
91
|
+
super()
|
92
|
+
|
93
|
+
add_option(:hosts, {
|
94
|
+
:on => "--hosts String",
|
95
|
+
:help => "Coordinate load generation on these servers in addition to the current host",
|
96
|
+
})
|
97
|
+
|
98
|
+
add_option(:threads, {
|
99
|
+
:on => "--threads String",
|
100
|
+
:parse => method(:parse_integer_option),
|
101
|
+
:help => "How many parallel threads should be used to generate load",
|
102
|
+
:default => 1,
|
103
|
+
})
|
104
|
+
|
105
|
+
add_option(:sleep, {
|
106
|
+
:on => "--sleep String",
|
107
|
+
:parse => method(:parse_integer_option),
|
108
|
+
:help => "How many seconds to wait between load transactions",
|
109
|
+
:default => 1,
|
110
|
+
})
|
111
|
+
|
112
|
+
add_option(:use_connector, {
|
113
|
+
:on => "--use-connector String",
|
114
|
+
:parse => method(:parse_boolean_option),
|
115
|
+
:help => "Enable/Disable use of the Tungsten Connector for adding load to the system.",
|
116
|
+
})
|
117
|
+
end
|
118
|
+
|
119
|
+
def validate
|
120
|
+
super()
|
121
|
+
|
122
|
+
unless TU.is_valid?()
|
123
|
+
return TU.is_valid?()
|
124
|
+
end
|
125
|
+
|
126
|
+
if opt(:use_connector) == nil
|
127
|
+
if TI.is_connector?()
|
128
|
+
opt(:use_connector, true)
|
129
|
+
|
130
|
+
unless TI.is_running?("connector")
|
131
|
+
TU.error("The Tungsten Connector is not running")
|
132
|
+
end
|
133
|
+
|
134
|
+
defaults_file = Tempfile.new("tungsten_nagios_connector")
|
135
|
+
opt(:my_cnf, defaults_file.path())
|
136
|
+
|
137
|
+
defaults_file.puts("[client]")
|
138
|
+
defaults_file.puts("user=#{TI.setting(TI.setting_key(CONNECTORS, "connector_user"))}")
|
139
|
+
defaults_file.puts("password=#{TI.setting(TI.setting_key(CONNECTORS, "connector_password"))}")
|
140
|
+
defaults_file.flush()
|
141
|
+
|
142
|
+
opt(:mysqlport, TI.setting(TI.setting_key(CONNECTORS, "connector_listen_port")))
|
143
|
+
opt(:mysqlhost, TI.hostname())
|
144
|
+
elsif TI.is_replicator?()
|
145
|
+
opt(:use_connector, false)
|
146
|
+
|
147
|
+
if TI.setting(TI.setting_key(REPL_SERVICES, @options[:service], "repl_datasource_type")) != "mysql"
|
148
|
+
TU.error("Unable to create load on this system because it is not configured for MySQL")
|
149
|
+
end
|
150
|
+
else
|
151
|
+
TU.error("Unable to create load on this system because it is not configured as a Tungsten Connector or Tungsten Replicator")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
if opt(:hosts) != nil
|
156
|
+
hosts = opt(:hosts).split(",").uniq().delete_if{
|
157
|
+
|h|
|
158
|
+
(h == TI.hostname())
|
159
|
+
}
|
160
|
+
hosts << TI.hostname()
|
161
|
+
opt(:hosts, hosts)
|
162
|
+
else
|
163
|
+
opt(:hosts, [TI.hostname()])
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def script_name
|
168
|
+
"tungsten_create_load"
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.interrupted?(val = nil)
|
172
|
+
if val != nil
|
173
|
+
@@interrupted = val
|
174
|
+
end
|
175
|
+
|
176
|
+
(@@interrupted == true)
|
177
|
+
end
|
178
|
+
|
179
|
+
self.new().run()
|
180
|
+
end
|
@@ -38,6 +38,101 @@ class TungstenUtil
|
|
38
38
|
forward_cmd_results?(original_fwd_state)
|
39
39
|
end
|
40
40
|
end
|
41
|
+
|
42
|
+
# A wrapper for running another Tungsten script on a remote host. This will
|
43
|
+
# automatically forward messages to the console and add any TungstenScript
|
44
|
+
# options to the command.
|
45
|
+
def tungsten_ssh_result(command, host, user)
|
46
|
+
original_fwd_state = forward_cmd_results?()
|
47
|
+
begin
|
48
|
+
if TI
|
49
|
+
prefix = "export CONTINUENT_ROOT=#{TI.root()}; "
|
50
|
+
else
|
51
|
+
prefix = ""
|
52
|
+
end
|
53
|
+
|
54
|
+
forward_cmd_results?(true)
|
55
|
+
return ssh_result("#{prefix}#{command} #{get_tungsten_command_options()}", host, user)
|
56
|
+
ensure
|
57
|
+
forward_cmd_results?(original_fwd_state)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Run the {command} and return a string of STDOUT
|
62
|
+
def cmd(command, ignore_fail = false, stdin_method = nil, stdout_method = nil, stderr_method = nil)
|
63
|
+
errors = ""
|
64
|
+
result = ""
|
65
|
+
threads = []
|
66
|
+
|
67
|
+
debug("Execute `#{command}`")
|
68
|
+
status = Open4::popen4("export LANG=en_US; #{command}") do |pid, stdin, stdout, stderr|
|
69
|
+
if stdin_method != nil
|
70
|
+
threads << Thread.new{
|
71
|
+
stdin_method.call(stdin)
|
72
|
+
stdin.close
|
73
|
+
}
|
74
|
+
else
|
75
|
+
stdin.close
|
76
|
+
end
|
77
|
+
|
78
|
+
threads << Thread.new{
|
79
|
+
while data = stdout.gets()
|
80
|
+
if data.to_s() != ""
|
81
|
+
result+=data
|
82
|
+
|
83
|
+
if data != "" && forward_cmd_results?()
|
84
|
+
write(data, (parse_log_level(data) || get_forward_log_level()), nil, false)
|
85
|
+
end
|
86
|
+
|
87
|
+
if stdout_method != nil
|
88
|
+
stdout_method.call(data)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
}
|
93
|
+
threads << Thread.new{
|
94
|
+
while edata = stderr.gets()
|
95
|
+
if edata.to_s() != ""
|
96
|
+
errors+=edata
|
97
|
+
|
98
|
+
if edata != "" && forward_cmd_results?()
|
99
|
+
write(edata, (parse_log_level(edata) || get_forward_log_level()), nil, false)
|
100
|
+
end
|
101
|
+
|
102
|
+
if stderr_method != nil
|
103
|
+
stderr_method.call(edata)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
}
|
108
|
+
|
109
|
+
threads.each{|t| t.join() }
|
110
|
+
end
|
111
|
+
|
112
|
+
result.strip!()
|
113
|
+
errors.strip!()
|
114
|
+
|
115
|
+
original_errors = errors
|
116
|
+
rc = status.exitstatus
|
117
|
+
if errors == ""
|
118
|
+
errors = "No Errors"
|
119
|
+
else
|
120
|
+
errors = "Errors: #{errors}"
|
121
|
+
end
|
122
|
+
|
123
|
+
if log_cmd_results?()
|
124
|
+
debug("RC: #{rc}, Result: #{result}, #{errors}")
|
125
|
+
elsif forward_cmd_results?()
|
126
|
+
debug("RC: #{rc}, Result length #{result.length}, Errors length #{original_errors.length}")
|
127
|
+
else
|
128
|
+
debug("RC: #{rc}, Result length #{result.length}, #{errors}")
|
129
|
+
end
|
130
|
+
if rc != 0 && ! ignore_fail
|
131
|
+
raise CommandError.new(command, rc, result, original_errors)
|
132
|
+
end
|
133
|
+
|
134
|
+
return result
|
135
|
+
end
|
41
136
|
end
|
42
137
|
|
43
138
|
module TungstenScript
|
@@ -57,4 +152,21 @@ module TungstenScript
|
|
57
152
|
end
|
58
153
|
}
|
59
154
|
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class Array
|
158
|
+
def peach(&block)
|
159
|
+
pids = []
|
160
|
+
results = []
|
161
|
+
idx = 0
|
162
|
+
|
163
|
+
self.each{
|
164
|
+
|i|
|
165
|
+
pids[idx] = fork {
|
166
|
+
block.call(i)
|
167
|
+
}
|
168
|
+
idx = idx+1
|
169
|
+
}
|
170
|
+
pids.each{|pid| Process.waitpid(pid) }
|
171
|
+
end
|
60
172
|
end
|
data/lib/tungsten/exec.rb
CHANGED
@@ -238,19 +238,6 @@ class TungstenUtil
|
|
238
238
|
|
239
239
|
return
|
240
240
|
end
|
241
|
-
|
242
|
-
# A wrapper for running another Tungsten script. This will automatically
|
243
|
-
# forward messages to the console and add any TungstenScript options to
|
244
|
-
# the command.
|
245
|
-
def tungsten_cmd_result(command)
|
246
|
-
original_fwd_state = forward_cmd_results?()
|
247
|
-
begin
|
248
|
-
forward_cmd_results?(true)
|
249
|
-
return cmd_result("#{command} #{get_tungsten_command_options()}")
|
250
|
-
ensure
|
251
|
-
forward_cmd_results?(original_fwd_state)
|
252
|
-
end
|
253
|
-
end
|
254
241
|
|
255
242
|
# Run a standard check to see if SSH connectivity to the host works
|
256
243
|
def test_ssh(host, user)
|
@@ -411,6 +398,11 @@ class TungstenUtil
|
|
411
398
|
|k,v|
|
412
399
|
opts << "--net-ssh-option=#{k.to_s()}=#{v}"
|
413
400
|
}
|
401
|
+
|
402
|
+
if @force == true
|
403
|
+
opts << "--force"
|
404
|
+
end
|
405
|
+
|
414
406
|
return opts.join(" ")
|
415
407
|
end
|
416
408
|
|
data/lib/tungsten/script.rb
CHANGED
@@ -118,12 +118,6 @@ module TungstenScript
|
|
118
118
|
:help => "Only run the script validation"
|
119
119
|
})
|
120
120
|
|
121
|
-
add_option(:force, {
|
122
|
-
:on => "--force",
|
123
|
-
:default => false,
|
124
|
-
:help => "Continue operation even if script validation fails"
|
125
|
-
})
|
126
|
-
|
127
121
|
add_option(:autocomplete, {
|
128
122
|
:on => "--autocomplete",
|
129
123
|
:default => false,
|
data/lib/tungsten/util.rb
CHANGED
@@ -10,6 +10,7 @@ class TungstenUtil
|
|
10
10
|
@ssh_options = {}
|
11
11
|
@display_help = false
|
12
12
|
@num_errors = 0
|
13
|
+
@force = false
|
13
14
|
@json_interface = false
|
14
15
|
@json_message_cache = []
|
15
16
|
|
@@ -47,6 +48,7 @@ class TungstenUtil
|
|
47
48
|
}
|
48
49
|
|
49
50
|
opts=OptionParser.new
|
51
|
+
opts.on("-f", "--force") {@force = true}
|
50
52
|
opts.on("-i", "--info") {@logger_threshold = Logger::INFO}
|
51
53
|
opts.on("-n", "--notice") {@logger_threshold = Logger::NOTICE}
|
52
54
|
opts.on("-q", "--quiet") {@logger_threshold = Logger::WARN}
|
@@ -155,8 +157,12 @@ class TungstenUtil
|
|
155
157
|
@num_errors = 0
|
156
158
|
end
|
157
159
|
|
160
|
+
def force?
|
161
|
+
@force
|
162
|
+
end
|
163
|
+
|
158
164
|
def is_valid?
|
159
|
-
(@num_errors == 0)
|
165
|
+
(@num_errors == 0 || @force == true)
|
160
166
|
end
|
161
167
|
|
162
168
|
def write(content="", level=Logger::INFO, hostname = nil, add_prefix = true)
|
@@ -168,10 +174,6 @@ class TungstenUtil
|
|
168
174
|
return
|
169
175
|
end
|
170
176
|
|
171
|
-
unless content == "" || level == nil || add_prefix == false
|
172
|
-
content = "#{get_log_level_prefix(level, hostname)}#{content}"
|
173
|
-
end
|
174
|
-
|
175
177
|
# Attempt to determine the level for this message based on it's content
|
176
178
|
# If it is forwarded from another Tungsten script it will have a prefix
|
177
179
|
# so we know to use stdout or stderr
|
@@ -181,6 +183,14 @@ class TungstenUtil
|
|
181
183
|
|
182
184
|
if level == Logger::ERROR
|
183
185
|
@num_errors = @num_errors + 1
|
186
|
+
|
187
|
+
if force?()
|
188
|
+
level = Logger::WARN
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
unless content == "" || level == nil || add_prefix == false
|
193
|
+
content = "#{get_log_level_prefix(level, hostname)}#{content}"
|
184
194
|
end
|
185
195
|
|
186
196
|
log(content)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: continuent-tools-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Continuent
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json_pure
|
@@ -110,10 +110,12 @@ dependencies:
|
|
110
110
|
version: '0'
|
111
111
|
description:
|
112
112
|
email: info@continuent.com
|
113
|
-
executables:
|
113
|
+
executables:
|
114
|
+
- tungsten_create_load
|
114
115
|
extensions: []
|
115
116
|
extra_rdoc_files: []
|
116
117
|
files:
|
118
|
+
- bin/tungsten_create_load
|
117
119
|
- lib/continuent-tools-core.rb
|
118
120
|
- lib/tungsten/api.rb
|
119
121
|
- lib/tungsten/common.rb
|