hotdog 0.30.0 → 0.31.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/lib/hotdog/application.rb +37 -10
- data/lib/hotdog/commands/down.rb +3 -2
- data/lib/hotdog/commands/search.rb +8 -0
- data/lib/hotdog/commands/ssh.rb +2 -0
- data/lib/hotdog/commands.rb +56 -21
- data/lib/hotdog/expression/semantics.rb +14 -6
- data/lib/hotdog/expression/syntax.rb +7 -3
- data/lib/hotdog/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9919088eda80ed6ec42ab4448a1e9474a8f6b3cf
|
4
|
+
data.tar.gz: b4659b72b4ee22337f1d74d14dad1d0d686b8bf0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6cdebee0eaf5a3c347aa9fb8fae6f589467cf040edcad75d1d220d2b29a7842a7619f1b1149fe58bb1b116e6fc59ae248b48af5291655e03da4866ade02d1005
|
7
|
+
data.tar.gz: 9af471697553ce75493da82aedfa9f79c59f65de5a74407b7fbf626bc04571dcfb5e29be495021eecea48fd3814cecabf6abd87cb9f8abe3a36550a934f01868
|
data/lib/hotdog/application.rb
CHANGED
@@ -51,7 +51,8 @@ module Hotdog
|
|
51
51
|
force: false,
|
52
52
|
format: "text",
|
53
53
|
headers: false,
|
54
|
-
|
54
|
+
source: nil,
|
55
|
+
status: nil,
|
55
56
|
listing: false,
|
56
57
|
logger: @logger,
|
57
58
|
max_time: 5,
|
@@ -159,11 +160,21 @@ module Hotdog
|
|
159
160
|
end
|
160
161
|
end
|
161
162
|
|
163
|
+
def source()
|
164
|
+
options.fetch(:source, SOURCE_DATADOG)
|
165
|
+
end
|
166
|
+
|
167
|
+
def source_name(source=self.source)
|
168
|
+
{
|
169
|
+
SOURCE_DATADOG => "datadog",
|
170
|
+
}.fetch(source, "unknown")
|
171
|
+
end
|
172
|
+
|
162
173
|
def status()
|
163
174
|
options.fetch(:status, STATUS_RUNNING)
|
164
175
|
end
|
165
176
|
|
166
|
-
def status_name()
|
177
|
+
def status_name(status=self.status)
|
167
178
|
{
|
168
179
|
STATUS_PENDING => "pending",
|
169
180
|
STATUS_RUNNING => "running",
|
@@ -171,7 +182,7 @@ module Hotdog
|
|
171
182
|
STATUS_TERMINATED => "terminated",
|
172
183
|
STATUS_STOPPING => "stopping",
|
173
184
|
STATUS_STOPPED => "stopped",
|
174
|
-
}.fetch(
|
185
|
+
}.fetch(status, "unknown")
|
175
186
|
end
|
176
187
|
|
177
188
|
private
|
@@ -215,22 +226,38 @@ module Hotdog
|
|
215
226
|
@optparse.on("-h", "--[no-]headers", "Display headeres for each columns") do |v|
|
216
227
|
options[:headers] = v
|
217
228
|
end
|
229
|
+
@optparse.on("--source=SOURCE", "Specify custom host source") do |v|
|
230
|
+
case v
|
231
|
+
when /\A\d\z/i
|
232
|
+
options[:source] = v.to_i
|
233
|
+
when /\A(?:all|any)\z/i
|
234
|
+
options[:source] = nil
|
235
|
+
when /\A(?:datadog)\z/i
|
236
|
+
options[:source] = SOURCE_DATADOG
|
237
|
+
else
|
238
|
+
raise(OptionParser::InvalidArgument.new("unknown source: #{v}"))
|
239
|
+
end
|
240
|
+
end
|
218
241
|
@optparse.on("--status=STATUS", "Specify custom host status") do |v|
|
219
242
|
case v
|
220
|
-
when /\
|
243
|
+
when /\A\d\z/i
|
244
|
+
options[:status] = v.to_i
|
245
|
+
when /\A(?:all|any)\z/i
|
246
|
+
options[:status] = nil
|
247
|
+
when /\A(?:pending)\z/i
|
221
248
|
options[:status] = STATUS_PENDING
|
222
|
-
when /\
|
249
|
+
when /\A(?:running)\z/i
|
223
250
|
options[:status] = STATUS_RUNNING
|
224
|
-
when /\
|
251
|
+
when /\A(?:shutting-down)\z/i
|
225
252
|
options[:status] = STATUS_SHUTTING_DOWN
|
226
|
-
when /\
|
253
|
+
when /\A(?:terminated)\z/i
|
227
254
|
options[:status] = STATUS_TERMINATED
|
228
|
-
when /\
|
255
|
+
when /\A(?:stopping)\z/i
|
229
256
|
options[:status] = STATUS_STOPPING
|
230
|
-
when /\
|
257
|
+
when /\A(?:stopped)\z/i
|
231
258
|
options[:status] = STATUS_STOPPED
|
232
259
|
else
|
233
|
-
|
260
|
+
raise(OptionParser::InvalidArgument.new("unknown status: #{v}"))
|
234
261
|
end
|
235
262
|
end
|
236
263
|
@optparse.on("-l", "--[no-]listing", "Use listing format") do |v|
|
data/lib/hotdog/commands/down.rb
CHANGED
@@ -60,9 +60,10 @@ module Hotdog
|
|
60
60
|
@db.transaction do
|
61
61
|
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
62
62
|
hosts.each_slice(sqlite_limit_compound_select - 1) do |hosts|
|
63
|
-
|
64
|
-
execute_db(@db,
|
63
|
+
execute_db(@db, "DELETE FROM hosts_tags WHERE tag_id IN ( SELECT id FROM tags WHERE name = '@status' ) AND host_id IN ( SELECT id FROM hosts WHERE name IN (%s) );" % hosts.map { "?" }.join(", "), hosts)
|
64
|
+
execute_db(@db, "UPDATE hosts SET status = ? WHERE name IN (%s);" % hosts.map { "?" }.join(", "), [STATUS_STOPPING] + hosts)
|
65
65
|
end
|
66
|
+
associate_tag_hosts(@db, "@status:#{application.status_name(STATUS_STOPPING)}", hosts)
|
66
67
|
end
|
67
68
|
end
|
68
69
|
end
|
@@ -120,6 +120,14 @@ module Hotdog
|
|
120
120
|
# return everything if given expression is empty
|
121
121
|
expression = "*"
|
122
122
|
end
|
123
|
+
if options[:source]
|
124
|
+
source_name = application.source_name(options[:source])
|
125
|
+
expression = "@source:#{source_name} AND (#{expression})"
|
126
|
+
end
|
127
|
+
if options[:status]
|
128
|
+
status_name = application.status_name(options[:status])
|
129
|
+
expression = "@status:#{status_name} AND (#{expression})"
|
130
|
+
end
|
123
131
|
if options[:limit]
|
124
132
|
expression = "LIMIT((#{expression}), #{options[:limit]})"
|
125
133
|
end
|
data/lib/hotdog/commands/ssh.rb
CHANGED
@@ -15,6 +15,8 @@ module Hotdog
|
|
15
15
|
default_option(options, :max_parallelism, Parallel.processor_count * 2)
|
16
16
|
default_option(options, :shuffle, false)
|
17
17
|
default_option(options, :ssh_config, nil)
|
18
|
+
# we must not need to run ssh against terminated hosts
|
19
|
+
default_option(options, :status, STATUS_RUNNING)
|
18
20
|
optparse.on("-C", "Enable compression.") do |v|
|
19
21
|
options[:ssh_options]["Compression"] = "yes"
|
20
22
|
end
|
data/lib/hotdog/commands.rb
CHANGED
@@ -61,11 +61,7 @@ module Hotdog
|
|
61
61
|
|
62
62
|
private
|
63
63
|
def default_option(options, key, default_value)
|
64
|
-
|
65
|
-
options[key]
|
66
|
-
else
|
67
|
-
options[key] = default_value
|
68
|
-
end
|
64
|
+
options[key] = default_value
|
69
65
|
end
|
70
66
|
|
71
67
|
def prepare(db, query)
|
@@ -81,15 +77,6 @@ module Hotdog
|
|
81
77
|
end
|
82
78
|
|
83
79
|
def get_hosts(host_ids, tags=nil)
|
84
|
-
status = application.status
|
85
|
-
n = Array(host_ids).length
|
86
|
-
host_ids = Array(host_ids).each_slice(SQLITE_LIMIT_COMPOUND_SELECT).flat_map { |host_ids|
|
87
|
-
execute("SELECT id FROM hosts WHERE status = ? AND id IN (%s);" % host_ids.map { "?" }.join(", "), [status] + host_ids).map { |row| row[0] }
|
88
|
-
}
|
89
|
-
m = host_ids.length
|
90
|
-
if n != m
|
91
|
-
logger.warn("filtered out #{n - m} host(s) out of #{n} due to status != #{application.status_name}.")
|
92
|
-
end
|
93
80
|
tags ||= @options[:tags]
|
94
81
|
update_db
|
95
82
|
if host_ids.empty?
|
@@ -263,6 +250,7 @@ module Hotdog
|
|
263
250
|
db = SQLite3::Database.new(persistent_db_path)
|
264
251
|
copy_db(memory_db, db)
|
265
252
|
close_db(memory_db)
|
253
|
+
$did_reload = true
|
266
254
|
@db = db
|
267
255
|
end
|
268
256
|
end
|
@@ -295,6 +283,25 @@ module Hotdog
|
|
295
283
|
execute_db(db, "CREATE TABLE IF NOT EXISTS hosts_tags (host_id INTEGER NOT NULL, tag_id INTEGER NOT NULL);")
|
296
284
|
execute_db(db, "CREATE UNIQUE INDEX IF NOT EXISTS hosts_tags_host_id_tag_id ON hosts_tags (host_id, tag_id);")
|
297
285
|
|
286
|
+
execute_db(db, "CREATE TABLE IF NOT EXISTS source_names (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(200) NOT NULL COLLATE NOCASE);")
|
287
|
+
{
|
288
|
+
SOURCE_DATADOG => application.source_name(SOURCE_DATADOG),
|
289
|
+
}.each do |source_id, source_name|
|
290
|
+
execute_db(db, "INSERT OR IGNORE INTO source_names (id, name) VALUES (?, ?);", [source_id, source_name])
|
291
|
+
end
|
292
|
+
|
293
|
+
execute_db(db, "CREATE TABLE IF NOT EXISTS status_names (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(200) NOT NULL COLLATE NOCASE);")
|
294
|
+
{
|
295
|
+
STATUS_PENDING => application.status_name(STATUS_PENDING),
|
296
|
+
STATUS_RUNNING => application.status_name(STATUS_RUNNING),
|
297
|
+
STATUS_SHUTTING_DOWN => application.status_name(STATUS_SHUTTING_DOWN),
|
298
|
+
STATUS_TERMINATED => application.status_name(STATUS_TERMINATED),
|
299
|
+
STATUS_STOPPING => application.status_name(STATUS_STOPPING),
|
300
|
+
STATUS_STOPPED => application.status_name(STATUS_STOPPED),
|
301
|
+
}.each do |status_id, status_name|
|
302
|
+
execute_db(db, "INSERT OR IGNORE INTO status_names (id, name) VALUES (?, ?);", [status_id, status_name])
|
303
|
+
end
|
304
|
+
|
298
305
|
known_tags = all_tags.keys.map { |tag| split_tag(tag) }.uniq
|
299
306
|
create_tags(db, known_tags)
|
300
307
|
|
@@ -362,20 +369,48 @@ module Hotdog
|
|
362
369
|
end
|
363
370
|
|
364
371
|
def create_hosts(db, hosts, downtimes)
|
365
|
-
hosts.each_slice(SQLITE_LIMIT_COMPOUND_SELECT /
|
366
|
-
q = "INSERT OR IGNORE INTO hosts (name, status) VALUES %s;" % hosts.map { "(?, ?)" }.join(", ")
|
372
|
+
hosts.each_slice(SQLITE_LIMIT_COMPOUND_SELECT / 3) do |hosts|
|
373
|
+
q = "INSERT OR IGNORE INTO hosts (name, source, status) VALUES %s;" % hosts.map { "(?, ?, ?)" }.join(", ")
|
367
374
|
execute_db(db, q, hosts.map { |host|
|
375
|
+
source = SOURCE_DATADOG
|
368
376
|
status = downtimes.include?(host) ? STATUS_STOPPED : STATUS_RUNNING
|
369
|
-
[host, status]
|
377
|
+
[host, source, status]
|
370
378
|
})
|
371
379
|
end
|
380
|
+
|
372
381
|
# create virtual `host` tag
|
373
382
|
execute_db(db, "INSERT OR IGNORE INTO tags (name, value) SELECT 'host', hosts.name FROM hosts;")
|
374
|
-
|
383
|
+
execute_db(db,
|
384
|
+
"INSERT OR REPLACE INTO hosts_tags (host_id, tag_id) " \
|
385
|
+
"SELECT hosts.id, tags.id FROM hosts " \
|
386
|
+
"INNER JOIN tags ON tags.name = 'host' AND hosts.name = tags.value;"
|
387
|
+
)
|
388
|
+
|
389
|
+
# create virtual `@host` tag
|
390
|
+
execute_db(db, "INSERT OR IGNORE INTO tags (name, value) SELECT '@host', hosts.name FROM hosts;")
|
391
|
+
execute_db(db,
|
392
|
+
"INSERT OR REPLACE INTO hosts_tags (host_id, tag_id) " \
|
393
|
+
"SELECT hosts.id, tags.id FROM hosts " \
|
394
|
+
"INNER JOIN tags ON tags.name = '@host' AND hosts.name = tags.value;"
|
395
|
+
)
|
396
|
+
|
397
|
+
# create virtual `@source` tag
|
398
|
+
execute_db(db, "INSERT OR IGNORE INTO tags (name, value) SELECT '@source', name FROM source_names;")
|
399
|
+
execute_db(db,
|
400
|
+
"INSERT OR REPLACE INTO hosts_tags (host_id, tag_id) " \
|
401
|
+
"SELECT hosts.id, tags.id FROM hosts " \
|
402
|
+
"INNER JOIN source_names ON hosts.source = source_names.id " \
|
403
|
+
"INNER JOIN tags ON tags.name = '@source' AND source_names.name = tags.value;"
|
404
|
+
)
|
405
|
+
|
406
|
+
# create virtual `@status` tag
|
407
|
+
execute_db(db, "INSERT OR IGNORE INTO tags (name, value) SELECT '@status', name FROM status_names;")
|
408
|
+
execute_db(db,
|
409
|
+
"INSERT OR REPLACE INTO hosts_tags (host_id, tag_id) " \
|
375
410
|
"SELECT hosts.id, tags.id FROM hosts " \
|
376
|
-
"INNER JOIN
|
377
|
-
|
378
|
-
|
411
|
+
"INNER JOIN status_names ON hosts.status = status_names.id " \
|
412
|
+
"INNER JOIN tags ON tags.name = '@status' AND status_names.name = tags.value;"
|
413
|
+
)
|
379
414
|
end
|
380
415
|
|
381
416
|
def create_tags(db, tags)
|
@@ -59,9 +59,13 @@ module Hotdog
|
|
59
59
|
(min / (sqlite_limit_compound_select - 2)).upto(max / (sqlite_limit_compound_select - 2)).flat_map { |i|
|
60
60
|
range = ((sqlite_limit_compound_select - 2) * i)...((sqlite_limit_compound_select - 2) * (i + 1))
|
61
61
|
selected = values.select { |n| range === n }
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
if 0 < selected.length
|
63
|
+
q = "SELECT id FROM hosts " \
|
64
|
+
"WHERE ? <= id AND id < ? AND id NOT IN (%s);"
|
65
|
+
environment.execute(q % selected.map { "?" }.join(", "), [range.first, range.last] + selected).map { |row| row.first }
|
66
|
+
else
|
67
|
+
[]
|
68
|
+
end
|
65
69
|
}.tap do |values|
|
66
70
|
environment.logger.debug("NOT expr: #{values.length} value(s)")
|
67
71
|
end
|
@@ -201,9 +205,13 @@ module Hotdog
|
|
201
205
|
range = (((sqlite_limit_compound_select - 2) / 2) * i)...(((sqlite_limit_compound_select - 2) / 2) * (i + 1))
|
202
206
|
left_selected = left_values.select { |n| range === n }
|
203
207
|
right_selected = right_values.select { |n| range === n }
|
204
|
-
|
205
|
-
|
206
|
-
|
208
|
+
if 0 < left_selected.length and 0 < right_selected.length
|
209
|
+
q = "SELECT id FROM hosts " \
|
210
|
+
"WHERE ? <= id AND id < ? AND ( id IN (%s) AND id IN (%s) );"
|
211
|
+
environment.execute(q % [left_selected.map { "?" }.join(", "), right_selected.map { "?" }.join(", ")], [range.first, range.last] + left_selected + right_selected).map { |row| row.first }
|
212
|
+
else
|
213
|
+
[]
|
214
|
+
end
|
207
215
|
}.tap do |values|
|
208
216
|
environment.logger.debug("lhs(#{left_values.length}) AND rhs(#{right_values.length}) => #{values.length}")
|
209
217
|
end
|
@@ -106,9 +106,9 @@ module Hotdog
|
|
106
106
|
)
|
107
107
|
}
|
108
108
|
rule(:tag) {
|
109
|
-
(
|
110
|
-
|
|
111
|
-
|
|
109
|
+
( tagname_regexp.as(:tagname_regexp) >> separator.as(:separator) >> tagvalue_regexp.as(:tagvalue_regexp) \
|
110
|
+
| tagname_regexp.as(:tagname_regexp) >> separator.as(:separator) \
|
111
|
+
| tagname_regexp.as(:tagname_regexp) \
|
112
112
|
| tagname_glob.as(:tagname_glob) >> separator.as(:separator) >> tagvalue_glob.as(:tagvalue_glob) \
|
113
113
|
| tagname_glob.as(:tagname_glob) >> separator.as(:separator) >> tagvalue.as(:tagvalue) \
|
114
114
|
| tagname_glob.as(:tagname_glob) >> separator.as(:separator) \
|
@@ -117,6 +117,10 @@ module Hotdog
|
|
117
117
|
| tagname.as(:tagname) >> separator.as(:separator) >> tagvalue.as(:tagvalue) \
|
118
118
|
| tagname.as(:tagname) >> separator.as(:separator) \
|
119
119
|
| tagname.as(:tagname) \
|
120
|
+
| (str('@') >> tagname).as(:tagname) >> separator.as(:separator) >> tagvalue_glob.as(:tagvalue_glob) \
|
121
|
+
| (str('@') >> tagname).as(:tagname) >> separator.as(:separator) >> tagvalue.as(:tagvalue) \
|
122
|
+
| (str('@') >> tagname).as(:tagname) >> separator.as(:separator) \
|
123
|
+
| (str('@') >> tagname).as(:tagname) \
|
120
124
|
| separator.as(:separator) >> regexp.as(:tagvalue_regexp) \
|
121
125
|
| separator.as(:separator) >> tagvalue_glob.as(:tagvalue_glob) \
|
122
126
|
| separator.as(:separator) >> tagvalue.as(:tagvalue) \
|
data/lib/hotdog/version.rb
CHANGED
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.31.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: 2017-11-
|
11
|
+
date: 2017-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|