diff options
author | Adam Jacob <adam@hjksolutions.com> | 2008-04-08 00:57:17 -0700 |
---|---|---|
committer | Adam Jacob <adam@hjksolutions.com> | 2008-04-08 00:57:17 -0700 |
commit | 95eb1375f0647accd1b1a1569a7d0e3acc4a61e4 (patch) | |
tree | a58d6fddde4d7818dc33511ff8275c7b9f69f1c6 /lib/chef | |
parent | 434f25ba07b5c0c50baa1e15b14a945bba3c3c3b (diff) | |
download | chef-95eb1375f0647accd1b1a1569a7d0e3acc4a61e4.tar.gz |
Adding chef-solo command, config examples, Chef::Log class, Chef::Log::Formatter, Chef::Compile, and all the tests
Diffstat (limited to 'lib/chef')
-rw-r--r-- | lib/chef/compile.rb | 62 | ||||
-rw-r--r-- | lib/chef/config.rb | 5 | ||||
-rw-r--r-- | lib/chef/cookbook.rb | 6 | ||||
-rw-r--r-- | lib/chef/log.rb | 93 | ||||
-rw-r--r-- | lib/chef/log/formatter.rb | 52 | ||||
-rw-r--r-- | lib/chef/node.rb | 62 | ||||
-rw-r--r-- | lib/chef/recipe.rb | 1 | ||||
-rw-r--r-- | lib/chef/resource_collection.rb | 3 |
8 files changed, 282 insertions, 2 deletions
diff --git a/lib/chef/compile.rb b/lib/chef/compile.rb new file mode 100644 index 0000000000..5b1f9d756e --- /dev/null +++ b/lib/chef/compile.rb @@ -0,0 +1,62 @@ +# +# Chef::Compile +# +# Compile a nodes resources. +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Chef + class Compile + + attr_accessor :node, :cookbook_loader, :resource_collection, :definitions + + def initialize() + @node = nil + @cookbook_loader = Chef::CookbookLoader.new + @resource_collection = Chef::ResourceCollection.new + @definitions = Hash.new + end + + def load_node(name) + @node = Chef::Node.find(name) + end + + def load_definitions() + @cookbook_loader.each do |cookbook| + hash = cookbook.load_definitions + @definitions.merge!(hash) + end + end + + def load_recipes + @node.recipes.each do |recipe| + rmatch = recipe.match(/(.+?)::(.+)/) + if rmatch + cookbook = @cookbook_loader[rmatch[1]] + cookbook.load_recipe(rmatch[2], @node, @resource_collection, @definitions, @cookbook_loader) + else + cookbook = @cookbook_loader[recipe] + cookbook.load_recipe("default", @node, @resource_collection, @definitions, @cookbook_loader) + end + end + end + + end +end
\ No newline at end of file diff --git a/lib/chef/config.rb b/lib/chef/config.rb index 191de2504c..4793011fb4 100644 --- a/lib/chef/config.rb +++ b/lib/chef/config.rb @@ -37,7 +37,10 @@ class Chef include Chef::Mixin::CheckHelper @configuration = { - :cookbook_path => [ "/etc/chef/site-cookbook", "/etc/chef/cookbook" ] + :cookbook_path => [ "/etc/chef/site-cookbook", "/etc/chef/cookbook" ], + :node_path => "/etc/chef/node", + :log_level => :info, + :log_location => STDOUT } class << self diff --git a/lib/chef/cookbook.rb b/lib/chef/cookbook.rb index 218ecb3c10..39013069ca 100644 --- a/lib/chef/cookbook.rb +++ b/lib/chef/cookbook.rb @@ -30,6 +30,7 @@ class Chef @definition_files = Array.new @recipe_files = Array.new @recipe_names = Hash.new + @loaded_attributes = false end def load_attributes(node) @@ -39,6 +40,7 @@ class Chef @attribute_files.each do |file| node.from_file(file) end + @loaded_atributes = true node end @@ -95,6 +97,10 @@ class Chef unless @recipe_names.has_key?(recipe_name) raise ArgumentError, "Cannot find a recipe matching #{recipe_name} in cookbook #{@name}" end + Chef::Log.debug("Found recipe #{recipe_name} in cookbook #{cookbook_name}") if Chef::Log.debug? + unless @loaded_attributes + load_attributes(node) + end recipe = Chef::Recipe.new(cookbook_name, recipe_name, node, collection, definitions, cookbook_loader) recipe.from_file(@recipe_files[@recipe_names[recipe_name]]) diff --git a/lib/chef/log.rb b/lib/chef/log.rb new file mode 100644 index 0000000000..cf8b0b45e9 --- /dev/null +++ b/lib/chef/log.rb @@ -0,0 +1,93 @@ +# +# Chef::Logger +# +# A simple wrapper for the standard Ruby Logger. +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'logger' + +class Chef + class Log + + @logger = nil + + class << self + attr_reader :logger #:nodoc + + # Use Chef::Logger.init when you want to set up the logger manually. Arguments to this method + # get passed directly to Logger.new, so check out the documentation for the standard Logger class + # to understand what to do here. + # + # If this method is called with no arguments, it will log to STDOUT at the :info level. + # + # It also configures the Logger instance it creates to use the custom Chef::Log::Formatter class. + def init(*opts) + if opts.length == 0 + @logger = Logger.new(STDOUT) + else + @logger = Logger.new(*opts) + end + @logger.formatter = Chef::Log::Formatter.new() + level(Chef::Config.log_level) + end + + # Sets the level for the Logger object by symbol. Valid arguments are: + # + # :debug + # :info + # :warn + # :error + # :fatal + # + # Throws an ArgumentError if you feed it a bogus log level. + def level(loglevel) + init() unless @logger + case loglevel + when :debug + @logger.level = Logger::DEBUG + when :info + @logger.level = Logger::INFO + when :warn + @logger.level = Logger::WARN + when :error + @logger.level = Logger::ERROR + when :fatal + @logger.level = Logger::FATAL + else + raise ArgumentError, "Log level must be one of :debug, :info, :warn, :error, or :fatal" + end + end + + # Passes any other method calls on directly to the underlying Logger object created with init. If + # this method gets hit before a call to Chef::Logger.init has been made, it will call + # Chef::Logger.init() with no arguments. + def method_missing(method_symbol, *args) + init() unless @logger + if args.length > 0 + @logger.send(method_symbol, *args) + else + @logger.send(method_symbol) + end + end + + end # class << self + end +end
\ No newline at end of file diff --git a/lib/chef/log/formatter.rb b/lib/chef/log/formatter.rb new file mode 100644 index 0000000000..d177060d97 --- /dev/null +++ b/lib/chef/log/formatter.rb @@ -0,0 +1,52 @@ +# +# Chef::Log::Formatter +# +# A custom Logger::Formatter implementation for Chef. +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require 'logger' +require 'time' + +class Chef + class Log + class Formatter < Logger::Formatter + # Prints a log message as '[time] severity: message' + def call(severity, time, progname, msg) + sprintf("[%s] %s: %s\n", time.rfc2822(), severity, msg2str(msg)) + end + + # Converts some argument to a Logger.severity() call to a string. Regular strings pass through like + # normal, Exceptions get formatted as "message (class)\nbacktrace", and other random stuff gets + # put through "object.inspect" + def msg2str(msg) + case msg + when ::String + msg + when ::Exception + "#{ msg.message } (#{ msg.class })\n" << + (msg.backtrace || []).join("\n") + else + msg.inspect + end + end + end + end +end
\ No newline at end of file diff --git a/lib/chef/node.rb b/lib/chef/node.rb index d5896fbd95..7cb42effd0 100644 --- a/lib/chef/node.rb +++ b/lib/chef/node.rb @@ -1,7 +1,6 @@ # # Chef::Node # -# # Author:: Adam Jacob (<adam@hjksolutions.com>) # Copyright:: Copyright (c) 2008 HJK Solutions, LLC # License:: GNU General Public License version 2 or later @@ -24,6 +23,9 @@ require File.join(File.dirname(__FILE__), "mixin", "check_helper") require File.join(File.dirname(__FILE__), "mixin", "from_file") +require 'rubygems' +require 'json' + class Chef class Node @@ -39,6 +41,42 @@ class Chef @recipe_list = Array.new end + # Find a Chef::Node by fqdn. Will search first for Chef::Config["node_path"]/fqdn.rb, then + # hostname.rb, then default.rb. + # + # Returns a new Chef::Node object. + # + # Raises an ArgumentError if it cannot find the node. + def self.find(fqdn) + node_file = nil + host_parts = fqdn.split(".") + hostname = host_parts[0] + + if File.exists?(File.join(Chef::Config[:node_path], "#{fqdn}.rb")) + node_file = File.join(Chef::Config[:node_path], "#{fqdn}.rb") + elsif File.exists?(File.join(Chef::Config[:node_path], "#{hostname}.rb")) + node_file = File.join(Chef::Config[:node_path], "#{hostname}.rb") + elsif File.exists?(File.join(Chef::Config[:node_path], "default.rb")) + node_file = File.join(Chef::Config[:node_path], "default.rb") + else + raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!" + end + chef_node = Chef::Node.new() + chef_node.from_file(node_file) + chef_node + end + + # Returns an array of nodes available, based on the list of files present. + def self.list + results = Array.new + Dir[File.join(Chef::Config[:node_path], "*.rb")].sort.each do |file| + mr = file.match(/^.+\/(.+)\.rb$/) + node_name = mr[1] + results << node_name + end + results + end + # Set the name of this Node, or return the current name. def name(arg=nil) set_if_args(@name, arg) do |a| @@ -62,6 +100,11 @@ class Chef end end + # Set an attribute of this node + def []=(attrib, value) + @attribute[attrib] = value + end + # Iterates over each attribute, passing the attribute and value to the block. def each_attribute(&block) @attribute.each do |k,v| @@ -108,5 +151,22 @@ class Chef end end + # Serialize this Node as json + def to_json() + result_object = { + "name" => @name, + "type" => "Chef::Node", + "attributes" => Hash.new, + "recipes" => Array.new + } + each_attribute do |a,v| + result_object["attributes"][a] = v + end + recipes.each do |r| + result_object["recipes"] << r + end + result_object.to_json + end + end end
\ No newline at end of file diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb index af1cbd2d77..d7d1435eb4 100644 --- a/lib/chef/recipe.rb +++ b/lib/chef/recipe.rb @@ -81,6 +81,7 @@ class Chef new_def.instance_eval(&block) new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @cookbook_loader) new_recipe.params = new_def.params + new_recipe.params[:name] = args[0] new_recipe.instance_eval(&new_def.recipe) else method_name = method_symbol.to_s diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb index dc93cfb4fa..5728fdd3e9 100644 --- a/lib/chef/resource_collection.rb +++ b/lib/chef/resource_collection.rb @@ -33,6 +33,7 @@ class Chef def []=(index, arg) is_chef_resource(arg) + raise ArgumentError, "Already have a resource named #{arg.to_s}" if @resources_by_name.has_key?(arg.to_s) @resources[index] = arg @resources_by_name[arg.to_s] = index end @@ -40,6 +41,7 @@ class Chef def <<(*args) args.flatten.each do |a| is_chef_resource(a) + raise ArgumentError, "Already have a resource named #{a.to_s}" if @resources_by_name.has_key?(a.to_s) @resources << a @resources_by_name[a.to_s] = @resources.length - 1 end @@ -48,6 +50,7 @@ class Chef def push(*args) args.flatten.each do |a| is_chef_resource(a) + raise ArgumentError, "Already have a resource named #{a.to_s}" if @resources_by_name.has_key?(a.to_s) @resources.push(a) @resources_by_name[a.to_s] = @resources.length - 1 end |