Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed up the agent, added a search script

  • Loading branch information...
commit e7436ef9d45d830aec3cab225e0848cc90ace753 1 parent 46d80e9
@adamhjk authored
View
5 app/controllers/nodes_controller.rb
@@ -96,8 +96,6 @@ def update_uuid
end
end
-
-
private
def populate_tags_and_attribs(params=nil)
@@ -109,7 +107,8 @@ def populate_tags_and_attribs(params=nil)
end
if params[:node].has_key?(:attribs)
ahash = params[:node].delete(:attribs)
- attribs = ahash[:attrib]
+ attribs = [ ahash[:attrib] ]
+ attribs.flatten!
end
logger.debug("Attribs: #{attribs.to_yaml}")
return tags, attribs
View
15 app/models/attrib.rb
@@ -14,9 +14,16 @@ def self.get_all_names
def self.create_missing_attribs(node, attribs, options=Hash.new)
attrib_array = Array.new
- attribs.each do |attrib_hash|
- attrib = Attrib.find(:first, :conditions => [ "node_id = ? and name = ?", node.id, attrib_hash['name'] ])
- unless attrib
+ attribs.each do |attrib_hash|
+ attrib = nil
+ if node.id
+ attrib = Attrib.find(:first, :conditions => [ "node_id = ? and name = ?", node.id, attrib_hash['name'] ])
+ unless attrib
+ attrib = node.attribs.new(
+ :name => attrib_hash['name']
+ )
+ end
+ else
attrib = node.attribs.new(
:name => attrib_hash['name']
)
@@ -34,7 +41,7 @@ def self.create_missing_attribs(node, attribs, options=Hash.new)
av.destroy unless attrib_hash['values']['value'].include?(av.value)
end
end
- logger.debug("My doobie: #{attrib.to_yaml}")
+ logger.debug(" #{attrib.to_yaml}")
attrib_array << attrib
end
attrib_array
View
2  app/views/search/index.rxml
@@ -3,6 +3,6 @@ xml.search do
@nodes.collect { |n| n.rest_serialize }.each do |node|
render :partial => "nodes/node",
:locals => { :xml_instance => xml, :node => node }
- end
+ end if @nodes
end
end
View
47 bin/icagent
@@ -5,13 +5,50 @@
require 'rubygems'
require File.dirname(__FILE__) + '/../lib/iclassify/agent'
+require 'optparse'
-agent = IClassify::Agent.new(File.dirname(__FILE__) + '/../icagent.uuid')
+config = {
+ :uuidfile => File.dirname(__FILE__) + '/../icagent.uuid',
+ :server => 'http://localhost:3000'
+}
+opts = OptionParser.new do |opts|
+ opts.banner = "Usage: #{$0} [-d DIR|-r FILE] (options)"
+ opts.on("-d DIRECTORY", "--directory DIRECTORY", "Path to icagent recipes") do |d|
+ config[:directory] = d
+ end
+ opts.on("-r RECIPE", "--recipe RECIPE", "Path to a single icagent recipe") do |r|
+ config[:recipe] = r
+ end
+ opts.on("-u UUIDFILE", "--uuidfile UUIDFILE", "Path to the uuid file") do |u|
+ config[:uuidfile] = u
+ end
+ opts.on("-s SERVER", "--server", "iClassify Server URL") do |s|
+ config[:server] = s
+ end
+ opts.on_tail("-h", "--help", "Show this message") do
+ puts opts
+ exit
+ end
+end
+opts.parse!(ARGV)
+
+unless config.has_key?(:recipe) || config.has_key?(:directory)
+ puts "You must specify either a recipe (-r) or a directory (-d)"
+ puts opts
+ exit
+end
+
+agent = IClassify::Agent.new(config[:uuidfile], config[:server])
agent.load
-agent.merge_facter
-ARGV.each do |f|
- if File.exists?(f)
- agent.run_script(f)
+if config.has_key?(:recipe)
+ agent.run_script(File.expand_path(f))
+end
+if config.has_key?(:directory)
+ Dir.foreach(config[:directory]) do |f|
+ file = File.expand_path(File.join(config[:directory], f))
+ if File.file?(file) && file !~ /^\./
+ agent.run_script(file)
+ end
end
end
agent.update
View
65 bin/icsearch
@@ -0,0 +1,65 @@
+#!/usr/bin/env ruby
+#
+# A very simple search utility for iclassify.
+#
+
+require 'rubygems'
+require File.dirname(__FILE__) + '/../lib/iclassify/client'
+require 'optparse'
+
+config = {
+ :server => 'http://localhost:3000'
+}
+opts = OptionParser.new do |opts|
+ opts.banner = "Usage: #{$0} (options) query"
+ opts.on("-a one,two,three", "--attrib one,two,three", Array, "Attributes to print") do |a|
+ config[:attribs] = a
+ end
+ opts.on("-t", "--tags", "Print tags or not, if attribs specified") do |t|
+ config[:tags] = t
+ end
+ opts.on("-s server", "--server server", "iClassify Server URL") do |s|
+ config[:server] = s
+ end
+ opts.on_tail("-h", "--help", "Show this message") do
+ puts opts
+ exit
+ end
+end
+args = ARGV
+opts.parse!(args)
+
+if args.length != 1
+ puts "You must specify a single query."
+ puts opts.help
+ exit 1
+end
+
+query = args[0]
+
+client = IClassify::Client.new(config[:server])
+results = client.search(query)
+if config.has_key?(:attribs)
+ header = "# uuid,#{config[:attribs].join(',')}"
+ header << ",tags" if config.has_key?(:tags)
+ puts header
+ results.each do |node|
+ line = [ "#{node.uuid}" ]
+ config[:attribs].each do |attrib|
+ na = node.attribs.detect { |a| a[:name] == attrib }
+ if na
+ line << "#{na[:values].join(':')}"
+ else
+ line << ""
+ end
+ end
+ line << "\"#{node.tags.join(' ')}\"" if config.has_key?(:tags)
+ puts line.join(",")
+ end
+
+else
+ results.each do |node|
+ puts "#\n# Node #{node.uuid}\n#"
+ puts node.to_s
+ end
+end
View
13 doc/README_FOR_APP
@@ -1,2 +1,11 @@
-Use this README file to introduce your application and point to useful places in the API for learning more.
-Run "rake appdoc" to generate API documentation for your models and controllers.
+To test:
+
+Get your database installed, call it iclassify_development
+
+Give it proper privileges, and edit database.yml
+
+Run rake db:migrate
+
+Run ./script/server
+
+Run ./bin/icagent
View
15 icagent/00_facter.rb
@@ -0,0 +1,15 @@
+#
+# Load all the facter facts
+#
+
+require 'rubygems'
+require 'facter'
+
+Facter.each do |name, value|
+ exists = @node.attribs.detect { |a| a[:name] == name }
+ if exists
+ exists[:values] = [ value ]
+ else
+ add_attrib(name, [ value ])
+ end
+end
View
7 icagent/01_has_textmate.rb
@@ -0,0 +1,7 @@
+#
+# The worlds simplest of Ruby DSL's. Basically, this evals in the
+# context of an instance of IClassify::Agent, who has already had
+# the Node data loaded from the server.
+#
+
+add_tag('textmate') if File.exists?('/Applications/TextMate.app')
View
12 icagent/02_tag_from_hostname.rb
@@ -0,0 +1,12 @@
+#
+# Set a tag based on the servers "group", which is pretty arbirtrary, but
+# a fine example of why this is really cool.
+#
+hostname = attrib?("hostname")
+if hostname
+ if hostname[0] =~ /^(.+?)\d+$/
+ add_tag("#{$1}_server")
+ else
+ add_tag("#{hostname[0]}_server")
+ end
+end
View
58 lib/iclassify/agent.rb
@@ -1,5 +1,4 @@
require 'rubygems'
-require 'facter'
require 'uuid'
require File.dirname(__FILE__) + '/client'
require File.dirname(__FILE__) + '/node'
@@ -8,11 +7,13 @@ module IClassify
class Agent
attr_accessor :node
attr_accessor :uuid
- attr_reader :server
+ #
+ # Create a new Agent. Takes a path to a file to either read or drop
+ # a UUID, and a server URL.
+ #
def initialize(uuidfile="/etc/icagent/icagent.uuid", server_url="http://localhost:3000")
- @server = URI.parse(server_url)
- @client = IClassify::Client.new(@server)
+ @client = IClassify::Client.new(server_url)
if File.exists?(uuidfile)
IO.foreach(uuidfile) do |line|
@uuid = line.chomp!
@@ -25,18 +26,9 @@ def initialize(uuidfile="/etc/icagent/icagent.uuid", server_url="http://localhos
end
end
- def merge_facter
- Facter.each do |name, value|
- exists = @node.attribs.detect { |a| a[:name] = name }
- if exists
- exists[:values] = [ value ]
- else
- @node.attribs << { :name => name, :values => [ value ]}
- end
- end
- @node.attribs
- end
-
+ #
+ # Loads data about this node from the iClassify service
+ #
def load
begin
@node = @client.get_node(@uuid)
@@ -48,23 +40,57 @@ def load
end
end
+ #
+ # Updates this node in the iClassify service.
+ #
def update
@client.update_node(@node)
end
+ #
+ # Deletes this node from the iClassify service.
+ #
def delete
@client.delete_node(@node)
end
+ #
+ # Returns the tag name if this node has that tag.
+ #
+ def tag?(tag)
+ @node.tags.detect { |t| t == tag }
+ end
+
+ # Returns the values for this attribute, if it exists for this node.
+ def attrib?(attrib)
+ na = @node.attribs.detect { |a| a[:name] == attrib }
+ na.values
+ end
+
+ # Returns the value if the given attribute has a given attribute.
+ def attrib_has_value?(attrib, value)
+ na = @node.attribs.detect { |a| a[:name] == attrib }
+ if na
+ return na.values.detect { |v| v == value}
+ else
+ return nil
+ end
+ end
+
+ # Add a tag to this node.
def add_tag(tag)
load unless @node
@node.tags << tag
end
+ # Add an attribute to this node. Requires a name and an array of
+ # values.
def add_attrib(name, values)
+ load unless @node
@node.attribs << { :name => name, :values => values }
end
+ # Run an iclassify script.
def run_script(scriptfile)
eval(IO.read(scriptfile))
end
View
14 lib/iclassify/client.rb
@@ -10,7 +10,7 @@ class Client
UUID_REGEX = /^[[:xdigit:]]{8}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{12}$/
def initialize(service_url)
- @url = service_url
+ @url = URI.parse(service_url)
end
def make_url(method, params)
@@ -19,7 +19,7 @@ def make_url(method, params)
end
def search(query)
- get "search.xml", :q => query
+ IClassify::Node.from_search(post_rest("search", "<q>#{query}</q>"))
end
def get_node(node_id)
@@ -40,9 +40,9 @@ def delete_node(node)
private
- def get_rest(path)
+ def get_rest(path, args=false)
url = URI.parse("#{@url}/#{path}")
- run_request(:get, url)
+ run_request(:get, url, args)
end
def delete_rest(path)
@@ -62,7 +62,11 @@ def put_rest(path, xml)
def run_request(method, url, data=false)
http = Net::HTTP.new(url.host, url.port)
- res = http.send_request(method, url.path, data, { 'Content-Type' => 'application/xml', 'Accept' => 'application/xml' })
+ headers = {
+ 'Accept' => 'application/xml',
+ 'Content-Type' => 'application/xml'
+ }
+ res = http.send_request(method, url.path, data, headers)
case res
when Net::HTTPSuccess
res.body
View
32 lib/iclassify/node.rb
@@ -11,6 +11,15 @@ def initialize(xml=nil)
@tags ||= Array.new
@attribs ||= Array.new
end
+
+ def self.from_search(doc)
+ xml = REXML::Document.new(doc)
+ node_array = Array.new
+ xml.elements.each("//node") do |node|
+ node_array << Node.new(node)
+ end
+ node_array
+ end
def to_xml
xml = Builder::XmlMarkup.new
@@ -39,9 +48,28 @@ def to_xml
end
output
end
+
+ def to_s(tags=nil,attribs=nil)
+ output = String.new
+ output << "uuid: #{@uuid}\n"
+ output << "node_id: #{@node_id}\n"
+ output << "notes: #{@notes}\n"
+ output << "description: #{@description}\n"
+ output << "tags: #{@tags.join(' ')}\n"
+ output << "attribs:\n"
+ @attribs.each do |attrib|
+ output << " #{attrib[:name]}: #{attrib[:values].join(', ')}\n"
+ end
+ output
+ end
def from_xml(doc)
- xml = REXML::Document.new(doc)
+ xml = nil
+ if doc.kind_of?(REXML::Element)
+ xml = doc
+ else
+ xml = REXML::Document.new(doc)
+ end
@tags = xml.elements.collect('//tag') { |t| t.text }
@uuid = xml.get_text('//uuid')
@node_id = xml.get_text('//id')
@@ -55,6 +83,6 @@ def from_xml(doc)
@attribs << cattrib
end
end
-
+
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.