loe-icagent 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,2 @@
1
+ icagent registers a node with iclassify, and lets you use small DSL for
2
+ classifiying them.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/bin/icagent ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # iClassify - A node classification service.
4
+ # Copyright (C) 2007 HJK Solutions and Adam Jacob (<adam@hjksolutions.com>)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program; if not, write to the Free Software Foundation, Inc.,
18
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ #
20
+ # icagent registers a node with iclassify, and lets you use small DSL for
21
+ # classifiying them.
22
+
23
+ require 'rubygems'
24
+ require File.dirname(__FILE__) + '/../lib/iclassify'
25
+ require 'optparse'
26
+
27
+ config = {
28
+ :uuidfile => File.dirname(__FILE__) + '/../icagent.uuid',
29
+ :server => 'https://ops.onehub.com'
30
+ }
31
+ opts = OptionParser.new do |opts|
32
+ opts.banner = "Usage: #{$0} [-d DIR|-r FILE] (options)"
33
+ opts.on("-d DIRECTORY", "--directory DIRECTORY", "Path to icagent recipes") do |d|
34
+ config[:directory] = d
35
+ end
36
+ opts.on("-r RECIPE", "--recipe RECIPE", "Path to a single icagent recipe") do |r|
37
+ config[:recipe] = r
38
+ end
39
+ opts.on("-u UUIDFILE", "--uuidfile UUIDFILE", "Path to the uuid file") do |u|
40
+ config[:uuidfile] = u
41
+ end
42
+ opts.on("-s SERVER", "--server", "iClassify Server URL") do |s|
43
+ config[:server] = s
44
+ end
45
+ opts.on("-n", "--no-action", "Don't update anything, just print.") do |n|
46
+ config[:dryrun] = true
47
+ end
48
+ opts.on("-w WAIT", "--wait TIME", "Wait for up to TIME seconds.") do |w|
49
+ config[:wait] = w.to_i
50
+ end
51
+ opts.on_tail("-h", "--help", "Show this message") do
52
+ puts opts
53
+ exit
54
+ end
55
+ end
56
+ opts.parse!(ARGV)
57
+
58
+ unless config.has_key?(:recipe) || config.has_key?(:directory)
59
+ puts "You must specify either a recipe (-r) or a directory (-d)"
60
+ puts opts
61
+ exit
62
+ end
63
+
64
+ if config.has_key?(:wait)
65
+ splay = rand(config[:wait])
66
+ sleep(splay)
67
+ end
68
+
69
+ agent = IClassify::Agent.new(config[:uuidfile], config[:server])
70
+ begin
71
+ agent.load
72
+ rescue SocketError
73
+ $stderr.puts("Error: Cannot connect to server.")
74
+ exit 1
75
+ end
76
+
77
+ if config.has_key?(:recipe)
78
+ agent.run_script(File.expand_path(config[:recipe]))
79
+ end
80
+ if config.has_key?(:directory)
81
+ Dir.glob(File.join(File.expand_path(config[:directory]), '*.rb')).sort.each do |file|
82
+ if File.file?(file)
83
+ agent.run_script(file)
84
+ end
85
+ end
86
+ end
87
+ if config.has_key?(:dryrun) && config[:dryrun]
88
+ puts agent.to_s
89
+ else
90
+ agent.update
91
+ end
data/bin/icsearch ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # iClassify - A node classification service.
4
+ # Copyright (C) 2007 HJK Solutions and Adam Jacob (<adam@hjksolutions.com>)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program; if not, write to the Free Software Foundation, Inc.,
18
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ #
20
+ # A very simple search utility for iclassify.
21
+ #
22
+
23
+ require 'rubygems'
24
+ require File.dirname(__FILE__) + '/../lib/iclassify'
25
+ require 'optparse'
26
+ require 'highline/import'
27
+
28
+ config = {
29
+ :server => 'https://iclassify',
30
+ :user => ENV.has_key?('USER') ? ENV['USER'] : 'puppet',
31
+ :only => nil,
32
+ :quiet => nil
33
+ }
34
+ opts = OptionParser.new do |opts|
35
+ opts.banner = "Usage: #{$0} (options) query"
36
+ opts.on("-a one,two,three", "--attrib one,two,three", Array, "Attributes to print") do |a|
37
+ config[:attribs] = a
38
+ end
39
+ opts.on("-t", "--tags", "Print tags or not, if attribs specified") do |t|
40
+ config[:tags] = t
41
+ end
42
+ opts.on("-u user", "--user user", "User to authenticate with, defaults to USER env variable") do |u|
43
+ config[:user] = u
44
+ end
45
+ opts.on("-p passwd", "--passwd passwd", "Password to authenticate with") do |p|
46
+ config[:passwd] = p
47
+ end
48
+ opts.on("-s server", "--server server", "iClassify Server URL") do |s|
49
+ config[:server] = s
50
+ end
51
+ opts.on("-o", "--only", "Print only the attributes specified on the command line") do |o|
52
+ config[:only] = o
53
+ end
54
+ opts.on("-q", "--quiet", "Do not print the header") do |q|
55
+ config[:quiet] = q
56
+ end
57
+ opts.on_tail("-h", "--help", "Show this message") do
58
+ puts opts
59
+ exit
60
+ end
61
+ end
62
+ args = ARGV
63
+ opts.parse!(args)
64
+
65
+ if args.length != 1
66
+ puts "You must specify a single query."
67
+ puts opts.help
68
+ exit 1
69
+ end
70
+
71
+ unless config[:passwd]
72
+ config[:passwd] = HighLine.ask("Password: ") { |q| q.echo = "*" }
73
+ end
74
+
75
+ unless config[:user] && config[:passwd]
76
+ puts "You must provide a username and password."
77
+ puts opts.help
78
+ exit 1
79
+ end
80
+
81
+ query = args[0]
82
+
83
+ client = IClassify::Client.new(config[:server], config[:user], config[:passwd])
84
+ begin
85
+ results = client.search(query, config[:attribs] ? config[:attribs] : [])
86
+ rescue SocketError
87
+ $stderr.puts("Error: Could not connect to server.")
88
+ exit 1
89
+ end
90
+
91
+ if config.has_key?(:attribs)
92
+ header = "# "
93
+ if config[:only]
94
+ header += "#{config[:attribs].join(',')}"
95
+ else
96
+ header += "description,uuid,#{config[:attribs].join(',')}"
97
+ end
98
+ header << ",tags" if config.has_key?(:tags)
99
+ puts header unless config[:quiet]
100
+ results.each do |node|
101
+ line = Array.new
102
+ line << "#{node.description}" unless config[:only]
103
+ line << "#{node.uuid}" unless config[:only]
104
+ config[:attribs].each do |attrib|
105
+ na = node.attribs.detect { |a| a[:name] == attrib }
106
+ if na
107
+ line << "#{na[:values].join(':')}"
108
+ else
109
+ line << ""
110
+ end
111
+ end
112
+ line << "\"#{node.tags.join(' ')}\"" if config.has_key?(:tags)
113
+ puts line.join(",")
114
+ end
115
+ else
116
+ results.each do |node|
117
+ puts "#\n# Node #{node.uuid}\n#"
118
+ puts node.to_s
119
+ end
120
+ end
data/bin/icwatcher ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # iClassify - A node classification service.
4
+ # Copyright (C) 2007 HJK Solutions and Adam Jacob (<adam@hjksolutions.com>)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program; if not, write to the Free Software Foundation, Inc.,
18
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ #
20
+ # Runs a command if the node has changed in iClassify
21
+ #
22
+
23
+ require 'rubygems'
24
+ require File.dirname(__FILE__) + '/../lib/iclassify'
25
+ require 'optparse'
26
+ require 'tempfile'
27
+ require 'open3'
28
+
29
+ config = {
30
+ :server => 'https://ops.onehub.com',
31
+ :uuidfile => File.dirname(__FILE__) + '/../icagent.uuid',
32
+ :tmpfile => File.join(Dir::tmpdir, "icwatcher.digest"),
33
+ }
34
+ verbose = false
35
+
36
+ args = ARGV
37
+ opts = OptionParser.new do |opts|
38
+ opts.banner = "Usage: #{$0} [-s server] -c command"
39
+ opts.on("-s SERVER", "--server", "iClassify Server URL") do |s|
40
+ config[:server] = s
41
+ end
42
+ opts.on("-u UUIDFILE", "--uuidfile UUIDFILE", "Path to the uuid file") do |u|
43
+ config[:uuidfile] = u
44
+ end
45
+ opts.on("-c COMMAND", "--command", "Command to run on changes") do |c|
46
+ config[:command] = c
47
+ end
48
+ opts.on("-t TMPFILE", "--tmpfile", "Where to store the digest between runs") do |t|
49
+ config[:tmpfile] = t
50
+ end
51
+ opts.on("-v", "--verbose", "Print the output of command") do
52
+ verbose = true
53
+ end
54
+ opts.on_tail("-h", "--help", "Show this message") do
55
+ puts opts
56
+ exit
57
+ end
58
+ end
59
+ opts.parse!(args)
60
+
61
+ unless config.has_key?(:command)
62
+ puts "You must supply a command!"
63
+ puts opts.help
64
+ exit 1
65
+ end
66
+
67
+ hostname = args[0]
68
+
69
+ agent = IClassify::Agent.new(config[:uuidfile], config[:server])
70
+ agent.load
71
+ digest = agent.node.digest
72
+
73
+ if FileTest.file?(config[:tmpfile])
74
+ last_digest = File.readlines(config[:tmpfile])
75
+ last_digest[0].chomp!
76
+ if digest == last_digest[0]
77
+ puts "Node has not changed." if verbose
78
+ exit 0
79
+ end
80
+ end
81
+
82
+ output = `#{config[:command]} 2>&1`
83
+ raise "#{config[:command]} failed: #{output}" unless $?.success?
84
+
85
+ if verbose
86
+ puts "Command: #{config[:command]}"
87
+ puts "---- OUTPUT ----"
88
+ puts output
89
+ end
90
+
91
+ File.open(config[:tmpfile], "w") do |tmp|
92
+ tmp.puts digest
93
+ end
94
+
95
+ exit 0
data/lib/iclassify.rb ADDED
@@ -0,0 +1,18 @@
1
+ # Author:: Adam Jacob (<adam@hjksolutions.com>)
2
+ # Copyright:: Copyright (c) 2007 HJK Solutions, LLC
3
+ # License:: GNU General Public License version 2.1
4
+ #
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License version 2.1
7
+ # as published by the Free Software Foundation.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License along
15
+ # with this program; if not, write to the Free Software Foundation, Inc.,
16
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
+
18
+ Dir[File.join(File.dirname(__FILE__), 'iclassify/**/*.rb')].sort.each { |lib| require lib }
@@ -0,0 +1,155 @@
1
+ require 'rubygems'
2
+ require 'uuidtools'
3
+
4
+ module IClassify
5
+ class Agent
6
+ attr_accessor :node
7
+ attr_accessor :uuid
8
+ attr_accessor :password
9
+
10
+ #
11
+ # Create a new Agent. Takes a path to a file to either read or drop
12
+ # a UUID, and a server URL.
13
+ #
14
+ def initialize(uuidfile="/etc/icagent/icagent.uuid", server_url="http://localhost:3000")
15
+ @uuid = nil
16
+ @password = nil
17
+ if File.exists?(uuidfile)
18
+ IO.foreach(uuidfile) do |line|
19
+ @uuid, @password = line.chomp.split("!")
20
+ end
21
+ unless @password
22
+ @password = random_password(30)
23
+ write_uuidfile(uuidfile)
24
+ end
25
+ else
26
+ @uuid = UUID.random_create
27
+ @password = random_password(30)
28
+ write_uuidfile(uuidfile)
29
+ end
30
+ @client = IClassify::Client.new(server_url, @uuid, @password)
31
+ end
32
+
33
+ #
34
+ # Loads data about this node from the iClassify service
35
+ #
36
+ def load
37
+ begin
38
+ @node = @client.get_node(@uuid)
39
+ rescue Net::HTTPServerException => e
40
+ if e.to_s =~ /^404/
41
+ @node = IClassify::Node.new()
42
+ @node.description = "New Node"
43
+ @node.tags << "unclassified"
44
+ @node.password = @password
45
+ @node.uuid = @uuid
46
+ else
47
+ throw(e)
48
+ end
49
+ end
50
+ end
51
+
52
+ #
53
+ # Updates this node in the iClassify service.
54
+ #
55
+ def update
56
+ if @node.description == "New Node"
57
+ hostname = attrib?("hostname")
58
+ hostname ||= "New Node"
59
+ @node.description = hostname
60
+ end
61
+ @client.update_node(@node)
62
+ end
63
+
64
+ #
65
+ # Deletes this node from the iClassify service.
66
+ #
67
+ def delete
68
+ @client.delete_node(@node)
69
+ end
70
+
71
+ #
72
+ # Returns the tag name if this node has that tag.
73
+ #
74
+ def tag?(tag)
75
+ @node.tag?(tag)
76
+ end
77
+
78
+ # Returns the values for this attribute, if it exists for this node. If
79
+ # there is only one, it will return it, if it's an array, you get the
80
+ # array. You have to check!
81
+ def attrib?(attrib)
82
+ @node.attrib?(attrib)
83
+ end
84
+
85
+ # Returns the current node as a string.
86
+ def to_s
87
+ @node.to_s
88
+ end
89
+
90
+ # Returns the value if the given attribute has a given attribute.
91
+ def attrib_has_value?(attrib, value)
92
+ na = @node.attribs.detect { |a| a[:name] == attrib }
93
+ if na
94
+ return na.values.detect { |v| v == value}
95
+ else
96
+ return nil
97
+ end
98
+ end
99
+
100
+ # Add a tag to this node.
101
+ def add_tag(tag)
102
+ load unless @node
103
+ @node.tags << tag
104
+ end
105
+
106
+ # Add an attribute to this node. Requires a name and either a string or
107
+ # array of values.
108
+ #
109
+ # Will be cumulative!
110
+ def add_attrib(name, values)
111
+ load unless @node
112
+ @node.attribs << { :name => name, :values => values.kind_of?(Array) ? values : [ values ] }
113
+ end
114
+
115
+ # Replace the attribute with the given name's values in place.
116
+ # Will add a new attribute if it needs to.
117
+ def replace_attrib(name, values)
118
+ exists = @node.attribs.detect { |a| a[:name] == name }
119
+ if exists
120
+ exists[:values] = values.kind_of?(Array) ? values : [ values ]
121
+ else
122
+ add_attrib(name, values)
123
+ end
124
+ end
125
+
126
+ # Set the description for the node
127
+ def description(value)
128
+ @node.description = value
129
+ end
130
+
131
+ # return the value of @node.description
132
+ def description?()
133
+ @node.description
134
+ end
135
+
136
+ # Run an iclassify script.
137
+ def run_script(scriptfile)
138
+ eval(IO.read(scriptfile))
139
+ end
140
+
141
+ protected
142
+ def random_password(len)
143
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
144
+ newpass = ""
145
+ 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
146
+ newpass
147
+ end
148
+
149
+ def write_uuidfile(uuidfile)
150
+ File.open(uuidfile, "w") do |file|
151
+ file.puts "#{@uuid}!#{@password}"
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,108 @@
1
+ require 'rubygems'
2
+ require 'net/https'
3
+ require 'rexml/document'
4
+ require 'uri'
5
+ require 'yaml'
6
+
7
+ module IClassify
8
+
9
+ class Client
10
+ UUID_REGEX = /^[[:xdigit:]]{8}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{12}$/
11
+
12
+ def initialize(service_url, username, password)
13
+ service_url = "#{service_url}/rest" unless service_url =~ /rest$/
14
+ @url = URI.parse(service_url)
15
+ @username = username
16
+ @password = password
17
+ end
18
+
19
+ def make_url(method, params)
20
+ params[:appid] = @appid
21
+ super method, params
22
+ end
23
+
24
+ def search(query, attribs=[])
25
+ raise ArgumentError, "Attributes must be given as a list!" unless attribs.kind_of?(Array)
26
+ querystring = "search"
27
+ querystring << "?q=#{URI.escape(query)}"
28
+ querystring << "&a=#{URI.escape(attribs.join(','))}" if attribs.length > 0
29
+ results = get_rest(querystring, "text/yaml")
30
+ node_array = YAML.load(results).collect { |n| IClassify::Node.new(:yaml, n) }
31
+ end
32
+
33
+ def get_node(node_id)
34
+ IClassify::Node.new(:xml, get_rest("nodes/#{node_id}"))
35
+ end
36
+
37
+ def update_node(node)
38
+ if node.node_id
39
+ put_rest("nodes/#{node.node_id}", node.to_xml)
40
+ else
41
+ post_rest("nodes", node.to_xml)
42
+ end
43
+ end
44
+
45
+ def delete_node(node)
46
+ delete_rest("nodes/#{node.node_id}")
47
+ end
48
+
49
+ private
50
+
51
+ def get_rest(path, accept="application/xml")
52
+ url = URI.parse("#{@url}/#{path}")
53
+ run_request(:GET, url, false, accept)
54
+ end
55
+
56
+ def delete_rest(path, accept="application/xml")
57
+ url = URI.parse("#{@url}/#{path}")
58
+ run_request(:DELETE, url, false, accept)
59
+ end
60
+
61
+ def post_rest(path, xml, accept="application/xml")
62
+ url = URI.parse("#{@url}/#{path}")
63
+ run_request(:POST, url, xml, accept)
64
+ end
65
+
66
+ def put_rest(path, xml, accept="application/xml")
67
+ url = URI.parse("#{@url}/#{path}")
68
+ run_request(:PUT, url, xml, accept)
69
+ end
70
+
71
+ def run_request(method, url, data=false, accept="application/xml")
72
+ http = Net::HTTP.new(url.host, url.port)
73
+ if url.scheme == "https"
74
+ http.use_ssl = true
75
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
76
+ end
77
+ http.read_timeout = 60
78
+ headers = {
79
+ 'Accept' => accept,
80
+ 'Content-Type' => accept
81
+ }
82
+ req = nil
83
+ case method
84
+ when :GET
85
+ req_path = "#{url.path}"
86
+ req_path << "?#{url.query}" if url.query
87
+ req = Net::HTTP::Get.new(req_path, headers)
88
+ when :POST
89
+ req = Net::HTTP::Post.new(url.path, headers)
90
+ req.body = data if data
91
+ when :PUT
92
+ req = Net::HTTP::Put.new(url.path, headers)
93
+ req.body = data if data
94
+ when :DELETE
95
+ req = Net::HTTP::Delete.new(url.path, headers)
96
+ end
97
+ req.basic_auth(@username, @password)
98
+ res = http.request(req)
99
+ case res
100
+ when Net::HTTPSuccess
101
+ res.body
102
+ else
103
+ res.error!
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,134 @@
1
+ require 'rubygems'
2
+ require 'rexml/document'
3
+ require 'builder'
4
+ require 'yaml'
5
+ require 'digest/sha1'
6
+
7
+ module IClassify
8
+ class Node
9
+ attr_accessor :tags, :uuid, :description, :notes, :attribs, :node_id, :password
10
+
11
+ def initialize(type=:xml, data=nil)
12
+ from_xml(data) if type == :xml && data
13
+ from_yaml(data) if type == :yaml && data
14
+ @tags ||= Array.new
15
+ @attribs ||= Array.new
16
+ @password = nil
17
+ end
18
+
19
+ def to_xml
20
+ xml = Builder::XmlMarkup.new
21
+ output = xml.node do
22
+ xml.id(@node_id) if @node_id
23
+ xml.uuid(@uuid)
24
+ xml.password(@password) if @password
25
+ xml.description(@description)
26
+ xml.notes(@notes)
27
+ xml.tags do
28
+ @tags.sort.each do |tag|
29
+ xml.tag(tag)
30
+ end
31
+ end
32
+ xml.attribs do
33
+ @attribs.sort{ |a,b| a[:name] <=> b[:name] }.each do |attrib|
34
+ xml.attrib do
35
+ xml.name(attrib[:name])
36
+ xml.values do
37
+ attrib[:values].each do |v|
38
+ xml.value(v)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ output
46
+ end
47
+
48
+ def digest
49
+ Digest::SHA1.hexdigest(to_s())
50
+ end
51
+
52
+ #
53
+ # Returns the tag name if this node has that tag.
54
+ #
55
+ def tag?(tag)
56
+ @tags.detect { |t| t == tag }
57
+ end
58
+
59
+ # Returns the values for this attribute, if it exists for this node. If
60
+ # there is only one, it will return it, if it's an array, you get the
61
+ # array. You have to check!
62
+ def attrib?(attrib)
63
+ na = @attribs.detect { |a| a[:name] == attrib }
64
+ return nil unless na
65
+ if na[:values].length > 1
66
+ return na[:values]
67
+ else
68
+ return na[:values][0]
69
+ end
70
+ end
71
+
72
+ def to_s(tags=nil,attribs=nil)
73
+ output = String.new
74
+ output << "uuid: #{@uuid}\n"
75
+ output << "node_id: #{@node_id}\n"
76
+ output << "notes: #{@notes}\n"
77
+ output << "description: #{@description}\n"
78
+ output << "tags: #{@tags.sort.join(' ')}\n"
79
+ output << "attribs:\n"
80
+ @attribs.sort{ |a,b| a[:name] <=> b[:name] }.each do |attrib|
81
+ output << " #{attrib[:name]}: #{attrib[:values].join(', ')}\n"
82
+ end
83
+ output
84
+ end
85
+
86
+ def to_puppet
87
+ output = Hash.new
88
+ output["classes"] = @tags
89
+ output["parameters"] = Hash.new
90
+ @attribs.each do |attrib|
91
+ if attrib[:values].length > 1
92
+ output["parameters"][attrib[:name]] = attrib[:values]
93
+ else
94
+ output["parameters"][attrib[:name]] = attrib[:values][0]
95
+ end
96
+ end
97
+ output.to_yaml
98
+ end
99
+
100
+ def from_xml(doc)
101
+ xml = nil
102
+ if doc.kind_of?(REXML::Element)
103
+ xml = doc
104
+ else
105
+ xml = REXML::Document.new(doc)
106
+ end
107
+ @tags = Array.new
108
+ xml.elements.each('//tag') { |t| @tags << t.text }
109
+ @uuid = xml.get_text('//uuid')
110
+ @node_id = xml.get_text('//id')
111
+ @description = xml.get_text('//description')
112
+ @notes = xml.get_text('//notes')
113
+ @attribs = Array.new
114
+ xml.elements.each('//attrib') do |attrib|
115
+ cattrib = Hash.new
116
+ cattrib[:name] = attrib.get_text('name').to_s
117
+ value_array = Array.new
118
+ attrib.elements.each('values/value') { |v| value_array << v.text }
119
+ cattrib[:values] = value_array
120
+ @attribs << cattrib
121
+ end
122
+ end
123
+
124
+ def from_yaml(data)
125
+ @tags = data[:tags].collect { |t| t[:name] }
126
+ @uuid = data[:uuid]
127
+ @description = data[:description]
128
+ @notes = data[:notes]
129
+ @attribs = data[:attribs].delete_if { |x| x[:name] == "text" }
130
+ @node_id = data[:id]
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # A simple icagent recipe. Takes all the facter facts and submits them to
3
+ # iClassify.
4
+ #
5
+
6
+ ENV['FACTERLIB'] = '/var/lib/puppet/lib/facter'
7
+ require 'rubygems'
8
+ require 'facter'
9
+
10
+ Facter.each do |name, value|
11
+ replace_attrib(name, value)
12
+ end
@@ -0,0 +1,5 @@
1
+ #
2
+ # Places each node in the "base" class.
3
+ #
4
+
5
+ add_tag("base") unless tag?("base")
@@ -0,0 +1,6 @@
1
+ # #
2
+ # # Apache should listen on 80, 443 by default.
3
+ # #
4
+ #
5
+ # add_attrib("apache_listen_ports", [ 80, 443 ]) unless attrib?("apache_listen_ports")
6
+ #
data/recipes/02_ec2.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'net/http'
2
+
3
+ ec2 = false
4
+ domain = attrib?('domain')
5
+ ec2 = true if domain =~ /(\.amazonaws.com|compute-1.internal)$/
6
+
7
+ if ec2
8
+ replace_attrib("ec2", "true")
9
+ else
10
+ replace_attrib("ec2", "false")
11
+ end
12
+
13
+ def get_from_ec2(thing="/")
14
+ base_url = "http://169.254.169.254/latest/meta-data" + thing
15
+ url = URI.parse(base_url)
16
+ req = Net::HTTP::Get.new(url.path)
17
+ res = Net::HTTP.start(url.host, url.port) {|http|
18
+ http.request(req)
19
+ }
20
+ res.body
21
+ end
22
+
23
+ if ec2
24
+ get_from_ec2.split("\n").each do |key|
25
+ add_attrib("ec2-#{key}", get_from_ec2("/#{key}"))
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # Configure how many mongrels a server should have
3
+ #
4
+
5
+ mongrel_size = 60
6
+ head_room = 1024
7
+
8
+ total_memory = attrib?("memorysize")
9
+ if total_memory
10
+ if total_memory =~ /MB$/
11
+ total_memory.gsub!(/ MB/, '')
12
+ total_memory = total_memory.to_f
13
+ else
14
+ total_memory.gsub!(/ GB/, '')
15
+ total_memory = total_memory.to_f * 1024
16
+ end
17
+ available_memory = total_memory - head_room
18
+ total_mongrels = available_memory / mongrel_size
19
+ add_attrib("mongrel_servers", total_mongrels.to_i) unless attrib?("mongrel_servers")
20
+ add_attrib("mongrel_port_number", 5000) unless attrib?("mongrel_port_number")
21
+ end
@@ -0,0 +1,17 @@
1
+ #
2
+ # Set up our puppet environment
3
+ #
4
+
5
+ unless attrib?("puppet_env")
6
+ hostname = attrib?("hostname")
7
+ fqdn = attrib?("fqdn")
8
+ if fqdn =~ /amazonaws.com$/
9
+ replace_attrib("puppet_env", "production")
10
+ else
11
+ if hostname =~ /^.+?\d+(.+)$/
12
+ replace_attrib("puppet_env", $1)
13
+ else
14
+ replace_attrib("puppet_env", "production")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ #
2
+ # How big a buffer pool size?
3
+ #
4
+
5
+ total_memory = attrib?("memorysize")
6
+ if total_memory
7
+ if total_memory =~ /MB$/
8
+ total_memory.gsub!(/ MB/, '')
9
+ total_memory = total_memory.to_f
10
+ else
11
+ total_memory.gsub!(/ GB/, '')
12
+ total_memory = total_memory.to_f * 1024
13
+ end
14
+ buffer_pool_size = total_memory * 0.75
15
+ buffer_pool_size = buffer_pool_size.to_i
16
+ add_attrib("innodb_buffer_pool_size", buffer_pool_size.to_s + "M") unless attrib?("innodb_buffer_pool_size")
17
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loe-icagent
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - W. Andrew Loe III
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: andrew@andrewloe.com
18
+ executables:
19
+ - icagent
20
+ - icsearch
21
+ - icwatcher
22
+ extensions: []
23
+
24
+ extra_rdoc_files:
25
+ - README
26
+ files:
27
+ - README
28
+ - VERSION
29
+ - bin/icagent
30
+ - bin/icsearch
31
+ - bin/icwatcher
32
+ - lib/iclassify.rb
33
+ - lib/iclassify/agent.rb
34
+ - lib/iclassify/client.rb
35
+ - lib/iclassify/node.rb
36
+ - recipes/00_facter.rb
37
+ - recipes/01_default_class.rb
38
+ - recipes/02_apache_server.rb
39
+ - recipes/02_ec2.rb
40
+ - recipes/02_mongrel_server.rb
41
+ - recipes/02_puppet_env.rb
42
+ - recipes/03_mysql_server.rb
43
+ has_rdoc: false
44
+ homepage: http://github.com/loe/icagent
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.2.0
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: TODO
69
+ test_files: []
70
+