loe-icagent 1.0.0

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