hosttag 0.12
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/ChangeLog +44 -0
- data/EXCLUDE +3 -0
- data/LICENCE +674 -0
- data/README +92 -0
- data/Rakefile +30 -0
- data/TODO +4 -0
- data/bin/hosttag +168 -0
- data/bin/ht +168 -0
- data/bin/htdel +164 -0
- data/bin/htdump +70 -0
- data/bin/htexport +99 -0
- data/bin/htimport +81 -0
- data/bin/htremap +93 -0
- data/bin/htset +164 -0
- data/etc/Makefile +16 -0
- data/etc/README +10 -0
- data/hosttag.gemspec +23 -0
- data/hosttag.spec +179 -0
- data/lib/hosttag.rb +402 -0
- data/lib/hosttag/server.rb +35 -0
- data/test/data_hosttag/a/centos +0 -0
- data/test/data_hosttag/a/centos5 +0 -0
- data/test/data_hosttag/a/centos5-x86_64 +0 -0
- data/test/data_hosttag/a/public +0 -0
- data/test/data_hosttag/g/SKIP +0 -0
- data/test/data_hosttag/g/centos +0 -0
- data/test/data_hosttag/g/centos4 +0 -0
- data/test/data_hosttag/g/centos4-i386 +0 -0
- data/test/data_hosttag/h/SKIP +0 -0
- data/test/data_hosttag/h/centos +0 -0
- data/test/data_hosttag/h/centos4 +0 -0
- data/test/data_hosttag/h/centos4-x86_64 +0 -0
- data/test/data_hosttag/h/public +0 -0
- data/test/data_hosttag/m/centos +0 -0
- data/test/data_hosttag/m/centos4 +0 -0
- data/test/data_hosttag/m/centos4-x86_64 +0 -0
- data/test/data_hosttag/m/public +0 -0
- data/test/data_hosttag/m/vps +0 -0
- data/test/data_hosttag/n/centos +0 -0
- data/test/data_hosttag/n/centos5 +0 -0
- data/test/data_hosttag/n/centos5-i386 +0 -0
- data/test/data_hosttag/n/laptop +0 -0
- data/test/test_hosttag_bin.rb +70 -0
- data/test/test_hosttag_lib.rb +119 -0
- data/test/test_htset_bin.rb +174 -0
- data/test/test_htset_lib.rb +183 -0
- data/test/ts_all.rb +4 -0
- metadata +132 -0
data/README
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
Introduction
|
2
|
+
------------
|
3
|
+
|
4
|
+
Hosttag is a client for tagging hostnames into groups or classes, storing
|
5
|
+
the mappings in a redis datastore. It requires the 'redis' rubygem.
|
6
|
+
|
7
|
+
|
8
|
+
Hosttag assumes your redis server is found on a server called 'hosttag' on
|
9
|
+
the default redis port (6379). You can either setup 'hosttag' as a hostname
|
10
|
+
alias in a local hosts file, or specify an alternative host to use in a
|
11
|
+
HOSTTAG_SERVER environment variable, or explicitly via a -s/--server
|
12
|
+
<hostname> argument. Similarly, an alternate port can be specified using a
|
13
|
+
HOSTTAG_PORT environment variable, or a -p/--port <port> command line
|
14
|
+
argument.
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
Basic Usage
|
19
|
+
-----------
|
20
|
+
|
21
|
+
# Set some tags (-T says assume anything you don't know is a tag)
|
22
|
+
$ htset -T zeus dell centos centos5 server
|
23
|
+
$ htset -T minerva dell centos centos6 laptop
|
24
|
+
$ htset -T hermes hp ubuntu lucid desktop
|
25
|
+
$ htset -T athena hp ubuntu maverick server
|
26
|
+
|
27
|
+
|
28
|
+
# Queries
|
29
|
+
$ ht dell
|
30
|
+
minerva zeus
|
31
|
+
|
32
|
+
$ ht ubuntu
|
33
|
+
hermes athena
|
34
|
+
|
35
|
+
$ ht -o hp dell # -o/--or ORs arguments
|
36
|
+
hermes minerva zeus
|
37
|
+
|
38
|
+
$ ht -a ubuntu server # -a/--and ANDs arguments
|
39
|
+
athena
|
40
|
+
|
41
|
+
$ ht -A # all hosts
|
42
|
+
athena hermes minerva zeus
|
43
|
+
|
44
|
+
$ ht -T # all tags
|
45
|
+
centos centos5 centos6 dell desktop hp laptop lucid maverick server
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
Security
|
51
|
+
--------
|
52
|
+
|
53
|
+
A warning on security: basically, there isn't any. Anyone who can get write
|
54
|
+
to your redis server can write, rewrite, and delete all your hosttags. So
|
55
|
+
you should only use hosttag on a trusted network.
|
56
|
+
|
57
|
+
Redis supports a password-ed mode, and it might make sense to use that via
|
58
|
+
a config file or something, so you could at least restrict usage via file
|
59
|
+
permissions (although traffic would still be in the clear, I believe). For
|
60
|
+
now, though, there's no security.
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
Installation
|
65
|
+
------------
|
66
|
+
|
67
|
+
To install from source, unpack the tarball and run 'rake install' (requires
|
68
|
+
rubygems and rake). You can set GEM_HOME to an alternate install directory
|
69
|
+
(e.g. ~/.gem) if you want to install somewhere other than your gem default.
|
70
|
+
|
71
|
+
RPMs are available for CentOS/RHEL {5,6} from the Open Fusion repository:
|
72
|
+
|
73
|
+
http://www.openfusion.net/linux/openfusion_rpm_repository
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
Author
|
79
|
+
------
|
80
|
+
|
81
|
+
Gavin Carr <gavin@openfusion.com.au>, http://www.openfusion.net/
|
82
|
+
|
83
|
+
Copyright 2010-2011 Gavin Carr.
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
Licence
|
88
|
+
-------
|
89
|
+
|
90
|
+
This software is free software, licensed under the GNU Public License v3
|
91
|
+
or any later version.
|
92
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
desc 'Run tests'
|
3
|
+
task :test do
|
4
|
+
system 'ruby -I lib -I test test/ts_all.rb'
|
5
|
+
end
|
6
|
+
|
7
|
+
gemspec = eval(File.read(Dir["*.gemspec"].first))
|
8
|
+
|
9
|
+
desc "Validate the gemspec"
|
10
|
+
task :validate do
|
11
|
+
gemspec.validate
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Build gem locally"
|
15
|
+
task :build => :validate do
|
16
|
+
system "gem build #{gemspec.name}.gemspec"
|
17
|
+
FileUtils.mkdir_p "pkg"
|
18
|
+
FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Install gem locally"
|
22
|
+
task :install => :build do
|
23
|
+
system "gem install pkg/#{gemspec.name}-#{gemspec.version}"
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Clean automatically generated files"
|
27
|
+
task :clean do
|
28
|
+
FileUtils.rm_rf "pkg"
|
29
|
+
end
|
30
|
+
|
data/TODO
ADDED
@@ -0,0 +1,4 @@
|
|
1
|
+
- ht -l -A doesn't work as expected
|
2
|
+
- ht -l -T doesn't work as expected
|
3
|
+
- it would be nice to able to do 'ht -x usd001 na', 'ht -X ignore_file na', 'ht -x usd001 -A'
|
4
|
+
- it would also be nice to able to do 'ht -n dell -n supermicro -A', 'ht -n dell server', 'ht -N not_file -A', 'ht -N not_file server'
|
data/bin/hosttag
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# hosttag query client
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# ht <tag>
|
7
|
+
#
|
8
|
+
# ht [-a] <tag1> <tag2> Show hosts with tag1 AND tag2 (intersection, default)
|
9
|
+
# ht -o <tag1> <tag2> Show hosts with tag1 OR tag2 (union)
|
10
|
+
#
|
11
|
+
# ht -A Show all hosts
|
12
|
+
#
|
13
|
+
# ht -t <host> Show tags on 'host'
|
14
|
+
# ht -t [-o] <host1> <host2> Show tags on 'host' OR 'host2' (union, default)
|
15
|
+
# ht -t -a <host1> <host2> Show tags on 'host' AND 'host2' (intersection)
|
16
|
+
#
|
17
|
+
# ht -T Show all tags
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'optparse'
|
21
|
+
|
22
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
23
|
+
require 'hosttag'
|
24
|
+
include Hosttag
|
25
|
+
|
26
|
+
# -------------------------------------------------------------------------
|
27
|
+
# Subroutines
|
28
|
+
|
29
|
+
def die(error)
|
30
|
+
warn error
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
def usage(opts, msg = nil)
|
35
|
+
if msg
|
36
|
+
warn msg
|
37
|
+
$stderr.puts
|
38
|
+
end
|
39
|
+
warn opts
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
def render(results, options, arg = nil)
|
44
|
+
return unless results and results.length > 0
|
45
|
+
# Report
|
46
|
+
if options[:list]
|
47
|
+
puts "#{arg}: #{results.sort.join(' ')}"
|
48
|
+
else
|
49
|
+
puts results.sort.join(options[:join])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# -------------------------------------------------------------------------
|
54
|
+
# Main
|
55
|
+
|
56
|
+
options = { :join => ' ' }
|
57
|
+
|
58
|
+
opts = OptionParser.new
|
59
|
+
opts.banner = "Usage: hosttag [options] <tag> [<tag2>...]"
|
60
|
+
opts.on('-?', '-h', '--help') do
|
61
|
+
puts opts
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
opts.on('-a', '--and', 'Report hosts with ALL the given tags (AND result sets)') do
|
65
|
+
options[:rel] = :and
|
66
|
+
end
|
67
|
+
opts.on('-o', '--or', 'Report hosts with ANY of the given tags (OR result sets)') do
|
68
|
+
options[:rel] = :or
|
69
|
+
end
|
70
|
+
opts.on('-l', '--list', "List hosts/tags separately for each tag/host") do
|
71
|
+
options[:list] = 1
|
72
|
+
end
|
73
|
+
opts.on('-t', '--tag', '--tags', "Tag mode: report tags for the given hosts") do
|
74
|
+
options[:type] = :host
|
75
|
+
end
|
76
|
+
opts.on('-A', '--all', 'Report all hosts') do
|
77
|
+
if not options[:all]
|
78
|
+
options[:all] = :hosts
|
79
|
+
elsif options[:all] == :hosts
|
80
|
+
options[:include_skip?] ||= true
|
81
|
+
else
|
82
|
+
usage(opts, "Error: can't specify both -A/--all-hosts and -T/--all-tags")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
opts.on('-T', '--all-tags', 'Report all tags') do
|
86
|
+
if not options[:all]
|
87
|
+
options[:all] = :tags
|
88
|
+
elsif options[:all] == :tags
|
89
|
+
options[:include_skip?] ||= true
|
90
|
+
else
|
91
|
+
usage(opts, "Error: can't specify both -A/--all-hosts and -T/--all-tags")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
opts.on('-1', 'List one item per line') do
|
95
|
+
options[:one] = 1
|
96
|
+
options[:join] = "\n"
|
97
|
+
end
|
98
|
+
opts.on('-d', '--delimiter=STR', String, 'Delimiter for reporting (default " ")') do |val|
|
99
|
+
options[:join] = val
|
100
|
+
end
|
101
|
+
opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to. Default: hosttag') do |val|
|
102
|
+
options[:server] = val
|
103
|
+
end
|
104
|
+
opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to') do |val|
|
105
|
+
options[:port] = val
|
106
|
+
end
|
107
|
+
opts.on('--ns=STR', '--namespace=STR', String, 'Namespace into which we load hosttag data. Default: hosttag') do |val|
|
108
|
+
options[:namespace] = val
|
109
|
+
end
|
110
|
+
opts.on('-v', '--verbose', 'Verbose output') do
|
111
|
+
options[:verbose] = true
|
112
|
+
end
|
113
|
+
|
114
|
+
# Parse options
|
115
|
+
begin
|
116
|
+
args = opts.parse(ARGV)
|
117
|
+
rescue => e
|
118
|
+
usage(opts, "Error: " << e)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Sanity checks
|
122
|
+
if args.length == 0 and not options[:all]
|
123
|
+
usage(opts)
|
124
|
+
end
|
125
|
+
if args.length > 0 and options[:all]
|
126
|
+
if options[:all] == :hosts
|
127
|
+
error = "Error: can't specify hosts with -A/--all-hosts"
|
128
|
+
else
|
129
|
+
error = "Error: can't specify tags with -T/--all-tags"
|
130
|
+
end
|
131
|
+
usage(opts, error)
|
132
|
+
end
|
133
|
+
if options[:list] and options[:one]
|
134
|
+
usage(opts, "Warning: -L/--list and -1 are incompatible")
|
135
|
+
end
|
136
|
+
|
137
|
+
# All request
|
138
|
+
if options[:all]
|
139
|
+
if options[:all] == :hosts
|
140
|
+
all = hosttag_all_hosts(options)
|
141
|
+
else
|
142
|
+
all = hosttag_all_tags(options)
|
143
|
+
end
|
144
|
+
if options[:list]
|
145
|
+
args = all
|
146
|
+
else
|
147
|
+
render all, options
|
148
|
+
exit
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Standard request
|
153
|
+
# In list mode, process all args separately; otherwise, do them all at once
|
154
|
+
if options[:list]
|
155
|
+
arg_list = args
|
156
|
+
else
|
157
|
+
arg_list = [ args ]
|
158
|
+
end
|
159
|
+
|
160
|
+
arg_list.each do |a|
|
161
|
+
begin
|
162
|
+
results = hosttag_lookup(a, options)
|
163
|
+
render results, options, a
|
164
|
+
rescue => e
|
165
|
+
warn e
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
data/bin/ht
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# hosttag query client
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# ht <tag>
|
7
|
+
#
|
8
|
+
# ht [-a] <tag1> <tag2> Show hosts with tag1 AND tag2 (intersection, default)
|
9
|
+
# ht -o <tag1> <tag2> Show hosts with tag1 OR tag2 (union)
|
10
|
+
#
|
11
|
+
# ht -A Show all hosts
|
12
|
+
#
|
13
|
+
# ht -t <host> Show tags on 'host'
|
14
|
+
# ht -t [-o] <host1> <host2> Show tags on 'host' OR 'host2' (union, default)
|
15
|
+
# ht -t -a <host1> <host2> Show tags on 'host' AND 'host2' (intersection)
|
16
|
+
#
|
17
|
+
# ht -T Show all tags
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'optparse'
|
21
|
+
|
22
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
23
|
+
require 'hosttag'
|
24
|
+
include Hosttag
|
25
|
+
|
26
|
+
# -------------------------------------------------------------------------
|
27
|
+
# Subroutines
|
28
|
+
|
29
|
+
def die(error)
|
30
|
+
warn error
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
def usage(opts, msg = nil)
|
35
|
+
if msg
|
36
|
+
warn msg
|
37
|
+
$stderr.puts
|
38
|
+
end
|
39
|
+
warn opts
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
def render(results, options, arg = nil)
|
44
|
+
return unless results and results.length > 0
|
45
|
+
# Report
|
46
|
+
if options[:list]
|
47
|
+
puts "#{arg}: #{results.sort.join(' ')}"
|
48
|
+
else
|
49
|
+
puts results.sort.join(options[:join])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# -------------------------------------------------------------------------
|
54
|
+
# Main
|
55
|
+
|
56
|
+
options = { :join => ' ' }
|
57
|
+
|
58
|
+
opts = OptionParser.new
|
59
|
+
opts.banner = "Usage: hosttag [options] <tag> [<tag2>...]"
|
60
|
+
opts.on('-?', '-h', '--help') do
|
61
|
+
puts opts
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
opts.on('-a', '--and', 'Report hosts with ALL the given tags (AND result sets)') do
|
65
|
+
options[:rel] = :and
|
66
|
+
end
|
67
|
+
opts.on('-o', '--or', 'Report hosts with ANY of the given tags (OR result sets)') do
|
68
|
+
options[:rel] = :or
|
69
|
+
end
|
70
|
+
opts.on('-l', '--list', "List hosts/tags separately for each tag/host") do
|
71
|
+
options[:list] = 1
|
72
|
+
end
|
73
|
+
opts.on('-t', '--tag', '--tags', "Tag mode: report tags for the given hosts") do
|
74
|
+
options[:type] = :host
|
75
|
+
end
|
76
|
+
opts.on('-A', '--all', 'Report all hosts') do
|
77
|
+
if not options[:all]
|
78
|
+
options[:all] = :hosts
|
79
|
+
elsif options[:all] == :hosts
|
80
|
+
options[:include_skip?] ||= true
|
81
|
+
else
|
82
|
+
usage(opts, "Error: can't specify both -A/--all-hosts and -T/--all-tags")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
opts.on('-T', '--all-tags', 'Report all tags') do
|
86
|
+
if not options[:all]
|
87
|
+
options[:all] = :tags
|
88
|
+
elsif options[:all] == :tags
|
89
|
+
options[:include_skip?] ||= true
|
90
|
+
else
|
91
|
+
usage(opts, "Error: can't specify both -A/--all-hosts and -T/--all-tags")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
opts.on('-1', 'List one item per line') do
|
95
|
+
options[:one] = 1
|
96
|
+
options[:join] = "\n"
|
97
|
+
end
|
98
|
+
opts.on('-d', '--delimiter=STR', String, 'Delimiter for reporting (default " ")') do |val|
|
99
|
+
options[:join] = val
|
100
|
+
end
|
101
|
+
opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to. Default: hosttag') do |val|
|
102
|
+
options[:server] = val
|
103
|
+
end
|
104
|
+
opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to') do |val|
|
105
|
+
options[:port] = val
|
106
|
+
end
|
107
|
+
opts.on('--ns=STR', '--namespace=STR', String, 'Namespace into which we load hosttag data. Default: hosttag') do |val|
|
108
|
+
options[:namespace] = val
|
109
|
+
end
|
110
|
+
opts.on('-v', '--verbose', 'Verbose output') do
|
111
|
+
options[:verbose] = true
|
112
|
+
end
|
113
|
+
|
114
|
+
# Parse options
|
115
|
+
begin
|
116
|
+
args = opts.parse(ARGV)
|
117
|
+
rescue => e
|
118
|
+
usage(opts, "Error: " << e)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Sanity checks
|
122
|
+
if args.length == 0 and not options[:all]
|
123
|
+
usage(opts)
|
124
|
+
end
|
125
|
+
if args.length > 0 and options[:all]
|
126
|
+
if options[:all] == :hosts
|
127
|
+
error = "Error: can't specify hosts with -A/--all-hosts"
|
128
|
+
else
|
129
|
+
error = "Error: can't specify tags with -T/--all-tags"
|
130
|
+
end
|
131
|
+
usage(opts, error)
|
132
|
+
end
|
133
|
+
if options[:list] and options[:one]
|
134
|
+
usage(opts, "Warning: -L/--list and -1 are incompatible")
|
135
|
+
end
|
136
|
+
|
137
|
+
# All request
|
138
|
+
if options[:all]
|
139
|
+
if options[:all] == :hosts
|
140
|
+
all = hosttag_all_hosts(options)
|
141
|
+
else
|
142
|
+
all = hosttag_all_tags(options)
|
143
|
+
end
|
144
|
+
if options[:list]
|
145
|
+
args = all
|
146
|
+
else
|
147
|
+
render all, options
|
148
|
+
exit
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Standard request
|
153
|
+
# In list mode, process all args separately; otherwise, do them all at once
|
154
|
+
if options[:list]
|
155
|
+
arg_list = args
|
156
|
+
else
|
157
|
+
arg_list = [ args ]
|
158
|
+
end
|
159
|
+
|
160
|
+
arg_list.each do |a|
|
161
|
+
begin
|
162
|
+
results = hosttag_lookup(a, options)
|
163
|
+
render results, options, a
|
164
|
+
rescue => e
|
165
|
+
warn e
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|