summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2019-06-11 18:02:10 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2020-02-14 10:38:38 -0800
commit6805006207c78f48961d24336be2054095a8bd68 (patch)
treee3991700623dabf67b2a8bea88714dab54a084d5
parent5a9f64b83e4605ee4d23190a3afcf08b000e3da1 (diff)
downloadchef-6805006207c78f48961d24336be2054095a8bd68.tar.gz
parse yaml recipes
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r--lib/chef/cookbook_version.rb39
-rw-r--r--lib/chef/mixin/from_file.rb21
-rw-r--r--lib/chef/recipe.rb16
3 files changed, 74 insertions, 2 deletions
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 4989fb8d91..ed0c199728 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -4,7 +4,7 @@
# Author:: Tim Hinderliter (<tim@chef.io>)
# Author:: Seth Falcon (<seth@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2008-2018, Chef Software Inc.
+# Copyright:: Copyright 2008-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -137,6 +137,18 @@ class Chef
end
end
+ def recipe_yml_filenames_by_name
+ @recipe_ym_filenames_by_name ||= begin
+ name_map = yml_filenames_by_name(files_for("recipes"))
+ root_alias = cookbook_manifest.root_files.find { |record| record[:name] == "root_files/recipe.yml" }
+ if root_alias
+ Chef::Log.error("Cookbook #{name} contains both recipe.yml and and recipes/default.yml, ignoring recipes/default.yml") if name_map["default"]
+ name_map["default"] = root_alias[:full_path]
+ end
+ name_map
+ end
+ end
+
def recipe_filenames_by_name
@recipe_filenames_by_name ||= begin
name_map = filenames_by_name(files_for("recipes"))
@@ -184,10 +196,29 @@ class Chef
# called from DSL
def load_recipe(recipe_name, run_context)
- unless recipe_filenames_by_name.key?(recipe_name)
+ if recipe_filenames_by_name.key?(recipe_name)
+ load_ruby_recipe(recipe_name, run_context)
+ elsif recipe_yml_filenames_by_name.key?(recipe_name)
+ load_yml_recipe(recipe_name, run_context)
+ else
raise Chef::Exceptions::RecipeNotFound, "could not find recipe #{recipe_name} for cookbook #{name}"
end
+ end
+ def load_yml_recipe(recipe_name, run_context)
+ Chef::Log.trace("Found recipe #{recipe_name} in cookbook #{name}")
+ recipe = Chef::Recipe.new(name, recipe_name, run_context)
+ recipe_filename = recipe_yml_filenames_by_name[recipe_name]
+
+ unless recipe_filename
+ raise Chef::Exceptions::RecipeNotFound, "could not find #{recipe_name} files for cookbook #{name}"
+ end
+
+ recipe.from_yaml_file(recipe_filename)
+ recipe
+ end
+
+ def load_ruby_recipe(recipe_name, run_context)
Chef::Log.trace("Found recipe #{recipe_name} in cookbook #{name}")
recipe = Chef::Recipe.new(name, recipe_name, run_context)
recipe_filename = recipe_filenames_by_name[recipe_name]
@@ -551,6 +582,10 @@ class Chef
records.select { |record| record[:name] =~ /\.rb$/ }.inject({}) { |memo, record| memo[File.basename(record[:name], ".rb")] = record[:full_path]; memo }
end
+ def yml_filenames_by_name(records)
+ records.select { |record| record[:name] =~ /\.yml$/ }.inject({}) { |memo, record| memo[File.basename(record[:name], ".yml")] = record[:full_path]; memo }
+ end
+
def file_vendor
unless @file_vendor
@file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(cookbook_manifest)
diff --git a/lib/chef/mixin/from_file.rb b/lib/chef/mixin/from_file.rb
index b8300340c7..ba034d331e 100644
--- a/lib/chef/mixin/from_file.rb
+++ b/lib/chef/mixin/from_file.rb
@@ -17,6 +17,8 @@
# limitations under the License.
#
+require "erb"
+
class Chef
module Mixin
module FromFile
@@ -37,6 +39,25 @@ class Chef
end
end
+ # This will return an array of hashes or something that then needs to get inflated.
+ def from_yaml_file(filename)
+ self.source_file = filename
+ if File.file?(filename) && File.readable?(filename)
+ tpl = ERB.new(IO.read(filename))
+ tpl.filename = filename
+ res = ::YAML.safe_load(tpl.result)
+ if res.is_a?(Hash)
+ from_hash(res)
+ elsif res.is_a?(Array)
+ from_array(res)
+ else
+ raise "boom"
+ end
+ else
+ raise IOError, "Cannot open or read #{filename}!"
+ end
+ end
+
# Loads a given ruby file, and runs class_eval against it in the context of the current
# object.
#
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index 154072827e..95b69532f8 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -85,6 +85,22 @@ class Chef
end
end
+ def from_array(array)
+ array.each { |e| from_hash(e) }
+ end
+
+ def from_hash(hash)
+ hash["resources"].each do |rhash|
+ type = rhash.delete("type").to_sym
+ name = rhash.delete("name")
+ res = declare_resource(type, name)
+ rhash.each do |key, value|
+ # FIXME?: we probably need a way to instance_exec a string that contains block code against the property?
+ res.send(key, value)
+ end
+ end
+ end
+
def to_s
"cookbook: #{cookbook_name ? cookbook_name : "(none)"}, recipe: #{recipe_name ? recipe_name : "(none)"} "
end