hotdog 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dad54741d7b612af34df19f0ae934c938411a941
4
- data.tar.gz: 951a0d2bafcf5edbc3262e9f1552b4aade13fc0c
3
+ metadata.gz: f3bcc93be20391d227013b6c05bb9113d68bc404
4
+ data.tar.gz: 3a8bc479c3122dc4b18ecf37d575e7b49dd8c1f8
5
5
  SHA512:
6
- metadata.gz: 9c4fdc6b65e2caa37150c2e47bf207cacfec32d775e7f23b9e7b79298935853b5c34dc094d75ee21b48187d9440b3d4d9ae787a212387a5ae3415e1e5caac7df
7
- data.tar.gz: 8e71095cbea2abee8f03173cfda463b289326a4a2a0fa187bd45040856e32e287f8ab84c270bacaa785f15ec6dddb052e126941438c6a353ed9d5e417b74140c
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
@@ -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).new(self).tap do |cmd|
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]).new
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)
@@ -6,13 +6,13 @@ module Hotdog
6
6
  module Commands
7
7
  class Down < BaseCommand
8
8
  def define_options(optparse, options={})
9
- @downtime = 86400
10
- @start = Time.new
9
+ options[:downtime] = 86400
10
+ options[:start] = Time.new
11
11
  optparse.on("--downtime DURATION") do |v|
12
- @downtime = v.to_i
12
+ options[:downtime] = v.to_i
13
13
  end
14
14
  optparse.on("--start TIME") do |v|
15
- @start = Time.parse(v)
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 = @dog.schedule_downtime(scope, :start => @start.to_i, :end => (@start+@downtime).to_i)
27
- logger.debug("dog.schedule_donwtime(%s, :start => %s, :end => %s) #==> [%s, %s]" % [scope.inspect, @start.to_i, (@start+@downtime).to_i, code.inspect, schedule.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
@@ -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? || args.empty?
40
- exit(1)
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
- result = evaluate(node, self)
51
- result, fields = get_hosts(result)
52
-
53
- if result.empty?
54
- STDERR.puts("no match found: #{search_args.join(" ")}")
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
- addresses = result.map {|host| [host.first, host.last] }
59
-
60
- # build ssh command
61
- cmdline = ["ssh"]
62
- options[:options].each do |option|
63
- cmdline << "-o" << option
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
- c = cmdline.dup
87
- if user
88
- c << (user + "@" + address)
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 "#{header}: #{line}"
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
- result = evaluate(node, self)
30
- if 0 < result.length
31
- _result, fields = get_hosts_with_search_tags(result, node)
32
- result = _result.take(options.fetch(:limit, _result.size))
33
- STDOUT.print(format(result, fields: fields))
34
- if _result.length == result.length
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
- logger.info("found %d host(s), limited to %d in result." % [_result.length, result.length])
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: #{args.join(" ")}")
40
+ STDERR.puts("no match found: #{expression}")
41
41
  exit(1)
42
42
  end
43
43
  end
@@ -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
- exit(1)
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
- result = evaluate(node, self)
57
-
58
- if result.length == 1
59
- host = result[0]
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
- result, fields = get_hosts_with_search_tags(result, node)
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
- # add "index" field
70
- result = result.each_with_index.map {|host,i| [i] + host }
71
- fields = ["index"] + fields
77
+ # add "index" field
78
+ result = result.each_with_index.map { |host, i| [i] + host }
79
+ fields = ["index"] + fields
72
80
 
73
- STDERR.print(format(result, fields: fields))
74
- logger.info("found %d host(s)." % result.length)
75
- exit(1)
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
- result, fields = get_hosts([host])
80
- address = result.flatten.first
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
- cmdline = ["ssh"]
84
- options[:options].each do |option|
85
- cmdline << "-o" << option
103
+ base_cmdline = ["ssh"]
104
+ if options[:forward_agent]
105
+ base_cmdline << "-A"
86
106
  end
87
- if path = options[:identity_file]
88
- cmdline << "-i" << Shellwords.escape(path)
107
+ if options[:identity_file]
108
+ base_cmdline << "-i" << options[:identity_file]
89
109
  end
90
- if port = options[:port]
91
- cmdline << "-p" << port.to_s
110
+ if options[:user]
111
+ base_cmdline << "-l" << options[:user]
92
112
  end
93
- if options[:forward_agent]
94
- cmdline << "-A"
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
- cmdline << "-v"
120
+ base_cmdline << "-v"
98
121
  end
99
- if user = options[:user]
100
- cmdline << (user + "@" + address)
101
- else
102
- cmdline << address
122
+ cmdline = base_cmdline + [host]
123
+ if @remote_command
124
+ cmdline << "--" << @remote_command
103
125
  end
104
- logger.debug("execute: #{Shellwords.join(cmdline)}")
105
- exec(*cmdline)
106
- exit(127)
126
+ Shellwords.join(cmdline)
107
127
  end
108
128
  end
109
129
  end
@@ -13,7 +13,7 @@ module Hotdog
13
13
  arg
14
14
  end
15
15
  }
16
- code, all_downtimes = @dog.get_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 = @dog.cancel_downtime(downtime["id"])
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
@@ -2,8 +2,12 @@
2
2
 
3
3
  require "fileutils"
4
4
  require "dogapi"
5
- require "json"
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 = Dogapi::Client.new(options[:api_key], options[:application_key])
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
- begin
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("SELECT id, name FROM hosts LIMIT 1")
187
- persistent_db.execute("SELECT id, name, value FROM tags LIMIT 1")
188
- persistent_db.execute("SELECT host_id, tag_id FROM hosts_tags LIMIT 1")
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
- create_table_hosts(memory_db)
202
- create_index_hosts(memory_db)
203
- create_table_tags(memory_db)
204
- create_index_tags(memory_db)
205
- create_table_hosts_tags(memory_db)
206
- create_index_hosts_tags(memory_db)
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
- begin
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
- begin
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
- prepare(memory_db, q).execute(hosts + split_tag(tag))
241
- rescue
242
- logger.error("failed: #{q} -- #{(hosts + split_tag(tag)).inspect}")
243
- raise
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 get_all_tags() #==> Hash<Tag,Array<Host>>
261
- code, all_tags = @dog.all_tags()
262
- logger.debug("dog.all_tags() #==> [%s, ...]" % [code.inspect])
263
- if code.to_i / 100 != 2
264
- raise("dog.all_tags() returns [%s, ...]" % [code.inspect])
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
- code, all_downtimes = @dog.get_all_downtimes()
267
- logger.debug("dog.get_all_downtimes() #==> [%s, ...]" % [code.inspect])
268
- if code.to_i / 100 != 2
269
- raise("dog.get_all_downtimes() returns [%s, ...]" % [code.inspect])
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 = all_downtimes.select { |downtime|
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["tags"].map { |tag, hosts| [tag, hosts.reject { |host| downtimes.include?(host) }] }]
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
- # create index later for better insert performance
300
- dst.transaction do
301
- create_table_hosts(dst)
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
@@ -1,3 +1,3 @@
1
1
  module Hotdog
2
- VERSION = "0.5.4"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -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 be(Hotdog::Commands::Hosts)
27
- expect(app.__send__(:get_command, "search")).to be(Hotdog::Commands::Search)
28
- expect(app.__send__(:get_command, "tags")).to be(Hotdog::Commands::Tags)
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.5.4
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-02 00:00:00.000000000 Z
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: parslet
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.6.2
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.6.2
82
+ version: 1.11.2
83
83
  - !ruby/object:Gem::Dependency
84
- name: sqlite3
84
+ name: oj
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.3.10
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: 1.3.10
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.4.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.4.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