hotdog 0.1.18 → 0.2.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/.travis.yml +6 -0
- data/README.md +2 -0
- data/hotdog.gemspec +1 -0
- data/lib/hotdog/commands/down.rb +3 -3
- data/lib/hotdog/commands/hosts.rb +3 -11
- data/lib/hotdog/commands/search.rb +146 -92
- data/lib/hotdog/commands/tags.rb +23 -17
- data/lib/hotdog/commands/up.rb +3 -3
- data/lib/hotdog/commands.rb +145 -195
- data/lib/hotdog/formatters/ltsv.rb +9 -4
- data/lib/hotdog/formatters/plain.rb +1 -1
- data/lib/hotdog/version.rb +1 -1
- data/spec/core/application_spec.rb +36 -0
- data/spec/formatter/csv_spec.rb +33 -0
- data/spec/formatter/json_spec.rb +66 -0
- data/spec/formatter/ltsv_spec.rb +32 -0
- data/spec/formatter/plain_spec.rb +76 -0
- data/spec/formatter/text_spec.rb +76 -0
- data/spec/formatter/tsv_spec.rb +33 -0
- data/spec/formatter/yaml_spec.rb +49 -0
- data/spec/parser/parser_spec.rb +300 -0
- data/spec/parser/tag_expression_spec.rb +63 -0
- data/spec/parser/tag_glob_expression_spec.rb +63 -0
- data/spec/parser/tag_regexp_expression_spec.rb +63 -0
- data/spec/spec_helper.rb +1 -0
- metadata +44 -3
data/lib/hotdog/commands.rb
CHANGED
@@ -27,7 +27,7 @@ module Hotdog
|
|
27
27
|
raise(NotImplementedError)
|
28
28
|
end
|
29
29
|
|
30
|
-
def execute(query,
|
30
|
+
def execute(query, args=[])
|
31
31
|
update_db
|
32
32
|
q = query.strip
|
33
33
|
if 0 < args.length
|
@@ -67,73 +67,94 @@ module Hotdog
|
|
67
67
|
s.index('*') or s.index('?') or s.index('[') or s.index(']')
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
71
|
-
host_id = execute("SELECT id FROM hosts WHERE name = %s LIMIT 1", s)
|
72
|
-
not host_id.nil?
|
73
|
-
end
|
74
|
-
|
75
|
-
def get_hosts(hosts, tags=nil)
|
70
|
+
def get_hosts(host_ids, tags=nil)
|
76
71
|
tags ||= @options[:tags]
|
77
72
|
update_db
|
78
|
-
if
|
79
|
-
|
80
|
-
tags.map { |tag|
|
81
|
-
tag_name, tag_value = tag.split(":", 2)
|
82
|
-
case tag_name
|
83
|
-
when "host"
|
84
|
-
select_name_from_hosts_by_id(@db, host_id)
|
85
|
-
else
|
86
|
-
if glob?(tag_name)
|
87
|
-
select_tag_values_from_hosts_tags_by_host_id_and_tag_name_glob(@db, host_id, tag_name)
|
88
|
-
else
|
89
|
-
select_tag_values_from_hosts_tags_by_host_id_and_tag_name(@db, host_id, tag_name)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
}
|
93
|
-
}
|
94
|
-
fields = tags
|
73
|
+
if host_ids.empty?
|
74
|
+
[[], []]
|
95
75
|
else
|
96
|
-
if
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
[
|
106
|
-
|
107
|
-
|
76
|
+
if 0 < tags.length
|
77
|
+
fields = tags.map { |tag|
|
78
|
+
tag_name, tag_value = split_tag(tag)
|
79
|
+
tag_name
|
80
|
+
}
|
81
|
+
fields_without_host = fields.reject { |tag_name| tag_name == "host" }
|
82
|
+
if fields == fields_without_host
|
83
|
+
host_names = {}
|
84
|
+
else
|
85
|
+
host_names = Hash[execute("SELECT id, name FROM hosts WHERE id IN (%s)" % host_ids.map { "?" }.join(", "), host_ids).map { |row| row.to_a }]
|
86
|
+
end
|
87
|
+
q1 = []
|
88
|
+
q1 << "SELECT tags.name, GROUP_CONCAT(tags.value, ',') FROM hosts_tags"
|
89
|
+
q1 << "INNER JOIN hosts ON hosts_tags.host_id = hosts.id"
|
90
|
+
q1 << "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
|
91
|
+
q1 << "WHERE hosts_tags.host_id = ? AND tags.name IN (%s)"
|
92
|
+
q1 << "GROUP BY tags.name;"
|
93
|
+
result = host_ids.map { |host_id|
|
94
|
+
tag_values = Hash[execute(q1.join(" ") % fields_without_host.map { "?" }.join(", "), [host_id] + fields_without_host).map { |row| row.to_a }]
|
95
|
+
fields.map { |tag_name|
|
96
|
+
if tag_name == "host"
|
97
|
+
host_names.fetch(host_id, "")
|
108
98
|
else
|
109
|
-
|
99
|
+
tag_values.fetch(tag_name, "")
|
110
100
|
end
|
111
101
|
}
|
112
102
|
}
|
113
|
-
|
103
|
+
[result, fields]
|
114
104
|
else
|
115
|
-
if @options[:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
105
|
+
if @options[:listing]
|
106
|
+
q1 = []
|
107
|
+
q1 << "SELECT DISTINCT tags.name FROM hosts_tags"
|
108
|
+
q1 << "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
|
109
|
+
q1 << "WHERE hosts_tags.host_id IN (%s);"
|
110
|
+
if @options[:primary_tag]
|
111
|
+
fields = [
|
112
|
+
@options[:primary_tag],
|
113
|
+
"host",
|
114
|
+
] + execute(q1.join(" ") % host_ids.map { "?" }.join(", "), host_ids).map { |row| row.first }.reject { |tag_name|
|
115
|
+
tag_name == @options[:primary_tag]
|
116
|
+
}
|
121
117
|
else
|
122
|
-
|
123
|
-
|
124
|
-
|
118
|
+
fields = [
|
119
|
+
"host",
|
120
|
+
] + execute(q1.join(" ") % host_ids.map { "?" }.join(", "), host_ids).map { |row| row.first }
|
121
|
+
end
|
122
|
+
host_names = Hash[execute("SELECT id, name FROM hosts WHERE id IN (%s)" % host_ids.map { "?" }.join(", "), host_ids).map { |row| row.to_a }]
|
123
|
+
q2 = []
|
124
|
+
q2 << "SELECT tags.name, GROUP_CONCAT(tags.value, ',') FROM hosts_tags"
|
125
|
+
q2 << "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
|
126
|
+
q2 << "WHERE hosts_tags.host_id = ? AND tags.name IN (%s)"
|
127
|
+
q2 << "GROUP BY tags.name;"
|
128
|
+
fields_without_host = fields.reject { |tag_name| tag_name == "host" }
|
129
|
+
result = host_ids.map { |host_id|
|
130
|
+
tag_values = Hash[execute(q2.join(" ") % fields_without_host.map { "?" }.join(", "), [host_id] + fields_without_host).map { |row| row.to_a }]
|
131
|
+
fields.map { |tag_name|
|
132
|
+
if tag_name == "host"
|
133
|
+
host_names.fetch(host_id, "")
|
125
134
|
else
|
126
|
-
|
135
|
+
tag_values.fetch(tag_name, "")
|
127
136
|
end
|
128
137
|
}
|
129
|
-
|
138
|
+
}
|
139
|
+
[result, fields]
|
130
140
|
else
|
131
|
-
|
132
|
-
|
141
|
+
if @options[:primary_tag]
|
142
|
+
fields = [@options[:primary_tag]]
|
143
|
+
q1 = []
|
144
|
+
q1 << "SELECT tags.value FROM hosts_tags"
|
145
|
+
q1 << "INNER JOIN hosts ON hosts_tags.host_id = hosts.id"
|
146
|
+
q1 << "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
|
147
|
+
q1 << "WHERE hosts_tags.host_id IN (%s) AND tags.name = ?;"
|
148
|
+
result = execute(q1.join(" ") % host_ids.map { "?" }.join(", "), host_ids + [@options[:primary_tag]]).map { |row| row.to_a }
|
149
|
+
[result, fields]
|
150
|
+
else
|
151
|
+
fields = ["host"]
|
152
|
+
result = execute("SELECT name FROM hosts WHERE id IN (%s)" % host_ids.map { "?" }.join(", "), host_ids).map { |row| row.to_a }
|
153
|
+
[result, fields]
|
154
|
+
end
|
133
155
|
end
|
134
156
|
end
|
135
157
|
end
|
136
|
-
[result, fields]
|
137
158
|
end
|
138
159
|
|
139
160
|
def close_db(db, options={})
|
@@ -172,44 +193,26 @@ module Hotdog
|
|
172
193
|
create_table_hosts_tags(memory_db)
|
173
194
|
create_index_hosts_tags(memory_db)
|
174
195
|
|
175
|
-
|
176
|
-
logger.debug("dog.all_tags() #==> [%s, ...]" % [code.inspect])
|
177
|
-
if code.to_i / 100 != 2
|
178
|
-
raise("dog.all_tags() returns [%s, ...]" % [code.inspect])
|
179
|
-
end
|
196
|
+
all_tags = get_all_tags()
|
180
197
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
raise("dog.get_all_downtimes() returns [%s, ...]" % [code.inspect])
|
198
|
+
known_tags = all_tags.keys.map { |tag| split_tag(tag) }.uniq
|
199
|
+
unless known_tags.empty?
|
200
|
+
prepare(memory_db, "INSERT OR IGNORE INTO tags (name, value) VALUES %s" % known_tags.map { "(?, ?)" }.join(", ")).execute(known_tags)
|
185
201
|
end
|
186
202
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
downtime["active"] and ( downtime["start"].nil? or downtime["start"] < now ) and ( downtime["end"].nil? or now <= downtime["end"] )
|
191
|
-
}.map { |downtime|
|
192
|
-
# find host scopes
|
193
|
-
downtime["scope"].select { |scope| scope.start_with?("host:") }.map { |scope| scope.sub(/\Ahost:/, "") }
|
194
|
-
}.reduce(:+)
|
195
|
-
downs ||= []
|
196
|
-
|
197
|
-
# for case-insensitive match of hostname
|
198
|
-
downs = downs.map { |down| down.downcase }
|
199
|
-
|
200
|
-
if not downs.empty?
|
201
|
-
logger.info("ignore host(s) with scheduled downtimes: #{downs.inspect}")
|
203
|
+
known_hosts = all_tags.values.reduce(:+).uniq
|
204
|
+
unless known_hosts.empty?
|
205
|
+
prepare(memory_db, "INSERT OR IGNORE INTO hosts (name) VALUES %s" % known_hosts.map { "(?)" }.join(", ")).execute(known_hosts)
|
202
206
|
end
|
203
207
|
|
204
|
-
all_tags
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
hosts
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
end
|
208
|
+
all_tags.each do |tag, hosts|
|
209
|
+
q = []
|
210
|
+
q << "INSERT OR REPLACE INTO hosts_tags (host_id, tag_id)"
|
211
|
+
q << "SELECT host.id, tag.id FROM"
|
212
|
+
q << "( SELECT id FROM hosts WHERE name IN (%s) ) AS host,"
|
213
|
+
q << "( SELECT id FROM tags WHERE name = ? AND value = ? LIMIT 1 ) AS tag;"
|
214
|
+
unless hosts.empty?
|
215
|
+
prepare(memory_db, q.join(" ") % hosts.map { "?" }.join(", ")).execute(hosts + split_tag(tag))
|
213
216
|
end
|
214
217
|
end
|
215
218
|
|
@@ -224,6 +227,36 @@ module Hotdog
|
|
224
227
|
end
|
225
228
|
end
|
226
229
|
|
230
|
+
def get_all_tags() #==> Hash<Tag,Array<Host>>
|
231
|
+
code, all_tags = @dog.all_tags()
|
232
|
+
logger.debug("dog.all_tags() #==> [%s, ...]" % [code.inspect])
|
233
|
+
if code.to_i / 100 != 2
|
234
|
+
raise("dog.all_tags() returns [%s, ...]" % [code.inspect])
|
235
|
+
end
|
236
|
+
code, all_downtimes = @dog.get_all_downtimes()
|
237
|
+
logger.debug("dog.get_all_downtimes() #==> [%s, ...]" % [code.inspect])
|
238
|
+
if code.to_i / 100 != 2
|
239
|
+
raise("dog.get_all_downtimes() returns [%s, ...]" % [code.inspect])
|
240
|
+
end
|
241
|
+
now = Time.new.to_i
|
242
|
+
downtimes = all_downtimes.select { |downtime|
|
243
|
+
# active downtimes
|
244
|
+
downtime["active"] and ( downtime["start"].nil? or downtime["start"] < now ) and ( downtime["end"].nil? or now <= downtime["end"] )
|
245
|
+
}.map { |downtime|
|
246
|
+
# find host scopes
|
247
|
+
downtime["scope"].select { |scope| scope.start_with?("host:") }.map { |scope| scope.sub(/\Ahost:/, "") }
|
248
|
+
}.reduce(:+) || []
|
249
|
+
if not downtimes.empty?
|
250
|
+
logger.info("ignore host(s) with scheduled downtimes: #{downtimes.inspect}")
|
251
|
+
end
|
252
|
+
Hash[all_tags["tags"].map { |tag, hosts| [tag, hosts.reject { |host| downtimes.include?(host) }] }]
|
253
|
+
end
|
254
|
+
|
255
|
+
def split_tag(tag)
|
256
|
+
tag_name, tag_value = tag.split(":", 2)
|
257
|
+
[tag_name, tag_value || ""]
|
258
|
+
end
|
259
|
+
|
227
260
|
def copy_db(src, dst)
|
228
261
|
# create index later for better insert performance
|
229
262
|
dst.transaction do
|
@@ -231,15 +264,14 @@ module Hotdog
|
|
231
264
|
create_table_tags(dst)
|
232
265
|
create_table_hosts_tags(dst)
|
233
266
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
end
|
267
|
+
hosts = prepare(src, "SELECT id, name FROM hosts").execute().to_a
|
268
|
+
prepare(dst, "INSERT INTO hosts (id, name) VALUES %s" % hosts.map { "(?, ?)" }.join(", ")).execute(hosts) unless hosts.empty?
|
269
|
+
|
270
|
+
tags = prepare(src, "SELECT id, name, value FROM tags").execute().to_a
|
271
|
+
prepare(dst, "INSERT INTO tags (id, name, value) VALUES %s" % tags.map { "(?, ?, ?)" }.join(", ")).execute(tags) unless tags.empty?
|
272
|
+
|
273
|
+
hosts_tags = prepare(src, "SELECT host_id, tag_id FROM hosts_tags").to_a
|
274
|
+
prepare(dst, "INSERT INTO hosts_tags (host_id, tag_id) VALUES %s" % hosts_tags.map { "(?, ?)" }.join(", ")).execute(hosts_tags) unless hosts_tags.empty?
|
243
275
|
|
244
276
|
create_index_hosts(dst)
|
245
277
|
create_index_tags(dst)
|
@@ -247,29 +279,14 @@ module Hotdog
|
|
247
279
|
end
|
248
280
|
end
|
249
281
|
|
250
|
-
def select_from_hosts(db)
|
251
|
-
logger.debug("select_from_hosts()")
|
252
|
-
prepare(db, "SELECT id, name FROM hosts").execute()
|
253
|
-
end
|
254
|
-
|
255
|
-
def select_from_tags(db)
|
256
|
-
logger.debug("select_from_tags()")
|
257
|
-
prepare(db, "SELECT id, name, value FROM tags").execute()
|
258
|
-
end
|
259
|
-
|
260
|
-
def select_from_hosts_tags(db)
|
261
|
-
logger.debug("select_from_hosts_tags()")
|
262
|
-
prepare(db, "SELECT host_id, tag_id FROM hosts_tags").execute()
|
263
|
-
end
|
264
|
-
|
265
282
|
def create_table_hosts(db)
|
266
283
|
logger.debug("create_table_hosts()")
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
284
|
+
q = []
|
285
|
+
q << "CREATE TABLE IF NOT EXISTS hosts ("
|
286
|
+
q << "id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
287
|
+
q << "name VARCHAR(255) NOT NULL COLLATE NOCASE"
|
288
|
+
q << ");"
|
289
|
+
db.execute(q.join(" "))
|
273
290
|
end
|
274
291
|
|
275
292
|
def create_index_hosts(db)
|
@@ -279,13 +296,13 @@ module Hotdog
|
|
279
296
|
|
280
297
|
def create_table_tags(db)
|
281
298
|
logger.debug("create_table_tags()")
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
299
|
+
q = []
|
300
|
+
q << "CREATE TABLE IF NOT EXISTS tags ("
|
301
|
+
q << "id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
302
|
+
q << "name VARCHAR(200) NOT NULL COLLATE NOCASE,"
|
303
|
+
q << "value VARCHAR(200) NOT NULL COLLATE NOCASE"
|
304
|
+
q << ");"
|
305
|
+
db.execute(q.join(" "))
|
289
306
|
end
|
290
307
|
|
291
308
|
def create_index_tags(db)
|
@@ -295,85 +312,18 @@ module Hotdog
|
|
295
312
|
|
296
313
|
def create_table_hosts_tags(db)
|
297
314
|
logger.debug("create_table_hosts_tags()")
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
315
|
+
q = []
|
316
|
+
q << "CREATE TABLE IF NOT EXISTS hosts_tags ("
|
317
|
+
q << "host_id INTEGER NOT NULL,"
|
318
|
+
q << "tag_id INTEGER NOT NULL"
|
319
|
+
q << ");"
|
320
|
+
db.execute(q.join(" "))
|
304
321
|
end
|
305
322
|
|
306
323
|
def create_index_hosts_tags(db)
|
307
324
|
logger.debug("create_index_hosts_tags()")
|
308
325
|
db.execute("CREATE UNIQUE INDEX IF NOT EXISTS hosts_tags_host_id_tag_id ON hosts_tags ( host_id, tag_id )")
|
309
326
|
end
|
310
|
-
|
311
|
-
def insert_into_tags(db, tag_id, tag_name, tag_value)
|
312
|
-
logger.debug("insert_into_tags(%s, %s, %s)" % [tag_id.inspect, tag_name.inspect, tag_value.inspect])
|
313
|
-
prepare(db, "INSERT INTO tags (id, name, value) VALUES (?, ?, ?)").execute(tag_id, tag_name, tag_value)
|
314
|
-
end
|
315
|
-
|
316
|
-
def insert_or_ignore_into_tags(db, tag_name, tag_value)
|
317
|
-
logger.debug("insert_or_ignore_into_tags(%s, %s)" % [tag_name.inspect, tag_value.inspect])
|
318
|
-
prepare(db, "INSERT OR IGNORE INTO tags (name, value) VALUES (?, ?)").execute(tag_name, tag_value)
|
319
|
-
end
|
320
|
-
|
321
|
-
def insert_into_hosts(db, host_id, host_name)
|
322
|
-
logger.debug("insert_into_hosts(%s, %s)" % [host_id.inspect, host_name.inspect])
|
323
|
-
prepare(db, "INSERT INTO hosts (id, name) VALUES (?, ?)").execute(host_id, host_name)
|
324
|
-
end
|
325
|
-
|
326
|
-
def insert_or_ignore_into_hosts(db, host_name)
|
327
|
-
logger.debug("insert_or_ignore_into_hosts(%s)" % [host_name.inspect])
|
328
|
-
prepare(db, "INSERT OR IGNORE INTO hosts (name) VALUES (?)").execute(host_name)
|
329
|
-
end
|
330
|
-
|
331
|
-
def insert_into_hosts_tags(db, host_id, tag_id)
|
332
|
-
logger.debug("insert_into_hosts_tags(%s, %s)" % [host_id.inspect, tag_id.inspect])
|
333
|
-
prepare(db, "INSERT INTO hosts_tags (host_id, tag_id) VALUES (?, ?)").execute(host_id, tag_id)
|
334
|
-
end
|
335
|
-
|
336
|
-
def insert_or_replace_into_hosts_tags(db, host_name, tag_name, tag_value)
|
337
|
-
logger.debug("insert_or_replace_into_hosts_tags(%s, %s, %s)" % [host_name.inspect, tag_name.inspect, tag_value.inspect])
|
338
|
-
prepare(db, <<-EOS).execute(host_name, tag_name, tag_value)
|
339
|
-
INSERT OR REPLACE INTO hosts_tags (host_id, tag_id)
|
340
|
-
SELECT host.id, tag.id FROM
|
341
|
-
( SELECT id FROM hosts WHERE LOWER(name) = LOWER(?) ) AS host,
|
342
|
-
( SELECT id FROM tags WHERE LOWER(name) = LOWER(?) AND LOWER(value) = LOWER(?) ) AS tag;
|
343
|
-
EOS
|
344
|
-
end
|
345
|
-
|
346
|
-
def select_name_from_hosts_by_id(db, host_id)
|
347
|
-
logger.debug("select_name_from_hosts_by_id(%s)" % [host_id.inspect])
|
348
|
-
prepare(db, "SELECT name FROM hosts WHERE id = ? LIMIT 1").execute(host_id).map { |row| row.first }.first
|
349
|
-
end
|
350
|
-
|
351
|
-
def select_tag_values_from_hosts_tags_by_host_id_and_tag_name_glob(db, host_id, tag_name)
|
352
|
-
logger.debug("select_tag_values_from_hosts_tags_by_host_id_and_tag_name_glob(%s, %s)" % [host_id.inspect, tag_name.inspect])
|
353
|
-
prepare(db, <<-EOS).execute(host_id, tag_name).map { |row| row.first }.join(",")
|
354
|
-
SELECT tags.value FROM hosts_tags
|
355
|
-
INNER JOIN tags ON hosts_tags.tag_id = tags.id
|
356
|
-
WHERE hosts_tags.host_id = ? AND LOWER(tags.name) GLOB LOWER(?);
|
357
|
-
EOS
|
358
|
-
end
|
359
|
-
|
360
|
-
def select_tag_values_from_hosts_tags_by_host_id_and_tag_name(db, host_id, tag_name)
|
361
|
-
logger.debug("select_tag_values_from_hosts_tags_by_host_id_and_tag_name(%s, %s)" % [host_id.inspect, tag_name.inspect])
|
362
|
-
prepare(db, <<-EOS).execute(host_id, tag_name).map { |row| row.first }.join(",")
|
363
|
-
SELECT tags.value FROM hosts_tags
|
364
|
-
INNER JOIN tags ON hosts_tags.tag_id = tags.id
|
365
|
-
WHERE hosts_tags.host_id = ? AND LOWER(tags.name) = LOWER(?);
|
366
|
-
EOS
|
367
|
-
end
|
368
|
-
|
369
|
-
def select_tag_names_from_hosts_tags_by_host_id(db, host_id)
|
370
|
-
logger.debug("select_tag_names_from_hosts_tags_by_host_id(%s)" % [host_id.inspect])
|
371
|
-
prepare(db, <<-EOS).execute(host_id).map { |row| row.first }
|
372
|
-
SELECT DISTINCT tags.name FROM hosts_tags
|
373
|
-
INNER JOIN tags ON hosts_tags.tag_id = tags.id
|
374
|
-
WHERE hosts_tags.host_id = ?;
|
375
|
-
EOS
|
376
|
-
end
|
377
327
|
end
|
378
328
|
end
|
379
329
|
end
|
@@ -4,10 +4,15 @@ module Hotdog
|
|
4
4
|
module Formatters
|
5
5
|
class Ltsv < BaseFormatter
|
6
6
|
def format(result, options={})
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
if options[:fields]
|
8
|
+
result.map { |row|
|
9
|
+
options[:fields].zip(row).map { |column| column.join(":") }.join("\t")
|
10
|
+
}.join("\n") + "\n"
|
11
|
+
else
|
12
|
+
result.map { |row|
|
13
|
+
row.join("\t")
|
14
|
+
}.join("\n") + "\n"
|
15
|
+
end
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
data/lib/hotdog/version.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/application"
|
3
|
+
require "hotdog/commands"
|
4
|
+
require "hotdog/commands/hosts"
|
5
|
+
require "hotdog/commands/search"
|
6
|
+
require "hotdog/commands/tags"
|
7
|
+
|
8
|
+
describe "application" do
|
9
|
+
let(:app) {
|
10
|
+
Hotdog::Application.new
|
11
|
+
}
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
ENV["DATADOG_API_KEY"] = "DATADOG_API_KEY"
|
15
|
+
ENV["DATADOG_APPLICATION_KEY"] = "DATADOG_APPLICATION_KEY"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "generates proper class name from file name" do
|
19
|
+
expect(app.__send__(:const_name, "csv")).to eq("Csv")
|
20
|
+
expect(app.__send__(:const_name, "json")).to eq("Json")
|
21
|
+
expect(app.__send__(:const_name, "pssh")).to eq("Pssh")
|
22
|
+
expect(app.__send__(:const_name, "parallel-ssh")).to eq("ParallelSsh")
|
23
|
+
end
|
24
|
+
|
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)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises error if the action is base-command" do
|
32
|
+
expect {
|
33
|
+
app.main(["base-command"])
|
34
|
+
}.to raise_error(NotImplementedError)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/formatters"
|
3
|
+
require "hotdog/formatters/csv"
|
4
|
+
|
5
|
+
describe "csv" do
|
6
|
+
let(:fmt) {
|
7
|
+
Hotdog::Formatters::Csv.new
|
8
|
+
}
|
9
|
+
|
10
|
+
it "generates csv without headers" do
|
11
|
+
options = {
|
12
|
+
headers: false,
|
13
|
+
}
|
14
|
+
expect(fmt.format([["foo", "aaa", 1], ["bar", "bbb", 2], ["baz", "ccc", 3]], options)).to eq(<<-EOS)
|
15
|
+
foo,aaa,1
|
16
|
+
bar,bbb,2
|
17
|
+
baz,ccc,3
|
18
|
+
EOS
|
19
|
+
end
|
20
|
+
|
21
|
+
it "generates csv with headers" do
|
22
|
+
options = {
|
23
|
+
headers: true,
|
24
|
+
fields: ["key1", "key2", "val1"],
|
25
|
+
}
|
26
|
+
expect(fmt.format([["foo", "aaa", 1], ["bar", "bbb", 2], ["baz", "ccc", 3]], options)).to eq(<<-EOS)
|
27
|
+
key1,key2,val1
|
28
|
+
foo,aaa,1
|
29
|
+
bar,bbb,2
|
30
|
+
baz,ccc,3
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/formatters"
|
3
|
+
require "hotdog/formatters/json"
|
4
|
+
|
5
|
+
describe "json" do
|
6
|
+
let(:fmt) {
|
7
|
+
Hotdog::Formatters::Json.new
|
8
|
+
}
|
9
|
+
|
10
|
+
it "generates json without headers" do
|
11
|
+
options = {
|
12
|
+
headers: false,
|
13
|
+
}
|
14
|
+
expect(fmt.format([["foo", "aaa", 1], ["bar", "bbb", 2], ["baz", "ccc", 3]], options)).to eq(<<-EOS)
|
15
|
+
[
|
16
|
+
[
|
17
|
+
"foo",
|
18
|
+
"aaa",
|
19
|
+
1
|
20
|
+
],
|
21
|
+
[
|
22
|
+
"bar",
|
23
|
+
"bbb",
|
24
|
+
2
|
25
|
+
],
|
26
|
+
[
|
27
|
+
"baz",
|
28
|
+
"ccc",
|
29
|
+
3
|
30
|
+
]
|
31
|
+
]
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
|
35
|
+
it "generates json with headers" do
|
36
|
+
options = {
|
37
|
+
headers: true,
|
38
|
+
fields: ["key1", "key2", "val1"],
|
39
|
+
prettyprint: false,
|
40
|
+
}
|
41
|
+
expect(fmt.format([["foo", "aaa", 1], ["bar", "bbb", 2], ["baz", "ccc", 3]], options)).to eq(<<-EOS)
|
42
|
+
[
|
43
|
+
[
|
44
|
+
"key1",
|
45
|
+
"key2",
|
46
|
+
"val1"
|
47
|
+
],
|
48
|
+
[
|
49
|
+
"foo",
|
50
|
+
"aaa",
|
51
|
+
1
|
52
|
+
],
|
53
|
+
[
|
54
|
+
"bar",
|
55
|
+
"bbb",
|
56
|
+
2
|
57
|
+
],
|
58
|
+
[
|
59
|
+
"baz",
|
60
|
+
"ccc",
|
61
|
+
3
|
62
|
+
]
|
63
|
+
]
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "hotdog/formatters"
|
3
|
+
require "hotdog/formatters/ltsv"
|
4
|
+
|
5
|
+
describe "ltsv" do
|
6
|
+
let(:fmt) {
|
7
|
+
Hotdog::Formatters::Ltsv.new
|
8
|
+
}
|
9
|
+
|
10
|
+
it "generates ltsv without headers" do
|
11
|
+
options = {
|
12
|
+
headers: false,
|
13
|
+
}
|
14
|
+
expect(fmt.format([["foo", "aaa", 1], ["bar", "bbb", 2], ["baz", "ccc", 3]], options)).to eq(<<-EOS)
|
15
|
+
foo\taaa\t1
|
16
|
+
bar\tbbb\t2
|
17
|
+
baz\tccc\t3
|
18
|
+
EOS
|
19
|
+
end
|
20
|
+
|
21
|
+
it "generates ltsv with headers" do
|
22
|
+
options = {
|
23
|
+
headers: true,
|
24
|
+
fields: ["key1", "key2", "val1"],
|
25
|
+
}
|
26
|
+
expect(fmt.format([["foo", "aaa", 1], ["bar", "bbb", 2], ["baz", "ccc", 3]], options)).to eq(<<-EOS)
|
27
|
+
key1:foo\tkey2:aaa\tval1:1
|
28
|
+
key1:bar\tkey2:bbb\tval1:2
|
29
|
+
key1:baz\tkey2:ccc\tval1:3
|
30
|
+
EOS
|
31
|
+
end
|
32
|
+
end
|