hosttag 0.12

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.
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
+