hotdog 0.5.4 → 0.6.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.
- checksums.yaml +4 -4
- data/hotdog.gemspec +3 -1
- data/lib/hotdog/application.rb +13 -7
- data/lib/hotdog/commands/down.rb +6 -6
- data/lib/hotdog/commands/pssh.rb +79 -42
- data/lib/hotdog/commands/search.rb +9 -9
- data/lib/hotdog/commands/ssh.rb +58 -38
- data/lib/hotdog/commands/up.rb +2 -2
- data/lib/hotdog/commands.rb +85 -134
- data/lib/hotdog/version.rb +1 -1
- data/spec/core/application_spec.rb +3 -3
- data/spec/optparse/down_spec.rb +49 -0
- data/spec/optparse/hosts_spec.rb +33 -0
- data/spec/optparse/pssh_spec.rb +76 -0
- data/spec/optparse/search_spec.rb +33 -0
- data/spec/optparse/ssh_spec.rb +76 -0
- data/spec/optparse/tags_spec.rb +33 -0
- data/spec/optparse/up_spec.rb +33 -0
- metadata +52 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3bcc93be20391d227013b6c05bb9113d68bc404
|
4
|
+
data.tar.gz: 3a8bc479c3122dc4b18ecf37d575e7b49dd8c1f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c9646d739e72b331cdfdf145da4e93b0c44598b64618a20db48eff13185a9bc277550581f2288e20ee548c8001466c454d30d43df900d9cef8e773bcf5f4bef
|
7
|
+
data.tar.gz: d51c0697ca67251ded20b0c2807af26ead5d4f7ed87b3c189ee109ff464c2a5cfccc82efeff20ec8f6cdcd0a2a07ab4ee5c1f374d1df4c14cdf9d5b98994fe03
|
data/hotdog.gemspec
CHANGED
@@ -23,7 +23,9 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "rspec", "~> 3.3.0"
|
24
24
|
|
25
25
|
spec.add_dependency "dogapi", ">= 1.13.0"
|
26
|
+
spec.add_dependency "multi_json", "~> 1.11.2"
|
27
|
+
spec.add_dependency "oj", "~> 2.12.14"
|
28
|
+
spec.add_dependency "parallel", "~> 1.6.1"
|
26
29
|
spec.add_dependency "parslet", "~> 1.6.2"
|
27
30
|
spec.add_dependency "sqlite3", "~> 1.3.10"
|
28
|
-
spec.add_dependency "parallel", "~> 1.4.1"
|
29
31
|
end
|
data/lib/hotdog/application.rb
CHANGED
@@ -13,6 +13,7 @@ module Hotdog
|
|
13
13
|
@optparse = OptionParser.new
|
14
14
|
@optparse.version = Hotdog::VERSION
|
15
15
|
@options = {
|
16
|
+
endpoint: ENV.fetch("DATADOG_HOST", "https://app.datadoghq.com"),
|
16
17
|
api_key: ENV["DATADOG_API_KEY"],
|
17
18
|
application_key: ENV["DATADOG_APPLICATION_KEY"],
|
18
19
|
application: self,
|
@@ -53,7 +54,7 @@ module Hotdog
|
|
53
54
|
|
54
55
|
begin
|
55
56
|
command = ( args.shift || "help" )
|
56
|
-
get_command(command).
|
57
|
+
get_command(command).tap do |cmd|
|
57
58
|
@optparse.banner = "Usage: hotdog #{command} [options]"
|
58
59
|
cmd.define_options(@optparse, @options)
|
59
60
|
args = cmd.parse_options(@optparse, args)
|
@@ -69,7 +70,7 @@ module Hotdog
|
|
69
70
|
options[:headers] = true
|
70
71
|
end
|
71
72
|
|
72
|
-
options[:formatter] = get_formatter(options[:format])
|
73
|
+
options[:formatter] = get_formatter(options[:format])
|
73
74
|
|
74
75
|
if options[:debug] or options[:verbose]
|
75
76
|
options[:logger].level = Logger::DEBUG
|
@@ -86,6 +87,9 @@ module Hotdog
|
|
86
87
|
|
87
88
|
private
|
88
89
|
def define_options
|
90
|
+
@optparse.on("--endpoint ENDPOINT", "Datadog API endpoint") do |endpoint|
|
91
|
+
options[:endpoint] = endpoint
|
92
|
+
end
|
89
93
|
@optparse.on("--api-key API_KEY", "Datadog API key") do |api_key|
|
90
94
|
options[:api_key] = api_key
|
91
95
|
end
|
@@ -139,29 +143,31 @@ module Hotdog
|
|
139
143
|
|
140
144
|
def get_formatter(name)
|
141
145
|
begin
|
142
|
-
Hotdog::Formatters.const_get(const_name(name))
|
146
|
+
klass = Hotdog::Formatters.const_get(const_name(name))
|
143
147
|
rescue NameError
|
144
148
|
if library = find_library("hotdog/formatters", name)
|
145
149
|
load library
|
146
|
-
Hotdog::Formatters.const_get(const_name(File.basename(library, ".rb")))
|
150
|
+
klass = Hotdog::Formatters.const_get(const_name(File.basename(library, ".rb")))
|
147
151
|
else
|
148
152
|
raise(NameError.new("unknown format: #{name}"))
|
149
153
|
end
|
150
154
|
end
|
155
|
+
klass.new
|
151
156
|
end
|
152
157
|
|
153
158
|
def get_command(name)
|
154
159
|
begin
|
155
|
-
Hotdog::Commands.const_get(const_name(name))
|
160
|
+
klass = Hotdog::Commands.const_get(const_name(name))
|
156
161
|
rescue NameError
|
157
162
|
if library = find_library("hotdog/commands", name)
|
158
163
|
load library
|
159
|
-
Hotdog::Commands.const_get(const_name(File.basename(library, ".rb")))
|
164
|
+
klass = Hotdog::Commands.const_get(const_name(File.basename(library, ".rb")))
|
160
165
|
else
|
161
166
|
require "hotdog/commands/help"
|
162
|
-
Hotdog::Commands::Help
|
167
|
+
klass = Hotdog::Commands::Help
|
163
168
|
end
|
164
169
|
end
|
170
|
+
klass.new(self)
|
165
171
|
end
|
166
172
|
|
167
173
|
def find_library(dirname, name)
|
data/lib/hotdog/commands/down.rb
CHANGED
@@ -6,13 +6,13 @@ module Hotdog
|
|
6
6
|
module Commands
|
7
7
|
class Down < BaseCommand
|
8
8
|
def define_options(optparse, options={})
|
9
|
-
|
10
|
-
|
9
|
+
options[:downtime] = 86400
|
10
|
+
options[:start] = Time.new
|
11
11
|
optparse.on("--downtime DURATION") do |v|
|
12
|
-
|
12
|
+
options[:downtime] = v.to_i
|
13
13
|
end
|
14
14
|
optparse.on("--start TIME") do |v|
|
15
|
-
|
15
|
+
options[:start] = Time.parse(v)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -23,8 +23,8 @@ module Hotdog
|
|
23
23
|
else
|
24
24
|
scope = arg
|
25
25
|
end
|
26
|
-
code, schedule =
|
27
|
-
logger.debug("dog.schedule_donwtime(%s, :start => %s, :end => %s) #==> [%s, %s]" % [scope.inspect,
|
26
|
+
code, schedule = dog.schedule_downtime(scope, :start => options[:start].to_i, :end => (options[:start]+options[:downtime]).to_i)
|
27
|
+
logger.debug("dog.schedule_donwtime(%s, :start => %s, :end => %s) #==> [%s, %s]" % [scope.inspect, options[:start].to_i, (options[:start]+options[:downtime]).to_i, code.inspect, schedule.inspect])
|
28
28
|
if code.to_i / 100 != 2
|
29
29
|
raise("dog.schedule_downtime(%s, ...) returns [%s, %s]" % [scope.inspect, code.inspect, schedule.inspect])
|
30
30
|
end
|
data/lib/hotdog/commands/pssh.rb
CHANGED
@@ -14,7 +14,9 @@ module Hotdog
|
|
14
14
|
options[:user] = nil
|
15
15
|
options[:port] = nil
|
16
16
|
options[:identity_file] = nil
|
17
|
+
options[:forward_agent] = false
|
17
18
|
options[:max_parallelism] = nil
|
19
|
+
options[:color] = :auto
|
18
20
|
|
19
21
|
optparse.on("-o SSH_OPTION", "Passes this string to ssh command through shell. This option may be given multiple times") do |option|
|
20
22
|
options[:options] += [option]
|
@@ -22,6 +24,9 @@ module Hotdog
|
|
22
24
|
optparse.on("-i SSH_IDENTITY_FILE", "SSH identity file path") do |path|
|
23
25
|
options[:identity_file] = path
|
24
26
|
end
|
27
|
+
optparse.on("-A", "Enable agent forwarding", TrueClass) do |b|
|
28
|
+
options[:forward_agent] = b
|
29
|
+
end
|
25
30
|
optparse.on("-p PORT", "Port of the remote host", Integer) do |port|
|
26
31
|
options[:port] = port
|
27
32
|
end
|
@@ -31,13 +36,30 @@ module Hotdog
|
|
31
36
|
optparse.on("-P PARALLELISM", "Max parallelism", Integer) do |n|
|
32
37
|
options[:max_parallelism] = n
|
33
38
|
end
|
39
|
+
optparse.on("-v", "--verbose", "Enable verbose ode") do |v|
|
40
|
+
options[:verbose] = v
|
41
|
+
end
|
42
|
+
optparse.on("--color=WHEN", "--colour=WHEN", "Enable colors") do |color|
|
43
|
+
options[:color] = color
|
44
|
+
end
|
34
45
|
end
|
35
46
|
|
47
|
+
def parse_options(optparse, args=[])
|
48
|
+
if args.index("--")
|
49
|
+
@remote_command = args.slice(args.index("--") + 1, args.length).join(" ")
|
50
|
+
optparse.parse(args.slice(0, args.index("--")))
|
51
|
+
else
|
52
|
+
@remote_command = nil
|
53
|
+
optparse.parse(args)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
attr_reader :remote_command
|
57
|
+
|
36
58
|
def run(args=[], options={})
|
37
|
-
use_color = STDOUT.tty?
|
38
59
|
expression = args.join(" ").strip
|
39
|
-
if expression.empty?
|
40
|
-
|
60
|
+
if expression.empty?
|
61
|
+
# return everything if given expression is empty
|
62
|
+
expression = "*"
|
41
63
|
end
|
42
64
|
|
43
65
|
begin
|
@@ -47,61 +69,76 @@ module Hotdog
|
|
47
69
|
exit(1)
|
48
70
|
end
|
49
71
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
STDERR.puts("no match found: #{
|
72
|
+
result0 = evaluate(node, self)
|
73
|
+
if 0 < result0.length
|
74
|
+
exec_command(result0, options)
|
75
|
+
else
|
76
|
+
STDERR.puts("no match found: #{expression}")
|
55
77
|
exit(1)
|
56
78
|
end
|
79
|
+
end
|
57
80
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
if path = options[:identity_file]
|
66
|
-
cmdline << "-i" << Shellwords.escape(path)
|
67
|
-
end
|
68
|
-
if port = options[:port]
|
69
|
-
cmdline << "-p" << port.to_s
|
70
|
-
end
|
71
|
-
if options[:forward_agent]
|
72
|
-
cmdline << "-A"
|
73
|
-
end
|
74
|
-
|
75
|
-
cmdline << "-o" << "BatchMode=yes"
|
76
|
-
|
77
|
-
user = options[:user]
|
78
|
-
|
79
|
-
threads = options[:max_parallelism] || addresses.size
|
80
|
-
stats = Parallel.map(addresses, in_threads: threads) { |address,name|
|
81
|
-
if use_color
|
81
|
+
def exec_command(result0, options={})
|
82
|
+
result, fields = get_hosts(result0)
|
83
|
+
hosts = result.flatten
|
84
|
+
threads = options[:max_parallelism] || hosts.size
|
85
|
+
stats = Parallel.map(hosts.zip(hosts), in_threads: threads) { |host, name|
|
86
|
+
if use_color?
|
82
87
|
header = "\e[0;36m#{name}\e[00m"
|
83
88
|
else
|
84
89
|
header = name
|
85
90
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
else
|
90
|
-
c << address
|
91
|
-
end
|
92
|
-
logger.debug("execute: #{Shellwords.join(c)}")
|
93
|
-
IO.popen([*c, in: :close, err: [:child, :out]]) do |io|
|
91
|
+
cmdline = build_command_string(host, options)
|
92
|
+
logger.debug("execute: #{cmdline}")
|
93
|
+
IO.popen(cmdline, in: :close, err: [:child, :out]) do |io|
|
94
94
|
io.each_line do |line|
|
95
|
-
STDOUT.write
|
95
|
+
STDOUT.write("#{header}: #{line}")
|
96
96
|
end
|
97
97
|
end
|
98
98
|
$?.success? # $? is thread-local variable
|
99
99
|
}
|
100
|
-
|
101
100
|
unless stats.all?
|
102
101
|
exit(1)
|
103
102
|
end
|
104
103
|
end
|
104
|
+
|
105
|
+
def build_command_string(host, options={})
|
106
|
+
# build ssh command
|
107
|
+
base_cmdline = ["ssh"]
|
108
|
+
if options[:forward_agent]
|
109
|
+
base_cmdline << "-A"
|
110
|
+
end
|
111
|
+
if options[:identity_file]
|
112
|
+
base_cmdline << "-i" << options[:identity_file]
|
113
|
+
end
|
114
|
+
if options[:user]
|
115
|
+
base_cmdline << "-l" << options[:user]
|
116
|
+
end
|
117
|
+
base_cmdline << "-o" << "BatchMode=yes"
|
118
|
+
if options[:options]
|
119
|
+
base_cmdline += options[:options].flat_map { |option| ["-o", option] }
|
120
|
+
end
|
121
|
+
if options[:port]
|
122
|
+
base_cmdline << "-p" << options[:port].to_s
|
123
|
+
end
|
124
|
+
cmdline = base_cmdline + [host]
|
125
|
+
if @remote_command
|
126
|
+
cmdline << "--" << @remote_command
|
127
|
+
end
|
128
|
+
Shellwords.join(cmdline)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def use_color?
|
133
|
+
case options[:color]
|
134
|
+
when :always
|
135
|
+
true
|
136
|
+
when :never
|
137
|
+
false
|
138
|
+
else
|
139
|
+
STDOUT.tty?
|
140
|
+
end
|
141
|
+
end
|
105
142
|
end
|
106
143
|
end
|
107
144
|
end
|
@@ -26,18 +26,18 @@ module Hotdog
|
|
26
26
|
exit(1)
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
if 0 <
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
logger.info("found %d host(s)." % result.length)
|
29
|
+
result0 = evaluate(node, self)
|
30
|
+
if 0 < result0.length
|
31
|
+
result, fields = get_hosts_with_search_tags(result0, node)
|
32
|
+
if options[:limit]
|
33
|
+
STDOUT.print(format(result.take(options[:limit]), fields: fields))
|
34
|
+
logger.info("found %d host(s), limited to %d in result." % [result.length, options[:limit]])
|
36
35
|
else
|
37
|
-
|
36
|
+
STDOUT.print(format(result, fields: fields))
|
37
|
+
logger.info("found %d host(s)." % result.length)
|
38
38
|
end
|
39
39
|
else
|
40
|
-
STDERR.puts("no match found: #{
|
40
|
+
STDERR.puts("no match found: #{expression}")
|
41
41
|
exit(1)
|
42
42
|
end
|
43
43
|
end
|
data/lib/hotdog/commands/ssh.rb
CHANGED
@@ -15,7 +15,6 @@ module Hotdog
|
|
15
15
|
options[:port] = nil
|
16
16
|
options[:identity_file] = nil
|
17
17
|
options[:forward_agent] = false
|
18
|
-
options[:verbose] = false
|
19
18
|
|
20
19
|
optparse.on("-n", "--index INDEX", "Use this index of host if multiple servers are found", Integer) do |index|
|
21
20
|
options[:index] = index
|
@@ -40,10 +39,22 @@ module Hotdog
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
42
|
+
def parse_options(optparse, args=[])
|
43
|
+
if args.index("--")
|
44
|
+
@remote_command = args.slice(args.index("--") + 1, args.length).join(" ")
|
45
|
+
optparse.parse(args.slice(0, args.index("--")))
|
46
|
+
else
|
47
|
+
@remote_command = nil
|
48
|
+
optparse.parse(args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
attr_reader :remote_command
|
52
|
+
|
43
53
|
def run(args=[], options={})
|
44
54
|
expression = args.join(" ").strip
|
45
55
|
if expression.empty?
|
46
|
-
|
56
|
+
# return everything if given expression is empty
|
57
|
+
expression = "*"
|
47
58
|
end
|
48
59
|
|
49
60
|
begin
|
@@ -53,57 +64,66 @@ module Hotdog
|
|
53
64
|
exit(1)
|
54
65
|
end
|
55
66
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
elsif result.empty?
|
61
|
-
STDERR.puts("no match found: #{search_args.join(" ")}")
|
62
|
-
exit(1)
|
63
|
-
else
|
64
|
-
if options[:index] && result.length > options[:index]
|
65
|
-
host = result[options[:index]]
|
67
|
+
result0 = evaluate(node, self)
|
68
|
+
if 0 < result0.length
|
69
|
+
if result0.length == 1
|
70
|
+
exec_command([result0.first], options)
|
66
71
|
else
|
67
|
-
|
72
|
+
if options[:index] and options[:index] < result0.length
|
73
|
+
exec_command([result0[options[:index]]], options)
|
74
|
+
else
|
75
|
+
result, fields = get_hosts_with_search_tags(result0, node)
|
68
76
|
|
69
|
-
|
70
|
-
|
71
|
-
|
77
|
+
# add "index" field
|
78
|
+
result = result.each_with_index.map { |host, i| [i] + host }
|
79
|
+
fields = ["index"] + fields
|
72
80
|
|
73
|
-
|
74
|
-
|
75
|
-
|
81
|
+
STDERR.print(format(result, fields: fields))
|
82
|
+
logger.info("found %d host(s)." % result.length)
|
83
|
+
exit(1)
|
84
|
+
end
|
76
85
|
end
|
86
|
+
else
|
87
|
+
STDERR.puts("no match found: #{expression}")
|
88
|
+
exit(1)
|
77
89
|
end
|
90
|
+
exit(127)
|
91
|
+
end
|
78
92
|
|
79
|
-
|
80
|
-
|
93
|
+
def exec_command(result0, options={})
|
94
|
+
result, fields = get_hosts(result0)
|
95
|
+
hosts = result.flatten
|
96
|
+
cmdline = build_command_string(hosts.first, options)
|
97
|
+
logger.debug("execute: #{cmdline}")
|
98
|
+
exec(cmdline)
|
99
|
+
end
|
81
100
|
|
101
|
+
def build_command_string(host, options={})
|
82
102
|
# build ssh command
|
83
|
-
|
84
|
-
options[:
|
85
|
-
|
103
|
+
base_cmdline = ["ssh"]
|
104
|
+
if options[:forward_agent]
|
105
|
+
base_cmdline << "-A"
|
86
106
|
end
|
87
|
-
if
|
88
|
-
|
107
|
+
if options[:identity_file]
|
108
|
+
base_cmdline << "-i" << options[:identity_file]
|
89
109
|
end
|
90
|
-
if
|
91
|
-
|
110
|
+
if options[:user]
|
111
|
+
base_cmdline << "-l" << options[:user]
|
92
112
|
end
|
93
|
-
if options[:
|
94
|
-
|
113
|
+
if options[:options]
|
114
|
+
base_cmdline += options[:options].flat_map { |option| ["-o", option] }
|
115
|
+
end
|
116
|
+
if options[:port]
|
117
|
+
base_cmdline << "-p" << options[:port].to_s
|
95
118
|
end
|
96
119
|
if options[:verbose]
|
97
|
-
|
120
|
+
base_cmdline << "-v"
|
98
121
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
cmdline << address
|
122
|
+
cmdline = base_cmdline + [host]
|
123
|
+
if @remote_command
|
124
|
+
cmdline << "--" << @remote_command
|
103
125
|
end
|
104
|
-
|
105
|
-
exec(*cmdline)
|
106
|
-
exit(127)
|
126
|
+
Shellwords.join(cmdline)
|
107
127
|
end
|
108
128
|
end
|
109
129
|
end
|
data/lib/hotdog/commands/up.rb
CHANGED
@@ -13,7 +13,7 @@ module Hotdog
|
|
13
13
|
arg
|
14
14
|
end
|
15
15
|
}
|
16
|
-
code, all_downtimes =
|
16
|
+
code, all_downtimes = dog.get_all_downtimes()
|
17
17
|
if code.to_i / 100 != 2
|
18
18
|
raise("dog.get_all_downtimes() returns [%s, %s]" % [code.inspect, all_downtimes.inspect])
|
19
19
|
end
|
@@ -23,7 +23,7 @@ module Hotdog
|
|
23
23
|
}
|
24
24
|
|
25
25
|
cancel_downtimes.each do |downtime|
|
26
|
-
code, cancel =
|
26
|
+
code, cancel = dog.cancel_downtime(downtime["id"])
|
27
27
|
if code.to_i / 100 != 2
|
28
28
|
raise("dog.cancel_downtime(%s) returns [%s, %s]" % [downtime["id"].inspect, code.inspect, cancel.inspect])
|
29
29
|
end
|
data/lib/hotdog/commands.rb
CHANGED
@@ -2,8 +2,12 @@
|
|
2
2
|
|
3
3
|
require "fileutils"
|
4
4
|
require "dogapi"
|
5
|
-
require "
|
5
|
+
require "multi_json"
|
6
|
+
require "oj"
|
7
|
+
require "open-uri"
|
8
|
+
require "parallel"
|
6
9
|
require "sqlite3"
|
10
|
+
require "uri"
|
7
11
|
|
8
12
|
module Hotdog
|
9
13
|
module Commands
|
@@ -18,7 +22,7 @@ module Hotdog
|
|
18
22
|
@application = application
|
19
23
|
@logger = application.options[:logger]
|
20
24
|
@options = application.options
|
21
|
-
@dog =
|
25
|
+
@dog = nil # lazy initialization
|
22
26
|
@prepared_statements = {}
|
23
27
|
end
|
24
28
|
attr_reader :application
|
@@ -31,13 +35,7 @@ module Hotdog
|
|
31
35
|
|
32
36
|
def execute(q, args=[])
|
33
37
|
update_db
|
34
|
-
|
35
|
-
logger.debug("execute: #{q} -- #{args.inspect}")
|
36
|
-
prepare(@db, q).execute(args)
|
37
|
-
rescue
|
38
|
-
logger.error("failed: #{q} -- #{args.inspect}")
|
39
|
-
raise
|
40
|
-
end
|
38
|
+
execute_db(@db, q, args)
|
41
39
|
end
|
42
40
|
|
43
41
|
def fixed_string?()
|
@@ -183,9 +181,12 @@ module Hotdog
|
|
183
181
|
if (not options[:force] and File.exist?(persistent) and Time.new < File.mtime(persistent) + options[:expiry]) or options[:offline]
|
184
182
|
begin
|
185
183
|
persistent_db = SQLite3::Database.new(persistent)
|
186
|
-
persistent_db.execute(
|
187
|
-
|
188
|
-
|
184
|
+
persistent_db.execute(<<-EOS)
|
185
|
+
SELECT hosts_tags.host_id FROM hosts_tags
|
186
|
+
INNER JOIN hosts ON hosts_tags.host_id = hosts.id
|
187
|
+
INNER JOIN tags ON hosts_tags.tag_id = tags.id
|
188
|
+
LIMIT 1;
|
189
|
+
EOS
|
189
190
|
@db = persistent_db
|
190
191
|
return
|
191
192
|
rescue SQLite3::SQLException
|
@@ -198,12 +199,28 @@ module Hotdog
|
|
198
199
|
end
|
199
200
|
|
200
201
|
memory_db = SQLite3::Database.new(":memory:")
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
202
|
+
execute_db(memory_db, <<-EOS)
|
203
|
+
CREATE TABLE IF NOT EXISTS hosts (
|
204
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
205
|
+
name VARCHAR(255) NOT NULL COLLATE NOCASE
|
206
|
+
);
|
207
|
+
EOS
|
208
|
+
execute_db(memory_db, "CREATE UNIQUE INDEX IF NOT EXISTS hosts_name ON hosts ( name );")
|
209
|
+
execute_db(memory_db, <<-EOS)
|
210
|
+
CREATE TABLE IF NOT EXISTS tags (
|
211
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
212
|
+
name VARCHAR(200) NOT NULL COLLATE NOCASE,
|
213
|
+
value VARCHAR(200) NOT NULL COLLATE NOCASE
|
214
|
+
);
|
215
|
+
EOS
|
216
|
+
execute_db(memory_db, "CREATE UNIQUE INDEX IF NOT EXISTS tags_name_value ON tags ( name, value );")
|
217
|
+
execute_db(memory_db, <<-EOS)
|
218
|
+
CREATE TABLE IF NOT EXISTS hosts_tags (
|
219
|
+
host_id INTEGER NOT NULL,
|
220
|
+
tag_id INTEGER NOT NULL
|
221
|
+
);
|
222
|
+
EOS
|
223
|
+
execute_db(memory_db, "CREATE UNIQUE INDEX IF NOT EXISTS hosts_tags_host_id_tag_id ON hosts_tags ( host_id, tag_id );")
|
207
224
|
|
208
225
|
all_tags = get_all_tags()
|
209
226
|
|
@@ -211,23 +228,13 @@ module Hotdog
|
|
211
228
|
known_tags = all_tags.keys.map { |tag| split_tag(tag) }.uniq
|
212
229
|
known_tags.each_slice(SQLITE_LIMIT_COMPOUND_SELECT / 2) do |known_tags|
|
213
230
|
q = "INSERT OR IGNORE INTO tags (name, value) VALUES %s" % known_tags.map { "(?, ?)" }.join(", ")
|
214
|
-
|
215
|
-
prepare(memory_db, q).execute(known_tags)
|
216
|
-
rescue
|
217
|
-
logger.error("failed: #{q} -- #{known_tags.inspect}")
|
218
|
-
raise
|
219
|
-
end
|
231
|
+
execute_db(memory_db, q, known_tags)
|
220
232
|
end
|
221
233
|
|
222
234
|
known_hosts = all_tags.values.reduce(:+).uniq
|
223
235
|
known_hosts.each_slice(SQLITE_LIMIT_COMPOUND_SELECT) do |known_hosts|
|
224
236
|
q = "INSERT OR IGNORE INTO hosts (name) VALUES %s" % known_hosts.map { "(?)" }.join(", ")
|
225
|
-
|
226
|
-
prepare(memory_db, q).execute(known_hosts)
|
227
|
-
rescue
|
228
|
-
logger.error("failed: #{q} -- #{known_hosts.inspect}")
|
229
|
-
raise
|
230
|
-
end
|
237
|
+
execute_db(memory_db, q, known_hosts)
|
231
238
|
end
|
232
239
|
|
233
240
|
all_tags.each do |tag, hosts|
|
@@ -237,10 +244,18 @@ module Hotdog
|
|
237
244
|
"( SELECT id FROM hosts WHERE name IN (%s) ) AS host, " \
|
238
245
|
"( SELECT id FROM tags WHERE name = ? AND value = ? LIMIT 1 ) AS tag;" % hosts.map { "?" }.join(", ")
|
239
246
|
begin
|
240
|
-
|
241
|
-
rescue
|
242
|
-
|
243
|
-
|
247
|
+
execute_db(memory_db, q, (hosts + split_tag(tag)))
|
248
|
+
rescue SQLite3::RangeException => error
|
249
|
+
# FIXME: bulk insert occationally fails even if there are no errors in bind parameters
|
250
|
+
# `bind_param': bind or column index out of range (SQLite3::RangeException)
|
251
|
+
logger.warn("bulk insert failed due to #{error.message}. fallback to normal insert.")
|
252
|
+
hosts.each do |host|
|
253
|
+
q = "INSERT OR REPLACE INTO hosts_tags (host_id, tag_id) " \
|
254
|
+
"SELECT host.id, tag.id FROM " \
|
255
|
+
"( SELECT id FROM hosts WHERE name = ? ) AS host, " \
|
256
|
+
"( SELECT id FROM tags WHERE name = ? AND value = ? LIMIT 1 ) AS tag;"
|
257
|
+
execute_db(memory_db, q, [host] + split_tag(tag))
|
258
|
+
end
|
244
259
|
end
|
245
260
|
end
|
246
261
|
end
|
@@ -257,19 +272,37 @@ module Hotdog
|
|
257
272
|
end
|
258
273
|
end
|
259
274
|
|
260
|
-
def
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
275
|
+
def execute_db(db, q, args=[])
|
276
|
+
begin
|
277
|
+
logger.debug("execute: #{q} -- #{args.inspect}")
|
278
|
+
prepare(db, q).execute(args)
|
279
|
+
rescue
|
280
|
+
logger.error("failed: #{q} -- #{args.inspect}")
|
281
|
+
raise
|
265
282
|
end
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
283
|
+
end
|
284
|
+
|
285
|
+
def get_all_tags() #==> Hash<Tag,Array<Host>>
|
286
|
+
endpoint = options[:endpoint]
|
287
|
+
requests = {all_downtime: "/api/v1/downtime", all_tags: "/api/v1/tags/hosts"}
|
288
|
+
query = URI.encode_www_form(api_key: options[:api_key], application_key: options[:application_key])
|
289
|
+
begin
|
290
|
+
responses = Hash[Parallel.map(requests) { |name, request_path|
|
291
|
+
uri = URI.join(endpoint, "#{request_path}?#{query}")
|
292
|
+
begin
|
293
|
+
response = uri.open("User-Agent" => "hotdog/#{Hotdog::VERSION}") { |fp| fp.read }
|
294
|
+
[name, MultiJson.load(response)]
|
295
|
+
rescue OpenURI::HTTPError => error
|
296
|
+
code, body = error.io.status
|
297
|
+
raise(RuntimeError.new("dog.get_#{name}() returns [#{code.inspect}, ...]"))
|
298
|
+
end
|
299
|
+
}]
|
300
|
+
rescue => error
|
301
|
+
STDERR.puts(error.message)
|
302
|
+
exit(1)
|
270
303
|
end
|
271
304
|
now = Time.new.to_i
|
272
|
-
downtimes =
|
305
|
+
downtimes = responses.fetch(:all_downtime, []).select { |downtime|
|
273
306
|
# active downtimes
|
274
307
|
downtime["active"] and ( downtime["start"].nil? or downtime["start"] < now ) and ( downtime["end"].nil? or now <= downtime["end"] )
|
275
308
|
}.flat_map { |downtime|
|
@@ -279,7 +312,11 @@ module Hotdog
|
|
279
312
|
if not downtimes.empty?
|
280
313
|
logger.info("ignore host(s) with scheduled downtimes: #{downtimes.inspect}")
|
281
314
|
end
|
282
|
-
Hash[all_tags
|
315
|
+
Hash[responses.fetch(:all_tags, {}).fetch("tags", []).map { |tag, hosts| [tag, hosts.reject { |host| downtimes.include?(host) }] }]
|
316
|
+
end
|
317
|
+
|
318
|
+
def dog()
|
319
|
+
@dog ||= Dogapi::Client.new(options[:api_key], options[:application_key])
|
283
320
|
end
|
284
321
|
|
285
322
|
def split_tag(tag)
|
@@ -296,95 +333,9 @@ module Hotdog
|
|
296
333
|
end
|
297
334
|
|
298
335
|
def copy_db(src, dst)
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
create_table_tags(dst)
|
303
|
-
create_table_hosts_tags(dst)
|
304
|
-
|
305
|
-
hosts = prepare(src, "SELECT id, name FROM hosts").execute().to_a
|
306
|
-
hosts.each_slice(SQLITE_LIMIT_COMPOUND_SELECT / 2) do |hosts|
|
307
|
-
q = "INSERT INTO hosts (id, name) VALUES %s" % hosts.map { "(?, ?)" }.join(", ")
|
308
|
-
begin
|
309
|
-
prepare(dst, q).execute(hosts)
|
310
|
-
rescue
|
311
|
-
logger.error("failed: #{q} -- #{hosts.inspect}")
|
312
|
-
raise
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
tags = prepare(src, "SELECT id, name, value FROM tags").execute().to_a
|
317
|
-
tags.each_slice(SQLITE_LIMIT_COMPOUND_SELECT / 3) do |tags|
|
318
|
-
q = "INSERT INTO tags (id, name, value) VALUES %s" % tags.map { "(?, ?, ?)" }.join(", ")
|
319
|
-
begin
|
320
|
-
prepare(dst, q).execute(tags)
|
321
|
-
rescue
|
322
|
-
logger.error("failed: #{q} -- #{tags.inspect}")
|
323
|
-
raise
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
hosts_tags = prepare(src, "SELECT host_id, tag_id FROM hosts_tags").to_a
|
328
|
-
hosts_tags.each_slice(SQLITE_LIMIT_COMPOUND_SELECT / 2) do |hosts_tags|
|
329
|
-
q = "INSERT INTO hosts_tags (host_id, tag_id) VALUES %s" % hosts_tags.map { "(?, ?)" }.join(", ")
|
330
|
-
begin
|
331
|
-
prepare(dst, q).execute(hosts_tags)
|
332
|
-
rescue
|
333
|
-
logger.error("failed: #{q} -- #{hosts_tags.inspect}")
|
334
|
-
raise
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
create_index_hosts(dst)
|
339
|
-
create_index_tags(dst)
|
340
|
-
create_index_hosts_tags(dst)
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
def create_table_hosts(db)
|
345
|
-
q = "CREATE TABLE IF NOT EXISTS hosts ( " \
|
346
|
-
"id INTEGER PRIMARY KEY AUTOINCREMENT, " \
|
347
|
-
"name VARCHAR(255) NOT NULL COLLATE NOCASE " \
|
348
|
-
");"
|
349
|
-
logger.debug(q)
|
350
|
-
db.execute(q)
|
351
|
-
end
|
352
|
-
|
353
|
-
def create_index_hosts(db)
|
354
|
-
q = "CREATE UNIQUE INDEX IF NOT EXISTS hosts_name ON hosts ( name );"
|
355
|
-
logger.debug(q)
|
356
|
-
db.execute(q)
|
357
|
-
end
|
358
|
-
|
359
|
-
def create_table_tags(db)
|
360
|
-
q = "CREATE TABLE IF NOT EXISTS tags ( " \
|
361
|
-
"id INTEGER PRIMARY KEY AUTOINCREMENT, " \
|
362
|
-
"name VARCHAR(200) NOT NULL COLLATE NOCASE, " \
|
363
|
-
"value VARCHAR(200) NOT NULL COLLATE NOCASE " \
|
364
|
-
");"
|
365
|
-
logger.debug(q)
|
366
|
-
db.execute(q)
|
367
|
-
end
|
368
|
-
|
369
|
-
def create_index_tags(db)
|
370
|
-
q = "CREATE UNIQUE INDEX IF NOT EXISTS tags_name_value ON tags ( name, value );"
|
371
|
-
logger.debug(q)
|
372
|
-
db.execute(q)
|
373
|
-
end
|
374
|
-
|
375
|
-
def create_table_hosts_tags(db)
|
376
|
-
q = "CREATE TABLE IF NOT EXISTS hosts_tags ( " \
|
377
|
-
"host_id INTEGER NOT NULL, " \
|
378
|
-
"tag_id INTEGER NOT NULL " \
|
379
|
-
");"
|
380
|
-
logger.debug(q)
|
381
|
-
db.execute(q)
|
382
|
-
end
|
383
|
-
|
384
|
-
def create_index_hosts_tags(db)
|
385
|
-
q = "CREATE UNIQUE INDEX IF NOT EXISTS hosts_tags_host_id_tag_id ON hosts_tags ( host_id, tag_id );"
|
386
|
-
logger.debug(q)
|
387
|
-
db.execute(q)
|
336
|
+
backup = SQLite3::Backup.new(dst, "main", src, "main")
|
337
|
+
backup.step(-1)
|
338
|
+
backup.finish
|
388
339
|
end
|
389
340
|
end
|
390
341
|
end
|
data/lib/hotdog/version.rb
CHANGED
@@ -23,9 +23,9 @@ describe "application" do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it "returns proper class by name" do
|
26
|
-
expect(app.__send__(:get_command, "hosts")).to
|
27
|
-
expect(app.__send__(:get_command, "search")).to
|
28
|
-
expect(app.__send__(:get_command, "tags")).to
|
26
|
+
expect(app.__send__(:get_command, "hosts")).to be_a(Hotdog::Commands::Hosts)
|
27
|
+
expect(app.__send__(:get_command, "search")).to be_a(Hotdog::Commands::Search)
|
28
|
+
expect(app.__send__(:get_command, "tags")).to be_a(Hotdog::Commands::Tags)
|
29
29
|
end
|
30
30
|
|
31
31
|
it "raises error if the action is base-command" do
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/down"
|
4
|
+
|
5
|
+
describe "option parser for down" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Down.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("down") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "cannot handle subcommand options before subcommand" do
|
21
|
+
expect {
|
22
|
+
app.main(["--downtime", "86400", "down", "foo", "bar", "baz"])
|
23
|
+
}.to raise_error(OptionParser::InvalidOption)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can handle subcommand options after subcommand" do
|
27
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
28
|
+
downtime: 12345,
|
29
|
+
verbose: false,
|
30
|
+
))
|
31
|
+
app.main(["down", "--downtime", "12345", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can handle common options before subcommand" do
|
35
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
36
|
+
downtime: 12345,
|
37
|
+
verbose: true,
|
38
|
+
))
|
39
|
+
app.main(["--verbose", "down", "--downtime", "12345", "foo", "bar", "baz"])
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can handle common options after subcommand" do
|
43
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
44
|
+
downtime: 12345,
|
45
|
+
verbose: true,
|
46
|
+
))
|
47
|
+
app.main(["down", "--downtime", "12345", "--verbose", "foo", "bar", "baz"])
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/hosts"
|
4
|
+
|
5
|
+
describe "option parser for hosts" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Hosts.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("hosts") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can handle common options before subcommand" do
|
21
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
22
|
+
verbose: true,
|
23
|
+
))
|
24
|
+
app.main(["--verbose", "hosts", "foo", "bar", "baz"])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can handle common options after subcommand" do
|
28
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
29
|
+
verbose: true,
|
30
|
+
))
|
31
|
+
app.main(["hosts", "--verbose", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/pssh"
|
4
|
+
|
5
|
+
describe "option parser for pssh" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Pssh.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("pssh") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "cannot handle subcommand options before subcommand" do
|
21
|
+
expect {
|
22
|
+
app.main(["-P", "42", "pssh", "foo", "bar", "baz"])
|
23
|
+
}.to raise_error(OptionParser::InvalidOption)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can handle subcommand options after subcommand" do
|
27
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
28
|
+
max_parallelism: 42,
|
29
|
+
verbose: false,
|
30
|
+
))
|
31
|
+
app.main(["pssh", "-P", "42", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can handle common options before subcommand" do
|
35
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
36
|
+
max_parallelism: 42,
|
37
|
+
verbose: true,
|
38
|
+
))
|
39
|
+
app.main(["--verbose", "pssh", "-P", "42", "foo", "bar", "baz"])
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can handle common options after subcommand" do
|
43
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
44
|
+
max_parallelism: 42,
|
45
|
+
verbose: true,
|
46
|
+
))
|
47
|
+
app.main(["pssh", "-P", "42", "--verbose", "foo", "bar", "baz"])
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can handle subcommand options with remote command, 1" do
|
51
|
+
allow(cmd).to receive(:run).with([], a_hash_including(
|
52
|
+
max_parallelism: 42,
|
53
|
+
verbose: true,
|
54
|
+
))
|
55
|
+
app.main(["pssh", "-P", "42", "--verbose", "--", "foo", "bar", "baz"])
|
56
|
+
expect(cmd.remote_command).to eq("foo bar baz")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "can handle subcommand options with remote command, 2" do
|
60
|
+
allow(cmd).to receive(:run).with(["foo"], a_hash_including(
|
61
|
+
max_parallelism: 42,
|
62
|
+
verbose: true,
|
63
|
+
))
|
64
|
+
app.main(["pssh", "-P", "42", "--verbose", "foo", "--", "bar", "baz"])
|
65
|
+
expect(cmd.remote_command).to eq("bar baz")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "can handle subcommand options with remote command, 3" do
|
69
|
+
allow(cmd).to receive(:run).with(["foo"], a_hash_including(
|
70
|
+
max_parallelism: 42,
|
71
|
+
verbose: true,
|
72
|
+
))
|
73
|
+
app.main(["pssh", "-P", "42", "--verbose", "foo", "--", "bar", "--", "baz"])
|
74
|
+
expect(cmd.remote_command).to eq("bar -- baz")
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/search"
|
4
|
+
|
5
|
+
describe "option parser for search" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Search.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("search") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can handle common options before subcommand" do
|
21
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
22
|
+
verbose: true,
|
23
|
+
))
|
24
|
+
app.main(["--verbose", "search", "foo", "bar", "baz"])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can handle common options after subcommand" do
|
28
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
29
|
+
verbose: true,
|
30
|
+
))
|
31
|
+
app.main(["search", "--verbose", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/ssh"
|
4
|
+
|
5
|
+
describe "option parser for ssh" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Ssh.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("ssh") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "cannot handle subcommand options before subcommand" do
|
21
|
+
expect {
|
22
|
+
app.main(["--index", "42", "ssh", "foo", "bar", "baz"])
|
23
|
+
}.to raise_error(OptionParser::InvalidOption)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can handle subcommand options after subcommand" do
|
27
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
28
|
+
index: 42,
|
29
|
+
verbose: false,
|
30
|
+
))
|
31
|
+
app.main(["ssh", "--index", "42", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can handle common options before subcommand" do
|
35
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
36
|
+
index: 42,
|
37
|
+
verbose: true,
|
38
|
+
))
|
39
|
+
app.main(["--verbose", "ssh", "--index", "42", "foo", "bar", "baz"])
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can handle common options after subcommand" do
|
43
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
44
|
+
index: 42,
|
45
|
+
verbose: true,
|
46
|
+
))
|
47
|
+
app.main(["ssh", "--index", "42", "--verbose", "foo", "bar", "baz"])
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can handle subcommand options with remote command, 1" do
|
51
|
+
allow(cmd).to receive(:run).with([], a_hash_including(
|
52
|
+
index: 42,
|
53
|
+
verbose: true,
|
54
|
+
))
|
55
|
+
app.main(["ssh", "--index", "42", "--verbose", "--", "foo", "bar", "baz"])
|
56
|
+
expect(cmd.remote_command).to eq("foo bar baz")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "can handle subcommand options with remote command, 2" do
|
60
|
+
allow(cmd).to receive(:run).with(["foo"], a_hash_including(
|
61
|
+
index: 42,
|
62
|
+
verbose: true,
|
63
|
+
))
|
64
|
+
app.main(["ssh", "--index", "42", "--verbose", "foo", "--", "bar", "baz"])
|
65
|
+
expect(cmd.remote_command).to eq("bar baz")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "can handle subcommand options with remote command, 3" do
|
69
|
+
allow(cmd).to receive(:run).with(["foo"], a_hash_including(
|
70
|
+
index: 42,
|
71
|
+
verbose: true,
|
72
|
+
))
|
73
|
+
app.main(["ssh", "--index", "42", "--verbose", "foo", "--", "bar", "--", "baz"])
|
74
|
+
expect(cmd.remote_command).to eq("bar -- baz")
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/tags"
|
4
|
+
|
5
|
+
describe "option parser for tags" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Tags.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("tags") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can handle common options before subcommand" do
|
21
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
22
|
+
verbose: true,
|
23
|
+
))
|
24
|
+
app.main(["--verbose", "tags", "foo", "bar", "baz"])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can handle common options after subcommand" do
|
28
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
29
|
+
verbose: true,
|
30
|
+
))
|
31
|
+
app.main(["tags", "--verbose", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands/up"
|
4
|
+
|
5
|
+
describe "option parser for up" do
|
6
|
+
let(:app) {
|
7
|
+
Hotdog::Application.new
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:cmd) {
|
11
|
+
Hotdog::Commands::Up.new(app)
|
12
|
+
}
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
allow(app).to receive(:get_command).with("up") {
|
16
|
+
cmd
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can handle common options before subcommand" do
|
21
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
22
|
+
verbose: true,
|
23
|
+
))
|
24
|
+
app.main(["--verbose", "up", "foo", "bar", "baz"])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can handle common options after subcommand" do
|
28
|
+
allow(cmd).to receive(:run).with(["foo", "bar", "baz"], a_hash_including(
|
29
|
+
verbose: true,
|
30
|
+
))
|
31
|
+
app.main(["up", "--verbose", "foo", "bar", "baz"])
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotdog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yamashita Yuu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -67,47 +67,75 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.13.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: multi_json
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 1.
|
75
|
+
version: 1.11.2
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.
|
82
|
+
version: 1.11.2
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: oj
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 2.12.14
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 2.12.14
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: parallel
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.
|
103
|
+
version: 1.6.1
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.6.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: parslet
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.6.2
|
104
118
|
type: :runtime
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.
|
124
|
+
version: 1.6.2
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sqlite3
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.3.10
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.3.10
|
111
139
|
description: Yet another command-line tool for Datadog
|
112
140
|
email:
|
113
141
|
- peek824545201@gmail.com
|
@@ -153,6 +181,13 @@ files:
|
|
153
181
|
- spec/formatter/text_spec.rb
|
154
182
|
- spec/formatter/tsv_spec.rb
|
155
183
|
- spec/formatter/yaml_spec.rb
|
184
|
+
- spec/optparse/down_spec.rb
|
185
|
+
- spec/optparse/hosts_spec.rb
|
186
|
+
- spec/optparse/pssh_spec.rb
|
187
|
+
- spec/optparse/search_spec.rb
|
188
|
+
- spec/optparse/ssh_spec.rb
|
189
|
+
- spec/optparse/tags_spec.rb
|
190
|
+
- spec/optparse/up_spec.rb
|
156
191
|
- spec/parser/glob_expression_spec.rb
|
157
192
|
- spec/parser/parser_spec.rb
|
158
193
|
- spec/parser/regexp_expression_spec.rb
|
@@ -192,6 +227,13 @@ test_files:
|
|
192
227
|
- spec/formatter/text_spec.rb
|
193
228
|
- spec/formatter/tsv_spec.rb
|
194
229
|
- spec/formatter/yaml_spec.rb
|
230
|
+
- spec/optparse/down_spec.rb
|
231
|
+
- spec/optparse/hosts_spec.rb
|
232
|
+
- spec/optparse/pssh_spec.rb
|
233
|
+
- spec/optparse/search_spec.rb
|
234
|
+
- spec/optparse/ssh_spec.rb
|
235
|
+
- spec/optparse/tags_spec.rb
|
236
|
+
- spec/optparse/up_spec.rb
|
195
237
|
- spec/parser/glob_expression_spec.rb
|
196
238
|
- spec/parser/parser_spec.rb
|
197
239
|
- spec/parser/regexp_expression_spec.rb
|