Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merging iclassify-interface and icagent.

  • Loading branch information...
commit 148daff9ee205c9f99073a6546a9dba8ad6f0beb 0 parents
@loe authored
2  .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+pkg
31 README
@@ -0,0 +1,31 @@
+= iclassify-interface
+
+http://github.com/loe/iclassify-interface
+
+== DESCRIPTION:
+
+Module for interfacing with iclassify.
+
+== INSTALL:
+
+sudo gem install loe-iclassify-interface
+
+== LICENSE:
+
+# Author:: Adam Jacob (<adam@hjksolutions.com>)
+# Mods:: W. Andrew Loe III (<andrew@andrewloe.com>)
+# Copyright:: Copyright (c) 2007 HJK Solutions, LLC
+# License:: GNU General Public License version 2.1
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2.1
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
60 Rakefile
@@ -0,0 +1,60 @@
+require 'rubygems'
+require 'rake'
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |gem|
+ gem.name = "iclassify-interface"
+ gem.summary = %Q{TODO}
+ gem.email = "andrew@andrewloe.com"
+ gem.homepage = "http://github.com/loe/iclassify-interface"
+ gem.authors = ["W. Andrew Loe III"]
+ gem.add_dependency("uuidtools", '1.0.7')
+ gem.add_dependency("rake", ">= 0.8.3")
+ gem.add_dependency("launchy")
+ gem.add_dependency("builder")
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
+ end
+
+rescue LoadError
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
+end
+
+require 'rake/testtask'
+Rake::TestTask.new(:test) do |test|
+ test.libs << 'lib' << 'test'
+ test.pattern = 'test/**/*_test.rb'
+ test.verbose = true
+end
+
+begin
+ require 'rcov/rcovtask'
+ Rcov::RcovTask.new do |test|
+ test.libs << 'test'
+ test.pattern = 'test/**/*_test.rb'
+ test.verbose = true
+ end
+rescue LoadError
+ task :rcov do
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
+ end
+end
+
+
+task :default => :test
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ if File.exist?('VERSION.yml')
+ config = YAML.load(File.read('VERSION.yml'))
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
+ else
+ version = ""
+ end
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "icagent2 #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
1  VERSION
@@ -0,0 +1 @@
+1.0.6
92 bin/icagent
@@ -0,0 +1,92 @@
+#!/usr/bin/env ruby
+#
+# iClassify - A node classification service.
+# Copyright (C) 2007 HJK Solutions and Adam Jacob (<adam@hjksolutions.com>)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# icagent registers a node with iclassify, and lets you use small DSL for
+# classifiying them.
+
+require 'rubygems'
+require File.dirname(__FILE__) + '/../lib/iclassify'
+require 'optparse'
+
+config = {
+ :uuidfile => '/etc/icagent/icagent.uuid',
+ :directory => File.dirname(__FILE__) + '/../recipes'
+}
+
+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("-n", "--no-action", "Don't update anything, just print.") do |n|
+ config[:dryrun] = true
+ end
+ opts.on("-w WAIT", "--wait TIME", "Wait for up to TIME seconds.") do |w|
+ config[:wait] = w.to_i
+ 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
+
+if config.has_key?(:wait)
+ splay = rand(config[:wait])
+ sleep(splay)
+end
+
+agent = IClassify::Agent.new(config[:uuidfile], config[:server])
+begin
+ agent.load
+rescue SocketError
+ $stderr.puts("Error: Cannot connect to server.")
+ exit 1
+end
+
+if config.has_key?(:recipe)
+ agent.run_script(File.expand_path(config[:recipe]))
+end
+if config.has_key?(:directory)
+ Dir.glob(File.join(File.expand_path(config[:directory]), '*.rb')).sort.each do |file|
+ if File.file?(file)
+ agent.run_script(file)
+ end
+ end
+end
+if config.has_key?(:dryrun) && config[:dryrun]
+ puts agent.to_s
+else
+ agent.update
+end
120 bin/icsearch
@@ -0,0 +1,120 @@
+#!/usr/bin/env ruby
+#
+# iClassify - A node classification service.
+# Copyright (C) 2007 HJK Solutions and Adam Jacob (<adam@hjksolutions.com>)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# A very simple search utility for iclassify.
+#
+
+require 'rubygems'
+require File.dirname(__FILE__) + '/../lib/iclassify'
+require 'optparse'
+require 'highline/import'
+
+config = {
+ :server => 'https://iclassify',
+ :user => ENV.has_key?('USER') ? ENV['USER'] : 'puppet',
+ :only => nil,
+ :quiet => nil
+}
+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("-u user", "--user user", "User to authenticate with, defaults to USER env variable") do |u|
+ config[:user] = u
+ end
+ opts.on("-p passwd", "--passwd passwd", "Password to authenticate with") do |p|
+ config[:passwd] = p
+ end
+ opts.on("-s server", "--server server", "iClassify Server URL") do |s|
+ config[:server] = s
+ end
+ opts.on("-o", "--only", "Print only the attributes specified on the command line") do |o|
+ config[:only] = o
+ end
+ opts.on("-q", "--quiet", "Do not print the header") do |q|
+ config[:quiet] = q
+ 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
+
+unless config[:passwd]
+ config[:passwd] = HighLine.ask("Password: ") { |q| q.echo = "*" }
+end
+
+unless config[:user] && config[:passwd]
+ puts "You must provide a username and password."
+ puts opts.help
+ exit 1
+end
+
+query = args[0]
+
+client = IClassify::Client.new(config[:server], config[:user], config[:passwd])
+begin
+ results = client.search(query, config[:attribs] ? config[:attribs] : [])
+rescue SocketError
+ $stderr.puts("Error: Could not connect to server.")
+ exit 1
+end
+
+if config.has_key?(:attribs)
+ header = "# "
+ if config[:only]
+ header += "#{config[:attribs].join(',')}"
+ else
+ header += "description,uuid,#{config[:attribs].join(',')}"
+ end
+ header << ",tags" if config.has_key?(:tags)
+ puts header unless config[:quiet]
+ results.each do |node|
+ line = Array.new
+ line << "#{node.description}" unless config[:only]
+ line << "#{node.uuid}" unless config[:only]
+ 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
94 bin/icwatcher
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+#
+# iClassify - A node classification service.
+# Copyright (C) 2007 HJK Solutions and Adam Jacob (<adam@hjksolutions.com>)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Runs a command if the node has changed in iClassify
+#
+
+require 'rubygems'
+require File.dirname(__FILE__) + '/../lib/iclassify'
+require 'optparse'
+require 'tempfile'
+require 'open3'
+
+config = {
+ :uuidfile => '/etc/icagent/icagent.uuid',
+ :tmpfile => File.join(Dir::tmpdir, "icwatcher.digest"),
+}
+verbose = false
+
+args = ARGV
+opts = OptionParser.new do |opts|
+ opts.banner = "Usage: #{$0} [-s server] -c command"
+ opts.on("-s SERVER", "--server", "iClassify Server URL") do |s|
+ config[:server] = s
+ end
+ opts.on("-u UUIDFILE", "--uuidfile UUIDFILE", "Path to the uuid file") do |u|
+ config[:uuidfile] = u
+ end
+ opts.on("-c COMMAND", "--command", "Command to run on changes") do |c|
+ config[:command] = c
+ end
+ opts.on("-t TMPFILE", "--tmpfile", "Where to store the digest between runs") do |t|
+ config[:tmpfile] = t
+ end
+ opts.on("-v", "--verbose", "Print the output of command") do
+ verbose = true
+ end
+ opts.on_tail("-h", "--help", "Show this message") do
+ puts opts
+ exit
+ end
+end
+opts.parse!(args)
+
+unless config.has_key?(:command)
+ puts "You must supply a command!"
+ puts opts.help
+ exit 1
+end
+
+hostname = args[0]
+
+agent = IClassify::Agent.new(config[:uuidfile], config[:server])
+agent.load
+digest = agent.node.digest
+
+if FileTest.file?(config[:tmpfile])
+ last_digest = File.readlines(config[:tmpfile])
+ last_digest[0].chomp!
+ if digest == last_digest[0]
+ puts "Node has not changed." if verbose
+ exit 0
+ end
+end
+
+output = `#{config[:command]} 2>&1`
+raise "#{config[:command]} failed: #{output}" unless $?.success?
+
+if verbose
+ puts "Command: #{config[:command]}"
+ puts "---- OUTPUT ----"
+ puts output
+end
+
+File.open(config[:tmpfile], "w") do |tmp|
+ tmp.puts digest
+end
+
+exit 0
57 iclassify-interface.gemspec
@@ -0,0 +1,57 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{iclassify-interface}
+ s.version = "1.0.6"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["W. Andrew Loe III"]
+ s.date = %q{2009-07-23}
+ s.email = %q{andrew@andrewloe.com}
+ s.executables = ["icagent", "icsearch", "icwatcher"]
+ s.extra_rdoc_files = [
+ "README"
+ ]
+ s.files = [
+ ".gitignore",
+ "README",
+ "Rakefile",
+ "VERSION",
+ "bin/icagent",
+ "bin/icsearch",
+ "bin/icwatcher",
+ "iclassify-interface.gemspec",
+ "lib/.DS_Store",
+ "lib/iclassify-interface.rb",
+ "lib/iclassify-interface/agent.rb",
+ "lib/iclassify-interface/client.rb",
+ "lib/iclassify-interface/node.rb"
+ ]
+ s.homepage = %q{http://github.com/loe/iclassify-interface}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.4}
+ s.summary = %q{TODO}
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<uuidtools>, ["= 1.0.7"])
+ s.add_runtime_dependency(%q<rake>, [">= 0.8.3"])
+ s.add_runtime_dependency(%q<launchy>, [">= 0"])
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
+ else
+ s.add_dependency(%q<uuidtools>, ["= 1.0.7"])
+ s.add_dependency(%q<rake>, [">= 0.8.3"])
+ s.add_dependency(%q<launchy>, [">= 0"])
+ s.add_dependency(%q<builder>, [">= 0"])
+ end
+ else
+ s.add_dependency(%q<uuidtools>, ["= 1.0.7"])
+ s.add_dependency(%q<rake>, [">= 0.8.3"])
+ s.add_dependency(%q<launchy>, [">= 0"])
+ s.add_dependency(%q<builder>, [">= 0"])
+ end
+end
4 lib/iclassify-interface.rb
@@ -0,0 +1,4 @@
+require 'iclassify-interface/agent'
+require 'iclassify-interface/client'
+require 'iclassify-interface/node'
+require 'iclassify-interface/version'
155 lib/iclassify-interface/agent.rb
@@ -0,0 +1,155 @@
+require 'rubygems'
+require 'uuidtools'
+
+module IClassify
+ class Agent
+ attr_accessor :node
+ attr_accessor :uuid
+ attr_accessor :password
+
+ #
+ # 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")
+ @uuid = nil
+ @password = nil
+ if File.exists?(uuidfile)
+ IO.foreach(uuidfile) do |line|
+ @uuid, @password = line.chomp.split("!")
+ end
+ unless @password
+ @password = random_password(30)
+ write_uuidfile(uuidfile)
+ end
+ else
+ @uuid = UUID.random_create
+ @password = random_password(30)
+ write_uuidfile(uuidfile)
+ end
+ @client = IClassify::Client.new(server_url, @uuid, @password)
+ end
+
+ #
+ # Loads data about this node from the iClassify service
+ #
+ def load
+ begin
+ @node = @client.get_node(@uuid)
+ rescue Net::HTTPServerException => e
+ if e.to_s =~ /^404/
+ @node = IClassify::Node.new()
+ @node.description = "New Node"
+ @node.tags << "unclassified"
+ @node.password = @password
+ @node.uuid = @uuid
+ else
+ throw(e)
+ end
+ end
+ end
+
+ #
+ # Updates this node in the iClassify service.
+ #
+ def update
+ if @node.description == "New Node"
+ hostname = attrib?("hostname")
+ hostname ||= "New Node"
+ @node.description = hostname
+ end
+ @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.tag?(tag)
+ end
+
+ # Returns the values for this attribute, if it exists for this node. If
+ # there is only one, it will return it, if it's an array, you get the
+ # array. You have to check!
+ def attrib?(attrib)
+ @node.attrib?(attrib)
+ end
+
+ # Returns the current node as a string.
+ def to_s
+ @node.to_s
+ 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 either a string or
+ # array of values.
+ #
+ # Will be cumulative!
+ def add_attrib(name, values)
+ load unless @node
+ @node.attribs << { :name => name, :values => values.kind_of?(Array) ? values : [ values ] }
+ end
+
+ # Replace the attribute with the given name's values in place.
+ # Will add a new attribute if it needs to.
+ def replace_attrib(name, values)
+ exists = @node.attribs.detect { |a| a[:name] == name }
+ if exists
+ exists[:values] = values.kind_of?(Array) ? values : [ values ]
+ else
+ add_attrib(name, values)
+ end
+ end
+
+ # Set the description for the node
+ def description(value)
+ @node.description = value
+ end
+
+ # return the value of @node.description
+ def description?()
+ @node.description
+ end
+
+ # Run an iclassify script.
+ def run_script(scriptfile)
+ eval(IO.read(scriptfile))
+ end
+
+ protected
+ def random_password(len)
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
+ newpass = ""
+ 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
+ newpass
+ end
+
+ def write_uuidfile(uuidfile)
+ File.open(uuidfile, "w") do |file|
+ file.puts "#{@uuid}!#{@password}"
+ end
+ end
+ end
+end
108 lib/iclassify-interface/client.rb
@@ -0,0 +1,108 @@
+require 'rubygems'
+require 'net/https'
+require 'rexml/document'
+require 'uri'
+require 'yaml'
+
+module IClassify
+
+ class Client
+ UUID_REGEX = /^[[:xdigit:]]{8}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{12}$/
+
+ def initialize(service_url, username, password)
+ service_url = "#{service_url}/rest" unless service_url =~ /rest$/
+ @url = URI.parse(service_url)
+ @username = username
+ @password = password
+ end
+
+ def make_url(method, params)
+ params[:appid] = @appid
+ super method, params
+ end
+
+ def search(query, attribs=[])
+ raise ArgumentError, "Attributes must be given as a list!" unless attribs.kind_of?(Array)
+ querystring = "search"
+ querystring << "?q=#{URI.escape(query)}"
+ querystring << "&a=#{URI.escape(attribs.join(','))}" if attribs.length > 0
+ results = get_rest(querystring, "text/yaml")
+ node_array = YAML.load(results).collect { |n| IClassify::Node.new(:yaml, n) }
+ end
+
+ def get_node(node_id)
+ IClassify::Node.new(:xml, get_rest("nodes/#{node_id}"))
+ end
+
+ def update_node(node)
+ if node.node_id
+ put_rest("nodes/#{node.node_id}", node.to_xml)
+ else
+ post_rest("nodes", node.to_xml)
+ end
+ end
+
+ def delete_node(node)
+ delete_rest("nodes/#{node.node_id}")
+ end
+
+ private
+
+ def get_rest(path, accept="application/xml")
+ url = URI.parse("#{@url}/#{path}")
+ run_request(:GET, url, false, accept)
+ end
+
+ def delete_rest(path, accept="application/xml")
+ url = URI.parse("#{@url}/#{path}")
+ run_request(:DELETE, url, false, accept)
+ end
+
+ def post_rest(path, xml, accept="application/xml")
+ url = URI.parse("#{@url}/#{path}")
+ run_request(:POST, url, xml, accept)
+ end
+
+ def put_rest(path, xml, accept="application/xml")
+ url = URI.parse("#{@url}/#{path}")
+ run_request(:PUT, url, xml, accept)
+ end
+
+ def run_request(method, url, data=false, accept="application/xml")
+ http = Net::HTTP.new(url.host, url.port)
+ if url.scheme == "https"
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+ http.read_timeout = 60
+ headers = {
+ 'Accept' => accept,
+ 'Content-Type' => accept
+ }
+ req = nil
+ case method
+ when :GET
+ req_path = "#{url.path}"
+ req_path << "?#{url.query}" if url.query
+ req = Net::HTTP::Get.new(req_path, headers)
+ when :POST
+ req = Net::HTTP::Post.new(url.path, headers)
+ req.body = data if data
+ when :PUT
+ req = Net::HTTP::Put.new(url.path, headers)
+ req.body = data if data
+ when :DELETE
+ req = Net::HTTP::Delete.new(url.path, headers)
+ end
+ req.basic_auth(@username, @password)
+ res = http.request(req)
+ case res
+ when Net::HTTPSuccess
+ res.body
+ else
+ res.error!
+ end
+ end
+
+ end
+end
134 lib/iclassify-interface/node.rb
@@ -0,0 +1,134 @@
+require 'rubygems'
+require 'rexml/document'
+require 'builder'
+require 'yaml'
+require 'digest/sha1'
+
+module IClassify
+ class Node
+ attr_accessor :tags, :uuid, :description, :notes, :attribs, :node_id, :password
+
+ def initialize(type=:xml, data=nil)
+ from_xml(data) if type == :xml && data
+ from_yaml(data) if type == :yaml && data
+ @tags ||= Array.new
+ @attribs ||= Array.new
+ @password = nil
+ end
+
+ def to_xml
+ xml = Builder::XmlMarkup.new
+ output = xml.node do
+ xml.id(@node_id) if @node_id
+ xml.uuid(@uuid)
+ xml.password(@password) if @password
+ xml.description(@description)
+ xml.notes(@notes)
+ xml.tags do
+ @tags.sort.each do |tag|
+ xml.tag(tag)
+ end
+ end
+ xml.attribs do
+ @attribs.sort{ |a,b| a[:name] <=> b[:name] }.each do |attrib|
+ xml.attrib do
+ xml.name(attrib[:name])
+ xml.values do
+ attrib[:values].each do |v|
+ xml.value(v)
+ end
+ end
+ end
+ end
+ end
+ end
+ output
+ end
+
+ def digest
+ Digest::SHA1.hexdigest(to_s())
+ end
+
+ #
+ # Returns the tag name if this node has that tag.
+ #
+ def tag?(tag)
+ @tags.detect { |t| t == tag }
+ end
+
+ # Returns the values for this attribute, if it exists for this node. If
+ # there is only one, it will return it, if it's an array, you get the
+ # array. You have to check!
+ def attrib?(attrib)
+ na = @attribs.detect { |a| a[:name] == attrib }
+ return nil unless na
+ if na[:values].length > 1
+ return na[:values]
+ else
+ return na[:values][0]
+ end
+ end
+
+ def to_s(tags=nil,attribs=[])
+ output = String.new
+ output << "uuid: #{@uuid}\n"
+ output << "node_id: #{@node_id}\n"
+ output << "notes: #{@notes}\n"
+ output << "description: #{@description}\n"
+ output << "tags: #{@tags.sort.join(' ')}\n"
+ output << "attribs:\n"
+ @attribs.select{ |attrib| attribs.include?(attrib[:name].to_sym) }.sort{ |a,b| a[:name] <=> b[:name] }.each do |attrib|
+ output << " #{attrib[:name]}: #{attrib[:values].join(', ')}\n"
+ end
+ output
+ end
+
+ def to_puppet
+ output = Hash.new
+ output["classes"] = @tags
+ output["parameters"] = Hash.new
+ @attribs.each do |attrib|
+ if attrib[:values].length > 1
+ output["parameters"][attrib[:name]] = attrib[:values]
+ else
+ output["parameters"][attrib[:name]] = attrib[:values][0]
+ end
+ end
+ output.to_yaml
+ end
+
+ def from_xml(doc)
+ xml = nil
+ if doc.kind_of?(REXML::Element)
+ xml = doc
+ else
+ xml = REXML::Document.new(doc)
+ end
+ @tags = Array.new
+ xml.elements.each('//tag') { |t| @tags << t.text }
+ @uuid = xml.get_text('//uuid')
+ @node_id = xml.get_text('//id')
+ @description = xml.get_text('//description')
+ @notes = xml.get_text('//notes')
+ @attribs = Array.new
+ xml.elements.each('//attrib') do |attrib|
+ cattrib = Hash.new
+ cattrib[:name] = attrib.get_text('name').to_s
+ value_array = Array.new
+ attrib.elements.each('values/value') { |v| value_array << v.text }
+ cattrib[:values] = value_array
+ @attribs << cattrib
+ end
+ end
+
+ def from_yaml(data)
+ @tags = data[:tags].collect { |t| t[:name] }
+ @uuid = data[:uuid]
+ @description = data[:description]
+ @notes = data[:notes]
+ @attribs = data[:attribs].delete_if { |x| x[:name] == "text" }
+ @node_id = data[:id]
+ end
+
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.