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
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Hosttag update client, redis version
4
+ #
5
+ # Usage:
6
+ # htset <host1> [<host2> ...] <tag> [<tag2> ...]
7
+ # htdel <host1> [<host2> ...] <tag> [<tag2> ...]
8
+ #
9
+
10
+ require 'optparse'
11
+ require 'fileutils'
12
+ require 'pp'
13
+
14
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
15
+ require 'hosttag'
16
+ include Hosttag
17
+
18
+ # ------------------------------------------------------------------------------
19
+ # Subroutines
20
+
21
+ def die(error)
22
+ puts error
23
+ exit 1
24
+ end
25
+
26
+ def parse_options(me)
27
+ options = { :all => false, :autoconfirm => false }
28
+ opts = OptionParser.new
29
+ opts.banner = "Usage: #{me} [options] <host> [<host2> ...] <tag> [<tag2>...]"
30
+ opts.on('-?', '-h', '--help') do
31
+ puts opts
32
+ exit
33
+ end
34
+ opts.on('-h', '--help', '-?', 'Show this usage information') do
35
+ die(opts)
36
+ end
37
+ opts.on('-A', '--all', '(htdel) Delete all tags from hosts') do
38
+ options[:all] = true
39
+ end
40
+ opts.on('-y', '--yes', "(htdel) Don't ask for confirmation on delete all operations") do
41
+ options[:autoconfirm] = true
42
+ end
43
+ opts.on('-H', '--host', '--hosts', 'Treat unrecognised elements as hosts') do
44
+ options[:host_mode] = true
45
+ end
46
+ opts.on('-T', '--tag', '--tags', 'Treat unrecognised elements as tags') do
47
+ options[:tag_mode] = true
48
+ end
49
+ opts.on('--ns=STR', '--namespace=STR', String, 'Namespace into which we load hosttag data. Default: hosttag') do |val|
50
+ options[:namespace] = val
51
+ end
52
+ opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to') do |val|
53
+ options[:server] = val
54
+ end
55
+ opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to') do |val|
56
+ options[:port] = val
57
+ end
58
+ opts.on('-v', '--verbose', 'Verbose output') do
59
+ options[:verbose] = true
60
+ end
61
+
62
+ # Parse options
63
+ begin
64
+ args = opts.parse(ARGV)
65
+ rescue => e
66
+ die(opts)
67
+ end
68
+
69
+ if args.length < 2 and not options[:all]
70
+ die(opts)
71
+ end
72
+ if options[:all] and me =~ /set$/
73
+ warn "Error: --all not available with #{me}"
74
+ die(opts)
75
+ end
76
+ if options[:host_mode] and options[:tag_mode]
77
+ warn "Error: --host and --tag options are mutually exclusive"
78
+ die(opts)
79
+ end
80
+
81
+ return options, args
82
+ end
83
+
84
+ # Classify args into hosts, tags, and uncertain buckets
85
+ def classify_args(args, options)
86
+ results = { :host => [], :tag => [], :uncertain => [] }
87
+ verbose = options[:verbose]
88
+
89
+ # First arg must be host, and last tag, by definition
90
+ results[:host].push(args.shift)
91
+ last_tag = args.pop
92
+
93
+ # Classify remainder by doing lookups
94
+ while a = args.shift do
95
+ begin
96
+ tags = hosttag_lookup_hosts(a, options)
97
+ if tags.length > 0
98
+ # if 'a' is a valid host, then everything already in uncertain must be too
99
+ if results[:uncertain].length > 0
100
+ results[:host].push(*results[:uncertain])
101
+ results[:uncertain] = []
102
+ end
103
+ results[:host].push(a)
104
+ end
105
+ rescue
106
+ # 'a' is not a known host, check if a tag
107
+ begin
108
+ hosts = hosttag_lookup_tags(a, options)
109
+ if hosts.length > 0
110
+ # If 'a' is a valid tag, then everything else in args must be too
111
+ results[:tag].push(a, *args)
112
+ args = []
113
+ end
114
+ rescue
115
+ # 'a' is not a known host or tag, add to uncertain list
116
+ results[:uncertain].push(a)
117
+ end
118
+ end
119
+ end
120
+
121
+ results[:tag].push(last_tag)
122
+
123
+ return results
124
+ end
125
+
126
+ # ------------------------------------------------------------------------------
127
+ # Main
128
+
129
+ mode = $0.sub(/^.*\//, '')
130
+
131
+ options, args = parse_options(mode)
132
+
133
+ # Normal mode
134
+ if (not options[:all])
135
+ results = classify_args(args, options)
136
+ if options[:verbose]
137
+ print "+ results: "
138
+ pp results
139
+ end
140
+
141
+ if results[:uncertain].length > 0
142
+ # --hosts: treat unknown elements as hosts
143
+ if options[:host_mode]
144
+ results[:host].push(*results[:uncertain])
145
+ elsif options[:tag_mode]
146
+ results[:tag].push(*results[:uncertain])
147
+ else
148
+ # TODO: do something useful here - ask the user?
149
+ die("Error: can't auto-classify '#{results[:uncertain].join(',')}' - aborting")
150
+ end
151
+ end
152
+
153
+ if (mode =~ /del$/)
154
+ hosttag_delete_tags(results[:host], results[:tag], options)
155
+ else
156
+ hosttag_add_tags(results[:host], results[:tag], options)
157
+ end
158
+
159
+ # htdel --all mode
160
+ elsif (mode =~ /del$/)
161
+ hosttag_delete_all_tags(args, options)
162
+
163
+ end
164
+
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Quick and dirty script to dump hosttag datastore
4
+ #
5
+
6
+ require 'optparse'
7
+
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
9
+ require 'hosttag/server'
10
+
11
+ defaults = {}
12
+
13
+ def die(error)
14
+ puts error
15
+ exit 1
16
+ end
17
+
18
+ def parse_options(options)
19
+ opts = OptionParser.new
20
+ opts.banner = "Usage: htimport [options]"
21
+ opts.on('-?', '-h', '--help') do
22
+ puts opts
23
+ exit
24
+ end
25
+ opts.on('-h', '--help', '-?', 'Show this usage information') do
26
+ die(opts)
27
+ end
28
+ opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to. Default: hosttag') do |val|
29
+ options[:server] = val
30
+ end
31
+ opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to. Default: 6379') do |val|
32
+ options[:port] = val
33
+ end
34
+ opts.on('--ns=STR', '--namespace=STR', String, 'Namespace from which to dump hosttag data. Default: hosttag') do |val|
35
+ options[:namespace] = val
36
+ end
37
+
38
+ # Parse options
39
+ begin
40
+ args = opts.parse(ARGV)
41
+ rescue => e
42
+ puts "Error: " << e
43
+ usage(opts)
44
+ end
45
+
46
+ if args.length > 0
47
+ puts "Error: unexpected arguments '#{args}'"
48
+ usage(opts)
49
+ end
50
+
51
+ return options
52
+ end
53
+
54
+ def usage(opts)
55
+ puts opts
56
+ exit
57
+ end
58
+
59
+ # ----------------------------------------------------------------------------
60
+ # Main
61
+
62
+ options, args = parse_options( defaults )
63
+
64
+ r = Hosttag::Server.new(options)
65
+
66
+ # Dump
67
+ r.keys(r.get_key('*')).sort.each do |k|
68
+ puts "#{k}: #{r.smembers(k).sort.join(' ')}"
69
+ end
70
+
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Export host tags held from redis to /etc/hosttag
4
+ #
5
+
6
+ require 'optparse'
7
+ require 'fileutils'
8
+
9
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
10
+ require 'hosttag/server'
11
+
12
+ defaults = { :datadir => '/etc/hosttag' }
13
+
14
+ # ------------------------------------------------------------------------------
15
+ # Subroutines
16
+
17
+ def die(error)
18
+ puts error
19
+ exit 1
20
+ end
21
+
22
+ def parse_options(options)
23
+ opts = OptionParser.new
24
+ opts.banner = "Usage: htexport [options]"
25
+ opts.on('-?', '-h', '--help') do
26
+ puts opts
27
+ exit
28
+ end
29
+ opts.on('-h', '--help', '-?', 'Show this usage information') do
30
+ die(opts)
31
+ end
32
+ opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to') do |val|
33
+ options[:server] = val
34
+ end
35
+ opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to') do |val|
36
+ options[:port] = val
37
+ end
38
+ opts.on('--datadir=DIR', String, 'Data directory to export data into. Default: /etc/hosttag') do |val|
39
+ options[:datadir] = val
40
+ end
41
+ opts.on('--ns=STR', '--namespace=STR', String, 'Namespace into which we load hosttag data. Default: hosttag') do |val|
42
+ options[:namespace] = val
43
+ end
44
+ opts.on('--delete', 'Delete mode - remove all directories from data dir before exporting') do
45
+ options[:delete] = true
46
+ end
47
+ opts.on('-n', '--noop', 'Noop mode - only report what would be exported') do
48
+ options[:noop] = true
49
+ end
50
+ opts.on('-v', '--verbose', 'Verbose output') do
51
+ options[:verbose] = true
52
+ end
53
+
54
+ # Parse options
55
+ begin
56
+ args = opts.parse(ARGV)
57
+ rescue => e
58
+ die(opts)
59
+ end
60
+
61
+ if args.length > 0
62
+ die(opts)
63
+ end
64
+
65
+ return options, args
66
+ end
67
+
68
+ def prune_data_directory
69
+ # TODO
70
+ die "--delete mode not implemented yet"
71
+ end
72
+
73
+ # ----------------------------------------------------------------------------
74
+ # Main
75
+
76
+ options, args = parse_options( defaults )
77
+
78
+ r = Hosttag::Server.new(options)
79
+
80
+ Dir.chdir(options[:datadir])
81
+
82
+ # If in delete mode, prune the data directory
83
+ if options[:delete] and not options[:noop]
84
+ prune_data_directory
85
+ end
86
+
87
+ r.smembers(r.get_key('all_hosts')).each do |host|
88
+ if not File.directory?(host)
89
+ puts "+ #{host}/"
90
+ Dir.mkdir(host, 0775) if not options[:noop]
91
+ end
92
+ r.smembers(r.get_key('host', host)).each do |tag|
93
+ if not File.exist?("#{host}/#{tag}")
94
+ puts "+ #{host}/#{tag}"
95
+ FileUtils.touch "#{host}/#{tag}" if not options[:noop]
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Import hosts and tags into datastore from a directory
4
+ #
5
+
6
+ require 'optparse'
7
+ require 'fileutils'
8
+
9
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
10
+ require 'hosttag'
11
+ include Hosttag
12
+
13
+ defaults = { :datadir => '/etc/hosttag' }
14
+
15
+ # ------------------------------------------------------------------------------
16
+ # Subroutines
17
+
18
+ def die(error)
19
+ puts error
20
+ exit 1
21
+ end
22
+
23
+ def usage(opts)
24
+ puts opts
25
+ exit
26
+ end
27
+
28
+ def parse_options(options)
29
+ opts = OptionParser.new
30
+ opts.banner = "Usage: htimport [options]"
31
+ opts.on('-?', '-h', '--help') do
32
+ puts opts
33
+ exit
34
+ end
35
+ opts.on('-h', '--help', '-?', 'Show this usage information') do
36
+ die(opts)
37
+ end
38
+ opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to. Default: hosttag') do |val|
39
+ options[:server] = val
40
+ end
41
+ opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to. Default: 6379') do |val|
42
+ options[:port] = val
43
+ end
44
+ opts.on('--delete', 'Delete mode - remove all hosttags from the datastore before importing') do
45
+ options[:delete] = true
46
+ end
47
+ opts.on('-y', '--yes', "(--delete) Assume automatic confirmation for --delete") do
48
+ options[:autoconfirm] = true
49
+ end
50
+ opts.on('--datadir=DIR', String, 'Data directory from which to load data. Default: /etc/hosttag') do |val|
51
+ options[:datadir] = val
52
+ end
53
+ opts.on('--ns=STR', '--namespace=STR', String, 'Namespace into which we load hosttag data. Default: hosttag') do |val|
54
+ options[:namespace] = val
55
+ end
56
+ opts.on('-v', '--verbose', 'Verbose output') do
57
+ options[:verbose] = true
58
+ end
59
+
60
+ # Parse options
61
+ begin
62
+ args = opts.parse(ARGV)
63
+ rescue => e
64
+ puts "Error: " << e
65
+ usage(opts)
66
+ end
67
+
68
+ if args.length > 0
69
+ puts "Error: unexpected arguments '#{args}'"
70
+ usage(opts)
71
+ end
72
+
73
+ return options
74
+ end
75
+
76
+ # ----------------------------------------------------------------------------
77
+ # Main
78
+
79
+ options = parse_options(defaults)
80
+ hosttag_import_from_directory(options[:datadir], options)
81
+
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Quick and dirty script to remap all_* keys to the new naming convention:
4
+ # - all_{hosts,tags} => all_{hosts,tags}_full,
5
+ # - all_{hosts,tags}_noskip => all_{hosts,tags}
6
+ #
7
+
8
+ require 'optparse'
9
+
10
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
11
+ require 'hosttag/server'
12
+ require 'hosttag'
13
+ include Hosttag
14
+
15
+ defaults = {}
16
+
17
+ def die(error)
18
+ puts error
19
+ exit 1
20
+ end
21
+
22
+ def parse_options(options)
23
+ opts = OptionParser.new
24
+ opts.banner = "Usage: htimport [options]"
25
+ opts.on('-?', '-h', '--help') do
26
+ puts opts
27
+ exit
28
+ end
29
+ opts.on('-h', '--help', '-?', 'Show this usage information') do
30
+ die(opts)
31
+ end
32
+ opts.on('-s=ARG', '--server=ARG', String, 'Server hostname to connect to. Default: hosttag') do |val|
33
+ options[:server] = val
34
+ end
35
+ opts.on('-p=ARG', '--port=ARG', Integer, 'Server port to connect to. Default: 6379') do |val|
36
+ options[:port] = val
37
+ end
38
+ opts.on('--ns=STR', '--namespace=STR', String, 'Namespace from which to dump hosttag data. Default: hosttag') do |val|
39
+ options[:namespace] = val
40
+ end
41
+
42
+ # Parse options
43
+ begin
44
+ args = opts.parse(ARGV)
45
+ rescue => e
46
+ puts "Error: " << e
47
+ usage(opts)
48
+ end
49
+
50
+ if args.length > 0
51
+ puts "Error: unexpected arguments '#{args}'"
52
+ usage(opts)
53
+ end
54
+
55
+ return options
56
+ end
57
+
58
+ def usage(opts)
59
+ puts opts
60
+ exit
61
+ end
62
+
63
+ # ----------------------------------------------------------------------------
64
+ # Main
65
+
66
+ options = parse_options( defaults )
67
+ r = Hosttag::Server.new(options)
68
+
69
+ key = r.get_key('all_hosts_noskip')
70
+ if not r.exists(key)
71
+ puts "No 'all_hosts_noskip' key found - aborting"
72
+ exit 1
73
+ end
74
+
75
+ %w{all_hosts all_tags}.each do |all_x|
76
+ key = r.get_key(all_x)
77
+ return unless r.exists(key)
78
+ members = r.smembers(key)
79
+ new_key = r.get_key("#{all_x}_full")
80
+ members.each { |m| r.sadd(new_key, m) }
81
+ r.del(key)
82
+ end
83
+
84
+ %w{all_hosts_noskip all_tags_noskip}.each do |all_x|
85
+ key = r.get_key(all_x)
86
+ return unless r.exists(key)
87
+ members = r.smembers(key)
88
+ all_x_new = all_x.sub(/_noskip$/, '')
89
+ new_key = r.get_key(all_x_new)
90
+ members.each { |m| r.sadd(new_key, m) }
91
+ r.del(key)
92
+ end
93
+