hosttag 0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +2 -0
  2. data/ChangeLog +44 -0
  3. data/EXCLUDE +3 -0
  4. data/LICENCE +674 -0
  5. data/README +92 -0
  6. data/Rakefile +30 -0
  7. data/TODO +4 -0
  8. data/bin/hosttag +168 -0
  9. data/bin/ht +168 -0
  10. data/bin/htdel +164 -0
  11. data/bin/htdump +70 -0
  12. data/bin/htexport +99 -0
  13. data/bin/htimport +81 -0
  14. data/bin/htremap +93 -0
  15. data/bin/htset +164 -0
  16. data/etc/Makefile +16 -0
  17. data/etc/README +10 -0
  18. data/hosttag.gemspec +23 -0
  19. data/hosttag.spec +179 -0
  20. data/lib/hosttag.rb +402 -0
  21. data/lib/hosttag/server.rb +35 -0
  22. data/test/data_hosttag/a/centos +0 -0
  23. data/test/data_hosttag/a/centos5 +0 -0
  24. data/test/data_hosttag/a/centos5-x86_64 +0 -0
  25. data/test/data_hosttag/a/public +0 -0
  26. data/test/data_hosttag/g/SKIP +0 -0
  27. data/test/data_hosttag/g/centos +0 -0
  28. data/test/data_hosttag/g/centos4 +0 -0
  29. data/test/data_hosttag/g/centos4-i386 +0 -0
  30. data/test/data_hosttag/h/SKIP +0 -0
  31. data/test/data_hosttag/h/centos +0 -0
  32. data/test/data_hosttag/h/centos4 +0 -0
  33. data/test/data_hosttag/h/centos4-x86_64 +0 -0
  34. data/test/data_hosttag/h/public +0 -0
  35. data/test/data_hosttag/m/centos +0 -0
  36. data/test/data_hosttag/m/centos4 +0 -0
  37. data/test/data_hosttag/m/centos4-x86_64 +0 -0
  38. data/test/data_hosttag/m/public +0 -0
  39. data/test/data_hosttag/m/vps +0 -0
  40. data/test/data_hosttag/n/centos +0 -0
  41. data/test/data_hosttag/n/centos5 +0 -0
  42. data/test/data_hosttag/n/centos5-i386 +0 -0
  43. data/test/data_hosttag/n/laptop +0 -0
  44. data/test/test_hosttag_bin.rb +70 -0
  45. data/test/test_hosttag_lib.rb +119 -0
  46. data/test/test_htset_bin.rb +174 -0
  47. data/test/test_htset_lib.rb +183 -0
  48. data/test/ts_all.rb +4 -0
  49. 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
+
@@ -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'
@@ -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
+