microwave 0.1004.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +102 -0
  3. data/bin/chef-solo +25 -0
  4. data/lib/chef.rb +41 -0
  5. data/lib/chef/application.rb +147 -0
  6. data/lib/chef/application/solo.rb +181 -0
  7. data/lib/chef/applications.rb +1 -0
  8. data/lib/chef/checksum.rb +83 -0
  9. data/lib/chef/checksum_cache.rb +189 -0
  10. data/lib/chef/client.rb +325 -0
  11. data/lib/chef/config.rb +152 -0
  12. data/lib/chef/cookbook/chefignore.rb +66 -0
  13. data/lib/chef/cookbook/cookbook_collection.rb +45 -0
  14. data/lib/chef/cookbook/cookbook_version_loader.rb +173 -0
  15. data/lib/chef/cookbook/file_system_file_vendor.rb +56 -0
  16. data/lib/chef/cookbook/file_vendor.rb +48 -0
  17. data/lib/chef/cookbook/metadata.rb +629 -0
  18. data/lib/chef/cookbook/syntax_check.rb +136 -0
  19. data/lib/chef/cookbook_loader.rb +121 -0
  20. data/lib/chef/cookbook_version.rb +786 -0
  21. data/lib/chef/cookbook_version_selector.rb +151 -0
  22. data/lib/chef/environment.rb +267 -0
  23. data/lib/chef/exceptions.rb +150 -0
  24. data/lib/chef/file_access_control.rb +144 -0
  25. data/lib/chef/file_cache.rb +218 -0
  26. data/lib/chef/handler.rb +206 -0
  27. data/lib/chef/handler/error_report.rb +33 -0
  28. data/lib/chef/handler/json_file.rb +58 -0
  29. data/lib/chef/json_compat.rb +52 -0
  30. data/lib/chef/log.rb +39 -0
  31. data/lib/chef/mash.rb +211 -0
  32. data/lib/chef/mixin/check_helper.rb +31 -0
  33. data/lib/chef/mixin/checksum.rb +32 -0
  34. data/lib/chef/mixin/command.rb +221 -0
  35. data/lib/chef/mixin/command/unix.rb +215 -0
  36. data/lib/chef/mixin/command/windows.rb +76 -0
  37. data/lib/chef/mixin/convert_to_class_name.rb +63 -0
  38. data/lib/chef/mixin/create_path.rb +57 -0
  39. data/lib/chef/mixin/deep_merge.rb +225 -0
  40. data/lib/chef/mixin/deprecation.rb +65 -0
  41. data/lib/chef/mixin/from_file.rb +50 -0
  42. data/lib/chef/mixin/get_source_from_package.rb +42 -0
  43. data/lib/chef/mixin/language.rb +125 -0
  44. data/lib/chef/mixin/language_include_attribute.rb +61 -0
  45. data/lib/chef/mixin/language_include_recipe.rb +52 -0
  46. data/lib/chef/mixin/params_validate.rb +225 -0
  47. data/lib/chef/mixin/recipe_definition_dsl_core.rb +78 -0
  48. data/lib/chef/mixin/shell_out.rb +41 -0
  49. data/lib/chef/mixin/template.rb +95 -0
  50. data/lib/chef/mixin/xml_escape.rb +140 -0
  51. data/lib/chef/mixins.rb +15 -0
  52. data/lib/chef/monkey_patches/dir.rb +36 -0
  53. data/lib/chef/monkey_patches/numeric.rb +15 -0
  54. data/lib/chef/monkey_patches/object.rb +9 -0
  55. data/lib/chef/monkey_patches/regexp.rb +34 -0
  56. data/lib/chef/monkey_patches/string.rb +49 -0
  57. data/lib/chef/monkey_patches/tempfile.rb +64 -0
  58. data/lib/chef/nil_argument.rb +3 -0
  59. data/lib/chef/node.rb +469 -0
  60. data/lib/chef/node/attribute.rb +487 -0
  61. data/lib/chef/platform.rb +409 -0
  62. data/lib/chef/provider.rb +124 -0
  63. data/lib/chef/provider/breakpoint.rb +31 -0
  64. data/lib/chef/provider/cookbook_file.rb +100 -0
  65. data/lib/chef/provider/cron.rb +186 -0
  66. data/lib/chef/provider/cron/solaris.rb +195 -0
  67. data/lib/chef/provider/deploy.rb +343 -0
  68. data/lib/chef/provider/deploy/revision.rb +80 -0
  69. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  70. data/lib/chef/provider/directory.rb +72 -0
  71. data/lib/chef/provider/env.rb +152 -0
  72. data/lib/chef/provider/env/windows.rb +75 -0
  73. data/lib/chef/provider/erl_call.rb +101 -0
  74. data/lib/chef/provider/execute.rb +66 -0
  75. data/lib/chef/provider/file.rb +222 -0
  76. data/lib/chef/provider/git.rb +243 -0
  77. data/lib/chef/provider/group.rb +133 -0
  78. data/lib/chef/provider/group/aix.rb +70 -0
  79. data/lib/chef/provider/group/dscl.rb +121 -0
  80. data/lib/chef/provider/group/gpasswd.rb +53 -0
  81. data/lib/chef/provider/group/groupadd.rb +81 -0
  82. data/lib/chef/provider/group/pw.rb +84 -0
  83. data/lib/chef/provider/group/suse.rb +53 -0
  84. data/lib/chef/provider/group/usermod.rb +57 -0
  85. data/lib/chef/provider/group/windows.rb +79 -0
  86. data/lib/chef/provider/ifconfig.rb +134 -0
  87. data/lib/chef/provider/link.rb +164 -0
  88. data/lib/chef/provider/log.rb +54 -0
  89. data/lib/chef/provider/mdadm.rb +91 -0
  90. data/lib/chef/provider/mount.rb +114 -0
  91. data/lib/chef/provider/mount/mount.rb +240 -0
  92. data/lib/chef/provider/mount/windows.rb +81 -0
  93. data/lib/chef/provider/ohai.rb +42 -0
  94. data/lib/chef/provider/package.rb +163 -0
  95. data/lib/chef/provider/package/apt.rb +135 -0
  96. data/lib/chef/provider/package/dpkg.rb +115 -0
  97. data/lib/chef/provider/package/easy_install.rb +136 -0
  98. data/lib/chef/provider/package/freebsd.rb +125 -0
  99. data/lib/chef/provider/package/macports.rb +105 -0
  100. data/lib/chef/provider/package/pacman.rb +101 -0
  101. data/lib/chef/provider/package/portage.rb +135 -0
  102. data/lib/chef/provider/package/rpm.rb +104 -0
  103. data/lib/chef/provider/package/rubygems.rb +465 -0
  104. data/lib/chef/provider/package/solaris.rb +130 -0
  105. data/lib/chef/provider/package/yum-dump.py +286 -0
  106. data/lib/chef/provider/package/yum.rb +1128 -0
  107. data/lib/chef/provider/package/zypper.rb +144 -0
  108. data/lib/chef/provider/remote_directory.rb +137 -0
  109. data/lib/chef/provider/route.rb +193 -0
  110. data/lib/chef/provider/ruby_block.rb +34 -0
  111. data/lib/chef/provider/script.rb +55 -0
  112. data/lib/chef/provider/service.rb +122 -0
  113. data/lib/chef/provider/service/arch.rb +116 -0
  114. data/lib/chef/provider/service/debian.rb +130 -0
  115. data/lib/chef/provider/service/freebsd.rb +154 -0
  116. data/lib/chef/provider/service/gentoo.rb +53 -0
  117. data/lib/chef/provider/service/init.rb +71 -0
  118. data/lib/chef/provider/service/insserv.rb +52 -0
  119. data/lib/chef/provider/service/redhat.rb +60 -0
  120. data/lib/chef/provider/service/simple.rb +120 -0
  121. data/lib/chef/provider/service/solaris.rb +85 -0
  122. data/lib/chef/provider/service/systemd.rb +102 -0
  123. data/lib/chef/provider/service/upstart.rb +198 -0
  124. data/lib/chef/provider/service/windows.rb +146 -0
  125. data/lib/chef/provider/subversion.rb +197 -0
  126. data/lib/chef/provider/template.rb +104 -0
  127. data/lib/chef/provider/user.rb +186 -0
  128. data/lib/chef/provider/user/dscl.rb +280 -0
  129. data/lib/chef/provider/user/pw.rb +113 -0
  130. data/lib/chef/provider/user/useradd.rb +137 -0
  131. data/lib/chef/provider/user/windows.rb +124 -0
  132. data/lib/chef/providers.rb +93 -0
  133. data/lib/chef/recipe.rb +129 -0
  134. data/lib/chef/resource.rb +584 -0
  135. data/lib/chef/resource/apt_package.rb +34 -0
  136. data/lib/chef/resource/bash.rb +33 -0
  137. data/lib/chef/resource/breakpoint.rb +35 -0
  138. data/lib/chef/resource/cookbook_file.rb +45 -0
  139. data/lib/chef/resource/cron.rb +188 -0
  140. data/lib/chef/resource/csh.rb +33 -0
  141. data/lib/chef/resource/deploy.rb +380 -0
  142. data/lib/chef/resource/deploy_revision.rb +40 -0
  143. data/lib/chef/resource/directory.rb +89 -0
  144. data/lib/chef/resource/dpkg_package.rb +34 -0
  145. data/lib/chef/resource/easy_install_package.rb +57 -0
  146. data/lib/chef/resource/env.rb +58 -0
  147. data/lib/chef/resource/erl_call.rb +83 -0
  148. data/lib/chef/resource/execute.rb +127 -0
  149. data/lib/chef/resource/file.rb +112 -0
  150. data/lib/chef/resource/freebsd_package.rb +35 -0
  151. data/lib/chef/resource/gem_package.rb +53 -0
  152. data/lib/chef/resource/git.rb +46 -0
  153. data/lib/chef/resource/group.rb +70 -0
  154. data/lib/chef/resource/ifconfig.rb +134 -0
  155. data/lib/chef/resource/link.rb +105 -0
  156. data/lib/chef/resource/log.rb +62 -0
  157. data/lib/chef/resource/macports_package.rb +29 -0
  158. data/lib/chef/resource/mdadm.rb +82 -0
  159. data/lib/chef/resource/mount.rb +134 -0
  160. data/lib/chef/resource/ohai.rb +40 -0
  161. data/lib/chef/resource/package.rb +80 -0
  162. data/lib/chef/resource/pacman_package.rb +33 -0
  163. data/lib/chef/resource/perl.rb +33 -0
  164. data/lib/chef/resource/portage_package.rb +33 -0
  165. data/lib/chef/resource/python.rb +33 -0
  166. data/lib/chef/resource/remote_directory.rb +109 -0
  167. data/lib/chef/resource/route.rb +135 -0
  168. data/lib/chef/resource/rpm_package.rb +34 -0
  169. data/lib/chef/resource/ruby.rb +33 -0
  170. data/lib/chef/resource/ruby_block.rb +40 -0
  171. data/lib/chef/resource/scm.rb +147 -0
  172. data/lib/chef/resource/script.rb +60 -0
  173. data/lib/chef/resource/service.rb +160 -0
  174. data/lib/chef/resource/solaris_package.rb +36 -0
  175. data/lib/chef/resource/subversion.rb +36 -0
  176. data/lib/chef/resource/template.rb +69 -0
  177. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  178. data/lib/chef/resource/user.rb +130 -0
  179. data/lib/chef/resource/yum_package.rb +63 -0
  180. data/lib/chef/resource_collection.rb +217 -0
  181. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  182. data/lib/chef/resource_definition.rb +67 -0
  183. data/lib/chef/resource_definition_list.rb +38 -0
  184. data/lib/chef/resources.rb +62 -0
  185. data/lib/chef/role.rb +225 -0
  186. data/lib/chef/run_context.rb +126 -0
  187. data/lib/chef/run_list.rb +161 -0
  188. data/lib/chef/run_list/run_list_expansion.rb +159 -0
  189. data/lib/chef/run_list/run_list_item.rb +92 -0
  190. data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
  191. data/lib/chef/run_status.rb +121 -0
  192. data/lib/chef/runner.rb +105 -0
  193. data/lib/chef/shell_out.rb +250 -0
  194. data/lib/chef/shell_out/unix.rb +223 -0
  195. data/lib/chef/shell_out/windows.rb +98 -0
  196. data/lib/chef/tasks/chef_repo.rake +330 -0
  197. data/lib/chef/util/file_edit.rb +122 -0
  198. data/lib/chef/util/windows.rb +56 -0
  199. data/lib/chef/util/windows/net_group.rb +101 -0
  200. data/lib/chef/util/windows/net_use.rb +121 -0
  201. data/lib/chef/util/windows/net_user.rb +198 -0
  202. data/lib/chef/util/windows/volume.rb +59 -0
  203. data/lib/chef/version.rb +23 -0
  204. data/lib/chef/version_class.rb +70 -0
  205. data/lib/chef/version_constraint.rb +116 -0
  206. metadata +493 -0
@@ -0,0 +1,126 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Walters (<cw@opscode.com>)
4
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
5
+ # Copyright:: Copyright (c) 2008-2010 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+
20
+ require 'chef/resource_collection'
21
+ require 'chef/node'
22
+ require 'chef/role'
23
+ require 'chef/log'
24
+ require 'chef/mixin/language_include_recipe'
25
+
26
+ class Chef
27
+ # == Chef::RunContext
28
+ # Value object that loads and tracks the context of a Chef run
29
+ class RunContext
30
+
31
+ # Used to load the node's recipes after expanding its run list
32
+ include Chef::Mixin::LanguageIncludeRecipe
33
+
34
+ attr_reader :node, :cookbook_collection, :definitions
35
+
36
+ # Needs to be settable so deploy can run a resource_collection independent
37
+ # of any cookbooks.
38
+ attr_accessor :resource_collection
39
+
40
+ # Creates a new Chef::RunContext object and populates its fields. This object gets
41
+ # used by the Chef Server to generate a fully compiled recipe list for a node.
42
+ #
43
+ # === Returns
44
+ # object<Chef::RunContext>:: Duh. :)
45
+ def initialize(node, cookbook_collection)
46
+ @node = node
47
+ @cookbook_collection = cookbook_collection
48
+ @resource_collection = Chef::ResourceCollection.new
49
+ @definitions = Hash.new
50
+
51
+ # TODO: 5/18/2010 cw/timh - See note on Chef::Node's
52
+ # cookbook_collection attr_accessor
53
+ node.cookbook_collection = cookbook_collection
54
+ end
55
+
56
+ def load(run_list_expansion)
57
+ load_libraries
58
+ load_lwrp_providers
59
+ load_lwrp_resources
60
+ load_attributes
61
+ load_resource_definitions
62
+
63
+ # Precendence rules state that roles' attributes come after
64
+ # cookbooks. Now we've loaded attributes from cookbooks with
65
+ # load_attributes, apply the expansion attributes (loaded from
66
+ # roles) to the node.
67
+ @node.apply_expansion_attributes(run_list_expansion)
68
+
69
+ run_list_expansion.recipes.each do |recipe|
70
+ # TODO: timh/cw, 5-14-2010: It's distasteful to be including
71
+ # the DSL in a class outside the context of the DSL
72
+ include_recipe(recipe)
73
+ end
74
+ end
75
+
76
+
77
+ private
78
+
79
+ def load_libraries
80
+ foreach_cookbook_load_segment(:libraries) do |cookbook_name, filename|
81
+ Chef::Log.debug("Loading cookbook #{cookbook_name}'s library file: #{filename}")
82
+ Kernel.load(filename)
83
+ end
84
+ end
85
+
86
+ def load_lwrp_providers
87
+ foreach_cookbook_load_segment(:providers) do |cookbook_name, filename|
88
+ Chef::Log.debug("Loading cookbook #{cookbook_name}'s providers from #{filename}")
89
+ Chef::Provider.build_from_file(cookbook_name, filename, self)
90
+ end
91
+ end
92
+
93
+ def load_lwrp_resources
94
+ foreach_cookbook_load_segment(:resources) do |cookbook_name, filename|
95
+ Chef::Log.debug("Loading cookbook #{cookbook_name}'s resources from #{filename}")
96
+ Chef::Resource.build_from_file(cookbook_name, filename, self)
97
+ end
98
+ end
99
+
100
+ def load_attributes
101
+ node.load_attributes
102
+ end
103
+
104
+ def load_resource_definitions
105
+ foreach_cookbook_load_segment(:definitions) do |cookbook_name, filename|
106
+ Chef::Log.debug("Loading cookbook #{cookbook_name}'s definitions from #{filename}")
107
+ resourcelist = Chef::ResourceDefinitionList.new
108
+ resourcelist.from_file(filename)
109
+ definitions.merge!(resourcelist.defines) do |key, oldval, newval|
110
+ Chef::Log.info("Overriding duplicate definition #{key}, new definition found in #{filename}")
111
+ newval
112
+ end
113
+ end
114
+ end
115
+
116
+ def foreach_cookbook_load_segment(segment, &block)
117
+ cookbook_collection.each do |cookbook_name, cookbook|
118
+ segment_filenames = cookbook.segment_filenames(segment)
119
+ segment_filenames.each do |segment_filename|
120
+ block.call(cookbook_name, segment_filename)
121
+ end
122
+ end
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,161 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Nuo Yan (<nuoyan@opscode.com>)
4
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
5
+ # Author:: Christopher Walters (<cw@opscode.com>)
6
+ # Author:: Seth Falcon (<seth@opscode.com>)
7
+ # Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
8
+ # License:: Apache License, Version 2.0
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+
22
+ require 'chef/run_list/run_list_item'
23
+ require 'chef/run_list/run_list_expansion'
24
+ require 'chef/run_list/versioned_recipe_list'
25
+ require 'chef/mixin/params_validate'
26
+
27
+ class Chef
28
+ class RunList
29
+ include Enumerable
30
+ include Chef::Mixin::ParamsValidate
31
+
32
+ # @run_list_items is an array of RunListItems that describe the items to
33
+ # execute in order. RunListItems can load from and convert to the string
34
+ # forms users set on roles and nodes.
35
+ # For example:
36
+ # @run_list_items = ['recipe[foo::bar]', 'role[webserver]']
37
+ # Thus,
38
+ # self.role_names would return ['webserver']
39
+ # self.recipe_names would return ['foo::bar']
40
+ attr_reader :run_list_items
41
+
42
+ # For backwards compat
43
+ alias :run_list :run_list_items
44
+
45
+ def initialize(*run_list_items)
46
+ @run_list_items = run_list_items.map { |i| coerce_to_run_list_item(i) }
47
+ end
48
+
49
+ def role_names
50
+ @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.role? ; memo}
51
+ end
52
+
53
+ alias :roles :role_names
54
+
55
+ def recipe_names
56
+ @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.recipe? ; memo}
57
+ end
58
+
59
+ alias :recipes :recipe_names
60
+
61
+ # Add an item of the form "recipe[foo::bar]" or "role[webserver]";
62
+ # takes a String or a RunListItem
63
+ def <<(run_list_item)
64
+ run_list_item = coerce_to_run_list_item(run_list_item)
65
+ @run_list_items << run_list_item unless @run_list_items.include?(run_list_item)
66
+ self
67
+ end
68
+
69
+ alias :push :<<
70
+
71
+ def ==(other)
72
+ if other.kind_of?(Chef::RunList)
73
+ other.run_list_items == @run_list_items
74
+ else
75
+ return false unless other.respond_to?(:size) && (other.size == @run_list_items.size)
76
+ other_run_list_items = other.dup
77
+
78
+ other_run_list_items.map! { |item| coerce_to_run_list_item(item) }
79
+ other_run_list_items == @run_list_items
80
+ end
81
+ end
82
+
83
+ def to_s
84
+ @run_list_items.join(", ")
85
+ end
86
+
87
+ def to_json(*args)
88
+ to_a.to_json(*args)
89
+ end
90
+
91
+ def empty?
92
+ @run_list_items.length == 0 ? true : false
93
+ end
94
+
95
+ def [](pos)
96
+ @run_list_items[pos]
97
+ end
98
+
99
+ def []=(pos, item)
100
+ @run_list_items[pos] = parse_entry(item)
101
+ end
102
+
103
+ def each(&block)
104
+ @run_list_items.each { |i| block.call(i) }
105
+ end
106
+
107
+ def each_index(&block)
108
+ @run_list_items.each_index { |i| block.call(i) }
109
+ end
110
+
111
+ def include?(item)
112
+ @run_list_items.include?(parse_entry(item))
113
+ end
114
+
115
+ def reset!(*args)
116
+ @run_list_items.clear
117
+ args.flatten.each do |item|
118
+ if item.kind_of?(Chef::RunList)
119
+ item.each { |r| self << r }
120
+ else
121
+ self << item
122
+ end
123
+ end
124
+ self
125
+ end
126
+
127
+ def remove(item)
128
+ @run_list_items.delete_if{|i| i == item}
129
+ self
130
+ end
131
+ alias :delete :remove
132
+
133
+ # Expands this run_list: recursively expand roles into their included
134
+ # recipes.
135
+ # Returns a RunListExpansion object.
136
+ def expand(environment, data_source='disk', expansion_opts={})
137
+ expansion = expansion_for_data_source(environment, data_source, expansion_opts)
138
+ expansion.expand
139
+ expansion
140
+ end
141
+
142
+ # Converts a string run list entry to a RunListItem object.
143
+ def parse_entry(entry)
144
+ RunListItem.new(entry)
145
+ end
146
+
147
+ def coerce_to_run_list_item(item)
148
+ item.kind_of?(RunListItem) ? item : parse_entry(item)
149
+ end
150
+
151
+ def expansion_for_data_source(environment, data_source, opts={})
152
+ case data_source.to_s
153
+ when 'disk'
154
+ RunListExpansionFromDisk.new(environment, @run_list_items)
155
+ end
156
+ end
157
+
158
+
159
+ end
160
+ end
161
+
@@ -0,0 +1,159 @@
1
+ #
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
4
+ # Copyright:: Copyright (c) 2010, 2011 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'chef/mash'
20
+
21
+ require 'chef/mixin/deep_merge'
22
+
23
+ require 'chef/role'
24
+
25
+ class Chef
26
+ class RunList
27
+ # Abstract Base class for expanding a run list. Subclasses must handle
28
+ # fetching roles from a data source by defining +fetch_role+
29
+ class RunListExpansion
30
+
31
+ attr_reader :run_list_items
32
+
33
+ # A VersionedRecipeList of recipes. Populated only after #expand
34
+ # is called.
35
+ attr_reader :recipes
36
+
37
+ attr_reader :default_attrs
38
+
39
+ attr_reader :override_attrs
40
+
41
+ attr_reader :errors
42
+
43
+ attr_reader :environment
44
+
45
+ # The data source passed to the constructor. Not used in this class.
46
+ # In subclasses, this is a couchdb or Chef::REST object pre-configured
47
+ # to fetch roles from their correct location.
48
+ attr_reader :source
49
+
50
+ def initialize(environment, run_list_items, source=nil)
51
+ @environment = environment
52
+ @errors = Array.new
53
+
54
+ @run_list_items = run_list_items.dup
55
+ @source = source
56
+
57
+ @default_attrs = Mash.new
58
+ @override_attrs = Mash.new
59
+
60
+ @recipes = Chef::RunList::VersionedRecipeList.new
61
+
62
+ @applied_roles = {}
63
+ end
64
+
65
+ # Did we find any errors (expanding roles)?
66
+ def errors?
67
+ @errors.length > 0
68
+ end
69
+
70
+ alias :invalid? :errors?
71
+
72
+ # Recurses over the run list items, expanding roles. After this,
73
+ # +recipes+ will contain the fully expanded recipe list
74
+ def expand
75
+ # Sure do miss function arity when being recursive
76
+ expand_run_list_items(@run_list_items)
77
+ end
78
+
79
+ # Fetches and inflates a role
80
+ # === Returns
81
+ # Chef::Role in most cases
82
+ # false if the role has already been applied
83
+ # nil if the role does not exist
84
+ def inflate_role(role_name)
85
+ return false if applied_role?(role_name) # Prevent infinite loops
86
+ applied_role(role_name)
87
+ fetch_role(role_name)
88
+ end
89
+
90
+ def apply_role_attributes(role)
91
+ @default_attrs = Chef::Mixin::DeepMerge.merge(@default_attrs, role.default_attributes)
92
+ @override_attrs = Chef::Mixin::DeepMerge.merge(@override_attrs, role.override_attributes)
93
+ end
94
+
95
+ def applied_role?(role_name)
96
+ @applied_roles.has_key?(role_name)
97
+ end
98
+
99
+ # Returns an array of role names that were expanded; this
100
+ # includes any roles that were in the original, pre-expansion
101
+ # run_list as well as roles processed during
102
+ # expansion. Populated only after #expand is called.
103
+ def roles
104
+ @applied_roles.keys
105
+ end
106
+
107
+ # In subclasses, this method will fetch the role from the data source.
108
+ def fetch_role(name)
109
+ raise NotImplementedError
110
+ end
111
+
112
+ # When a role is not found, an error message is logged, but no
113
+ # exception is raised. We do add an entry in the errors collection.
114
+ # === Returns
115
+ # nil
116
+ def role_not_found(name)
117
+ Chef::Log.error("Role #{name} is in the runlist but does not exist. Skipping expand.")
118
+ @errors << name
119
+ nil
120
+ end
121
+
122
+ private
123
+
124
+ # these methods modifies internal state based on arguments, so hide it.
125
+
126
+ def applied_role(role_name)
127
+ @applied_roles[role_name] = true
128
+ end
129
+
130
+ def expand_run_list_items(items)
131
+ if entry = items.shift
132
+ case entry.type
133
+ when :recipe
134
+ recipes.add_recipe(entry.name, entry.version)
135
+ when :role
136
+ if role = inflate_role(entry.name)
137
+ expand_run_list_items(role.run_list_for(@environment).run_list_items)
138
+ apply_role_attributes(role)
139
+ end
140
+ end
141
+ expand_run_list_items(items)
142
+ end
143
+ end
144
+
145
+ end
146
+
147
+ # Expand a run list from disk. Suitable for chef-solo
148
+ class RunListExpansionFromDisk < RunListExpansion
149
+
150
+ def fetch_role(name)
151
+ Chef::Role.from_disk(name)
152
+ rescue Chef::Exceptions::RoleNotFound
153
+ role_not_found(name)
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,92 @@
1
+ #
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Copyright:: Copyright (c) 2010 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ class Chef
19
+ class RunList
20
+ class RunListItem
21
+ QUALIFIED_RECIPE = %r{^recipe\[([^\]@]+)(@([0-9]+(\.[0-9]+){1,2}))?\]$}
22
+ QUALIFIED_ROLE = %r{^role\[([^\]]+)\]$}
23
+ VERSIONED_UNQUALIFIED_RECIPE = %r{^([^@]+)(@([0-9]+(\.[0-9]+){1,2}))$}
24
+
25
+ attr_reader :name, :type, :version
26
+
27
+
28
+ def initialize(item)
29
+ @version = nil
30
+ case item
31
+ when Hash
32
+ assert_hash_is_valid_run_list_item!(item)
33
+ @type = (item['type'] || item[:type]).to_sym
34
+ @name = item['name'] || item[:name]
35
+ if (item.has_key?('version') || item.has_key?(:version))
36
+ @version = item['version'] || item[:version]
37
+ end
38
+ when String
39
+ if match = QUALIFIED_RECIPE.match(item)
40
+ # recipe[recipe_name]
41
+ # recipe[recipe_name@1.0.0]
42
+ @type = :recipe
43
+ @name = match[1]
44
+ @version = match[3] if match[3]
45
+ elsif match = QUALIFIED_ROLE.match(item)
46
+ # role[role_name]
47
+ @type = :role
48
+ @name = match[1]
49
+ elsif match = VERSIONED_UNQUALIFIED_RECIPE.match(item)
50
+ # recipe_name@1.0.0
51
+ @type = :recipe
52
+ @name = match[1]
53
+ @version = match[3] if match[3]
54
+ else
55
+ # recipe_name
56
+ @type = :recipe
57
+ @name = item
58
+ end
59
+ else
60
+ raise ArgumentError, "Unable to create #{self.class} from #{item.class}:#{item.inspect}: must be a Hash or String"
61
+ end
62
+ end
63
+
64
+ def to_s
65
+ "#{@type}[#{@name}#{@version ? "@#{@version}" :""}]"
66
+ end
67
+
68
+ def role?
69
+ @type == :role
70
+ end
71
+
72
+ def recipe?
73
+ @type == :recipe
74
+ end
75
+
76
+ def ==(other)
77
+ if other.kind_of?(String)
78
+ self.to_s == other.to_s
79
+ else
80
+ other.respond_to?(:type) && other.respond_to?(:name) && other.respond_to?(:version) && other.type == @type && other.name == @name && other.version == @version
81
+ end
82
+ end
83
+
84
+ def assert_hash_is_valid_run_list_item!(item)
85
+ unless (item.key?('type')|| item.key?(:type)) && (item.key?('name') || item.key?(:name))
86
+ raise ArgumentError, "Initializing a #{self.class} from a hash requires that it have a 'type' and 'name' key"
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end