summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@chef.io>2020-02-24 10:14:28 -0800
committerGitHub <noreply@github.com>2020-02-24 10:14:28 -0800
commite1298393a94212a8c467a7deea7a81c991b73365 (patch)
tree85c1f314e357a29e4e189c8e7c5b2d32ce2a41a4
parentdabb4a8bb027b63bb555acb5a057df1ccf5a5584 (diff)
parentfc25d304203409093206ab2a76698932b990641c (diff)
downloadchef-e1298393a94212a8c467a7deea7a81c991b73365.tar.gz
Merge pull request #8653 from chef/lcg/yml-recipes
Parse YAML recipes
-rw-r--r--lib/chef/cookbook_version.rb39
-rw-r--r--lib/chef/recipe.rb37
2 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/recipe.rb b/lib/chef/recipe.rb
index 154072827e..ddb45de8e3 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -85,6 +85,43 @@ class Chef
end
end
+ def from_yaml_file(filename)
+ self.source_file = filename
+ if File.file?(filename) && File.readable?(filename)
+ from_yaml(IO.read(filename))
+ else
+ raise IOError, "Cannot open or read #{filename}!"
+ end
+ end
+
+ def from_yaml(string)
+ res = ::YAML.safe_load(string)
+ if res.is_a?(Hash)
+ from_hash(res)
+ elsif res.is_a?(Array)
+ from_array(res)
+ else
+ raise "boom"
+ end
+ end
+
+ def from_array(array)
+ Chef::Log.warn "array yaml files are super duper experimental behavior"
+ 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