chef-dk 0.2.0
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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +192 -0
- data/LICENSE +201 -0
- data/README.md +198 -0
- data/Rakefile +18 -0
- data/bin/chef +25 -0
- data/lib/chef-dk.rb +19 -0
- data/lib/chef-dk/builtin_commands.rb +31 -0
- data/lib/chef-dk/chef_runner.rb +83 -0
- data/lib/chef-dk/cli.rb +135 -0
- data/lib/chef-dk/command/base.rb +71 -0
- data/lib/chef-dk/command/exec.rb +33 -0
- data/lib/chef-dk/command/gem.rb +47 -0
- data/lib/chef-dk/command/generate.rb +97 -0
- data/lib/chef-dk/command/generator_commands.rb +417 -0
- data/lib/chef-dk/command/shell_init.rb +80 -0
- data/lib/chef-dk/command/verify.rb +226 -0
- data/lib/chef-dk/commands_map.rb +115 -0
- data/lib/chef-dk/component_test.rb +142 -0
- data/lib/chef-dk/cookbook_metadata.rb +36 -0
- data/lib/chef-dk/cookbook_omnifetch.rb +29 -0
- data/lib/chef-dk/cookbook_profiler/git.rb +95 -0
- data/lib/chef-dk/cookbook_profiler/identifiers.rb +79 -0
- data/lib/chef-dk/cookbook_profiler/null_scm.rb +32 -0
- data/lib/chef-dk/exceptions.rb +46 -0
- data/lib/chef-dk/generator.rb +70 -0
- data/lib/chef-dk/helpers.rb +95 -0
- data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +46 -0
- data/lib/chef-dk/policyfile/community_cookbook_source.rb +84 -0
- data/lib/chef-dk/policyfile/cookbook_sources.rb +20 -0
- data/lib/chef-dk/policyfile/cookbook_spec.rb +96 -0
- data/lib/chef-dk/policyfile/dsl.rb +148 -0
- data/lib/chef-dk/policyfile/null_cookbook_source.rb +37 -0
- data/lib/chef-dk/policyfile_compiler.rb +217 -0
- data/lib/chef-dk/policyfile_lock.rb +243 -0
- data/lib/chef-dk/shell_out.rb +36 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +3 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +96 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/converge_spec.rb +9 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/gitignore +16 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +8 -0
- data/lib/chef-dk/skeletons/code_generator/metadata.rb +8 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +65 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/attribute.rb +12 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +50 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/cookbook_file.rb +24 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/lwrp.rb +23 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +9 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/template.rb +32 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/README.md.erb +4 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/attribute.rb.erb +0 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/cookbook_file.erb +0 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/default_recipe.rb.erb +8 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +16 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/metadata.rb.erb +8 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/provider.rb.erb +0 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +0 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/resource.rb.erb +0 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/template.erb +0 -0
- data/lib/chef-dk/version.rb +20 -0
- data/spec/shared/setup_git_cookbooks.rb +53 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/test_helpers.rb +59 -0
- data/spec/unit/chef_runner_spec.rb +70 -0
- data/spec/unit/cli_spec.rb +151 -0
- data/spec/unit/command/base_spec.rb +88 -0
- data/spec/unit/command/exec_spec.rb +123 -0
- data/spec/unit/command/generate_spec.rb +102 -0
- data/spec/unit/command/generator_commands_spec.rb +504 -0
- data/spec/unit/command/shell_init_spec.rb +109 -0
- data/spec/unit/command/verify_spec.rb +311 -0
- data/spec/unit/commands_map_spec.rb +57 -0
- data/spec/unit/component_test_spec.rb +126 -0
- data/spec/unit/cookbook_metadata_spec.rb +62 -0
- data/spec/unit/cookbook_profiler/git_spec.rb +127 -0
- data/spec/unit/cookbook_profiler/identifiers_spec.rb +79 -0
- data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_one.rb +9 -0
- data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_two.rb +9 -0
- data/spec/unit/fixtures/command/cli_test_command.rb +26 -0
- data/spec/unit/fixtures/command/explicit_path_example.rb +7 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +3 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/chefignore +96 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -0
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/.kitchen.yml +16 -0
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +3 -0
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/README.md +4 -0
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/chefignore +96 -0
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/metadata.rb +8 -0
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/recipes/default.rb +8 -0
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/.kitchen.yml +16 -0
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +3 -0
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/README.md +4 -0
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/chefignore +96 -0
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/metadata.rb +8 -0
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/recipes/default.rb +8 -0
- data/spec/unit/fixtures/cookbooks_api/pruned_small_universe.json +1322 -0
- data/spec/unit/fixtures/cookbooks_api/small_universe.json +2987 -0
- data/spec/unit/fixtures/cookbooks_api/universe.json +1 -0
- data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +36 -0
- data/spec/unit/fixtures/dev_cookbooks/README.md +16 -0
- data/spec/unit/fixtures/dev_cookbooks/bar-cookbook.gitbundle +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_apps/bin/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_apps/embedded/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_apps/embedded/bin/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_component/bin/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_component/embedded/apps/berkshelf/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_component/embedded/apps/test-kitchen/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/missing_component/embedded/bin/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/bin/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/integration_test +2 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/verify_me +5 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef-dk/.keep +0 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef/verify_me +3 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/test-kitchen/verify_me +2 -0
- data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/bin/.keep +0 -0
- data/spec/unit/fixtures/example_app/Policyfile.rb +0 -0
- data/spec/unit/fixtures/example_cookbook/.gitignore +17 -0
- data/spec/unit/fixtures/example_cookbook/.kitchen.yml +16 -0
- data/spec/unit/fixtures/example_cookbook/Berksfile +3 -0
- data/spec/unit/fixtures/example_cookbook/README.md +4 -0
- data/spec/unit/fixtures/example_cookbook/chefignore +96 -0
- data/spec/unit/fixtures/example_cookbook/metadata.rb +8 -0
- data/spec/unit/fixtures/example_cookbook/recipes/default.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/.kitchen.yml +16 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +3 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/README.md +4 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/chefignore +96 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/metadata.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/recipes/default.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/metadata-missing/README.md +2 -0
- data/spec/unit/policyfile/chef_server_cookbook_source_spec.rb +34 -0
- data/spec/unit/policyfile/community_cookbook_source_spec.rb +51 -0
- data/spec/unit/policyfile/cookbook_spec_spec.rb +200 -0
- data/spec/unit/policyfile/null_cookbook_source_spec.rb +35 -0
- data/spec/unit/policyfile_builder_spec.rb +489 -0
- data/spec/unit/policyfile_demands_spec.rb +484 -0
- data/spec/unit/policyfile_evaluation_spec.rb +284 -0
- data/spec/unit/shell_out_spec.rb +34 -0
- metadata +422 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef-dk/exceptions'
|
|
19
|
+
|
|
20
|
+
module ChefDK
|
|
21
|
+
module Policyfile
|
|
22
|
+
class ChefServerCookbookSource
|
|
23
|
+
|
|
24
|
+
attr_reader :uri
|
|
25
|
+
|
|
26
|
+
def initialize(uri)
|
|
27
|
+
@uri = uri
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ==(other)
|
|
31
|
+
other.kind_of?(self.class) && other.uri == uri
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def universe_graph
|
|
35
|
+
raise UnsupportedFeature, 'ChefDK does not support chef-server cookbook default sources at this time'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def source_options_for(cookbook_name, cookbook_version)
|
|
39
|
+
raise UnsupportedFeature, 'ChefDK does not support chef-server cookbook default sources at this time'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'json'
|
|
19
|
+
require 'chef-dk/cookbook_omnifetch'
|
|
20
|
+
require 'chef-dk/exceptions'
|
|
21
|
+
# TODO: chef bug. Chef::HTTP::Simple needs to require this itself.
|
|
22
|
+
# Fixed in 2ed829e661f9a357fc9a8cdf316c84f077dad7f9 waiting for that to be
|
|
23
|
+
# released...
|
|
24
|
+
require 'tempfile'
|
|
25
|
+
require 'chef/platform/query_helpers' # should be handled by http/simple
|
|
26
|
+
require 'chef/http/cookie_manager' # should be handled by http/simple
|
|
27
|
+
require 'chef/http/validate_content_length' # should be handled by http/simple
|
|
28
|
+
require 'chef/http/simple'
|
|
29
|
+
|
|
30
|
+
# TODO: fix hardcoding
|
|
31
|
+
Chef::Config.ssl_verify_mode = :verify_peer
|
|
32
|
+
|
|
33
|
+
module ChefDK
|
|
34
|
+
module Policyfile
|
|
35
|
+
|
|
36
|
+
class CommunityCookbookSource
|
|
37
|
+
|
|
38
|
+
attr_reader :uri
|
|
39
|
+
|
|
40
|
+
def initialize(uri = nil)
|
|
41
|
+
@uri = uri || "https://supermarket.getchef.com"
|
|
42
|
+
@http_connections = {}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ==(other)
|
|
46
|
+
other.kind_of?(self.class) && other.uri == uri
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def universe_graph
|
|
50
|
+
@universe_graph ||= begin
|
|
51
|
+
full_community_graph.inject({}) do |normalized_graph, (cookbook_name, metadata_by_version)|
|
|
52
|
+
normalized_graph[cookbook_name] = metadata_by_version.inject({}) do |deps_by_version, (version, metadata)|
|
|
53
|
+
deps_by_version[version] = metadata["dependencies"]
|
|
54
|
+
deps_by_version
|
|
55
|
+
end
|
|
56
|
+
normalized_graph
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def source_options_for(cookbook_name, cookbook_version)
|
|
62
|
+
base_uri = full_community_graph[cookbook_name][cookbook_version]["download_url"]
|
|
63
|
+
{ artifactserver: base_uri, version: cookbook_version }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def http_connection_for(base_url)
|
|
69
|
+
@http_connections[base_url] ||= Chef::HTTP::Simple.new(base_url)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def full_community_graph
|
|
74
|
+
@full_community_graph ||=
|
|
75
|
+
begin
|
|
76
|
+
graph_json = http_connection_for(uri).get("/universe")
|
|
77
|
+
JSON.parse(graph_json)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef-dk/policyfile/null_cookbook_source'
|
|
19
|
+
require 'chef-dk/policyfile/community_cookbook_source'
|
|
20
|
+
require 'chef-dk/policyfile/chef_server_cookbook_source'
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'semverse'
|
|
19
|
+
require 'cookbook-omnifetch'
|
|
20
|
+
|
|
21
|
+
module ChefDK
|
|
22
|
+
module Policyfile
|
|
23
|
+
|
|
24
|
+
class CookbookSpec
|
|
25
|
+
|
|
26
|
+
SOURCE_TYPES = [:git, :github, :path, :artifactserver]
|
|
27
|
+
|
|
28
|
+
attr_reader :version_constraint
|
|
29
|
+
attr_reader :name
|
|
30
|
+
attr_reader :source_options
|
|
31
|
+
attr_reader :source_type
|
|
32
|
+
|
|
33
|
+
def initialize(name, version_constraint, source_options, policyfile_filename)
|
|
34
|
+
@name = name
|
|
35
|
+
@version_constraint = Semverse::Constraint.new(version_constraint)
|
|
36
|
+
@source_options = source_options
|
|
37
|
+
@policyfile_filename = policyfile_filename
|
|
38
|
+
@source_type = SOURCE_TYPES.find { |type| source_options.key?(type) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def ==(other)
|
|
42
|
+
other.kind_of?(self.class) and
|
|
43
|
+
other.name == name and
|
|
44
|
+
other.version_constraint == version_constraint and
|
|
45
|
+
other.source_options == source_options
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def mirrors_canonical_upstream?
|
|
49
|
+
[:git, :github, :artifactserver].include?(source_type)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def ensure_cached
|
|
53
|
+
unless installer.installed?
|
|
54
|
+
installer.install
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def installer
|
|
59
|
+
@installer ||= CookbookOmnifetch.init(self, source_options)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def cache_key
|
|
63
|
+
installer.cache_key
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def relative_path
|
|
67
|
+
installer.relative_path.to_s
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def uri
|
|
71
|
+
installer.uri
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def version_fixed?
|
|
75
|
+
[:git, :github, :path].include?(@source_type)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def version
|
|
79
|
+
cached_cookbook.version
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def dependencies
|
|
83
|
+
cached_cookbook.dependencies
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def cached_cookbook
|
|
87
|
+
installer.cached_cookbook
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def relative_paths_root
|
|
91
|
+
File.dirname(@policyfile_filename)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef-dk/policyfile/cookbook_sources'
|
|
19
|
+
require 'chef-dk/policyfile/cookbook_spec'
|
|
20
|
+
|
|
21
|
+
module ChefDK
|
|
22
|
+
module Policyfile
|
|
23
|
+
class DSL
|
|
24
|
+
|
|
25
|
+
attr_reader :errors
|
|
26
|
+
attr_reader :run_list
|
|
27
|
+
attr_reader :default_source
|
|
28
|
+
attr_reader :policyfile_cookbook_specs
|
|
29
|
+
|
|
30
|
+
attr_accessor :policyfile_filename
|
|
31
|
+
|
|
32
|
+
def initialize
|
|
33
|
+
@errors = []
|
|
34
|
+
@run_list = []
|
|
35
|
+
@default_source = NullCookbookSource.new
|
|
36
|
+
@policyfile_cookbook_specs = {}
|
|
37
|
+
@policyfile_filename = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def run_list(*run_list_items)
|
|
41
|
+
run_list_items = run_list_items.flatten
|
|
42
|
+
@run_list = run_list_items unless run_list_items.empty?
|
|
43
|
+
@run_list
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def default_source(source_type = nil, source_uri = nil)
|
|
47
|
+
return @default_source if source_type.nil?
|
|
48
|
+
case source_type
|
|
49
|
+
when :community
|
|
50
|
+
set_default_community_source(source_uri)
|
|
51
|
+
when :chef_server
|
|
52
|
+
set_default_chef_server_source(source_uri)
|
|
53
|
+
else
|
|
54
|
+
@errors << "Invalid default_source type '#{source_type.inspect}'"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def cookbook(name, *version_and_source_opts)
|
|
59
|
+
source_options =
|
|
60
|
+
if version_and_source_opts.last.is_a?(Hash)
|
|
61
|
+
version_and_source_opts.pop
|
|
62
|
+
else
|
|
63
|
+
{}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
constraint = version_and_source_opts.first || ">= 0.0.0"
|
|
67
|
+
spec = CookbookSpec.new(name, constraint, source_options, policyfile_filename)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if existing_source = @policyfile_cookbook_specs[name]
|
|
71
|
+
err = "Cookbook '#{name}' assigned to conflicting sources\n\n"
|
|
72
|
+
err << "Previous source: #{existing_source.source_options.inspect}\n"
|
|
73
|
+
err << "Conflicts with: #{source_options.inspect}\n"
|
|
74
|
+
@errors << err
|
|
75
|
+
else
|
|
76
|
+
@policyfile_cookbook_specs[name] = spec
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def eval_policyfile(policyfile_string, policyfile_filename)
|
|
81
|
+
@policyfile_filename = policyfile_filename
|
|
82
|
+
instance_eval(policyfile_string, policyfile_filename)
|
|
83
|
+
validate!
|
|
84
|
+
self
|
|
85
|
+
rescue SyntaxError => e
|
|
86
|
+
@errors << "Invalid ruby syntax in policyfile '#{policyfile_filename}':\n\n#{e.message}"
|
|
87
|
+
rescue SignalException, SystemExit
|
|
88
|
+
# allow signal from kill, ctrl-C, etc. to bubble up:
|
|
89
|
+
raise
|
|
90
|
+
rescue Exception => e
|
|
91
|
+
error_message = "Evaluation of policyfile '#{policyfile_filename}' raised an exception\n"
|
|
92
|
+
error_message << " Exception: #{e.class.name} \"#{e.to_s}\"\n\n"
|
|
93
|
+
trace = filtered_bt(policyfile_filename, e)
|
|
94
|
+
error_message << " Relevant Code:\n"
|
|
95
|
+
error_message << " #{error_context(policyfile_string, policyfile_filename, e)}\n\n"
|
|
96
|
+
unless trace.empty?
|
|
97
|
+
error_message << " Backtrace:\n"
|
|
98
|
+
error_message << filtered_bt(policyfile_filename, e).inject("") { |formatted_trace, line| formatted_trace << " #{line}" }
|
|
99
|
+
error_message << "\n"
|
|
100
|
+
end
|
|
101
|
+
@errors << error_message
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
def set_default_community_source(source_uri)
|
|
107
|
+
@default_source = CommunityCookbookSource.new(source_uri)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def set_default_chef_server_source(source_uri)
|
|
111
|
+
if source_uri.nil?
|
|
112
|
+
@errors << "You must specify the server's URI when using a default_source :chef_server"
|
|
113
|
+
else
|
|
114
|
+
@default_source = ChefServerCookbookSource.new(source_uri)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def validate!
|
|
119
|
+
if @run_list.empty?
|
|
120
|
+
@errors << "Invalid run_list. run_list cannot be empty"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def error_context(policyfile_string, policyfile_filename, exception)
|
|
125
|
+
if line_number_to_show = culprit_line_number(policyfile_filename, exception)
|
|
126
|
+
code = policyfile_string.lines.to_a[line_number_to_show - 1].strip
|
|
127
|
+
"#{line_number_to_show}: #{code}"
|
|
128
|
+
else
|
|
129
|
+
"Could not find relevant code from backtrace"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def culprit_line_number(policyfile_filename, exception)
|
|
134
|
+
if most_proximate_backtrace_line = filtered_bt(policyfile_filename, exception).first
|
|
135
|
+
most_proximate_backtrace_line[/^(?:.\:)?[^:]+:([\d]+)/,1].to_i
|
|
136
|
+
else
|
|
137
|
+
nil
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def filtered_bt(policyfile_filename, exception)
|
|
142
|
+
policyfile_filename_matcher = /^#{Regexp.escape(policyfile_filename)}/
|
|
143
|
+
exception.backtrace.select {|line| line =~ policyfile_filename_matcher }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef-dk/exceptions'
|
|
19
|
+
|
|
20
|
+
module ChefDK
|
|
21
|
+
module Policyfile
|
|
22
|
+
class NullCookbookSource
|
|
23
|
+
|
|
24
|
+
def initialize(_uri=nil)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def universe_graph
|
|
28
|
+
{}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def source_options_for(cookbook_name, cookbook_version)
|
|
32
|
+
raise UnsupportedFeature, 'You must set a default_source in your Policyfile to download cookbooks without explicit sources'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'forwardable'
|
|
19
|
+
|
|
20
|
+
require 'solve'
|
|
21
|
+
require 'chef/run_list/run_list_item'
|
|
22
|
+
|
|
23
|
+
require 'chef-dk/policyfile/dsl'
|
|
24
|
+
require 'chef-dk/policyfile_lock'
|
|
25
|
+
|
|
26
|
+
module ChefDK
|
|
27
|
+
|
|
28
|
+
class PolicyfileCompiler
|
|
29
|
+
|
|
30
|
+
extend Forwardable
|
|
31
|
+
|
|
32
|
+
DEFAULT_DEMAND_CONSTRAINT = '>= 0.0.0'.freeze
|
|
33
|
+
|
|
34
|
+
# Cookbooks from these sources lock that cookbook to exactly one version
|
|
35
|
+
SOURCE_TYPES_WITH_FIXED_VERSIONS = [:git, :path].freeze
|
|
36
|
+
|
|
37
|
+
def self.evaluate(policyfile_string, policyfile_filename)
|
|
38
|
+
compiler = new
|
|
39
|
+
compiler.evaluate_policyfile(policyfile_string, policyfile_filename)
|
|
40
|
+
compiler
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def_delegator :@dsl, :run_list
|
|
44
|
+
def_delegator :@dsl, :errors
|
|
45
|
+
def_delegator :@dsl, :default_source
|
|
46
|
+
def_delegator :@dsl, :policyfile_cookbook_specs
|
|
47
|
+
|
|
48
|
+
attr_reader :dsl
|
|
49
|
+
|
|
50
|
+
def initialize
|
|
51
|
+
@dsl = Policyfile::DSL.new
|
|
52
|
+
@artifact_server_cookbook_specs = {}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def error!
|
|
56
|
+
unless errors.empty?
|
|
57
|
+
raise PolicyfileError, errors.join("\n")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def cookbook_spec_for(cookbook_name)
|
|
62
|
+
policyfile_cookbook_specs[cookbook_name]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def expanded_run_list
|
|
66
|
+
run_list
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def lock
|
|
70
|
+
@policyfile_lock ||= PolicyfileLock.build_from_compiler(self, cache_path: cache_path)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def install
|
|
74
|
+
ensure_cache_dir_exists
|
|
75
|
+
|
|
76
|
+
graph_solution.each do |cookbook_name, version|
|
|
77
|
+
spec = cookbook_spec_for(cookbook_name)
|
|
78
|
+
if spec.nil? or !spec.version_fixed?
|
|
79
|
+
spec = create_spec_for_cookbook(cookbook_name, version)
|
|
80
|
+
spec.ensure_cached
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def create_spec_for_cookbook(cookbook_name, version)
|
|
86
|
+
source_options = default_source.source_options_for(cookbook_name, version)
|
|
87
|
+
spec = Policyfile::CookbookSpec.new(cookbook_name, "= #{version}", source_options, dsl)
|
|
88
|
+
@artifact_server_cookbook_specs[cookbook_name] = spec
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def all_cookbook_specs
|
|
92
|
+
# in the installation proces, we create "artifact_server_cookbook_specs"
|
|
93
|
+
# for any cookbook that isn't sourced from a single-version source (e.g.,
|
|
94
|
+
# path and git only support one version at a time), but we might have
|
|
95
|
+
# specs for them to track additional version constraint demands. Merging
|
|
96
|
+
# in this order ensures the artifact_server_cookbook_specs "win".
|
|
97
|
+
policyfile_cookbook_specs.merge(@artifact_server_cookbook_specs)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# Compilation Methods
|
|
102
|
+
##
|
|
103
|
+
|
|
104
|
+
def graph_solution
|
|
105
|
+
return @solution if @solution
|
|
106
|
+
cache_fixed_version_cookbooks
|
|
107
|
+
@solution = Solve.it!(graph, graph_demands)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def graph
|
|
111
|
+
@graph ||= Solve::Graph.new.tap do |g|
|
|
112
|
+
artifacts_graph.each do |name, dependencies_by_version|
|
|
113
|
+
dependencies_by_version.each do |version, dependencies|
|
|
114
|
+
artifact = g.artifact(name, version)
|
|
115
|
+
dependencies.each do |dep_name, constraint|
|
|
116
|
+
artifact.dependency(dep_name, constraint)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def graph_demands
|
|
124
|
+
cookbooks_for_demands.map do |cookbook_name|
|
|
125
|
+
spec = cookbook_spec_for(cookbook_name)
|
|
126
|
+
if spec.nil?
|
|
127
|
+
[ cookbook_name, DEFAULT_DEMAND_CONSTRAINT ]
|
|
128
|
+
elsif spec.version_fixed?
|
|
129
|
+
[ cookbook_name, "= #{spec.version}" ]
|
|
130
|
+
else
|
|
131
|
+
[ cookbook_name, spec.version_constraint.to_s ]
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def artifacts_graph
|
|
137
|
+
remote_artifacts_graph.merge(local_artifacts_graph)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Gives a dependency graph for cookbooks that are source from an alternate
|
|
141
|
+
# location. These cookbooks could have a different set of dependencies
|
|
142
|
+
# compared to an unmodified copy upstream. For example, the community site
|
|
143
|
+
# may have a cookbook "apache2" at version "1.10.4", which the user has
|
|
144
|
+
# forked on github and modified the dependencies without changing the
|
|
145
|
+
# version number. To accomodate this, the local_artifacts_graph should be
|
|
146
|
+
# merged over the upstream's artifacts graph.
|
|
147
|
+
def local_artifacts_graph
|
|
148
|
+
policyfile_cookbook_specs.inject({}) do |local_artifacts, (cookbook_name, cookbook_spec)|
|
|
149
|
+
if cookbook_spec.version_fixed?
|
|
150
|
+
local_artifacts[cookbook_name] = { cookbook_spec.version => cookbook_spec.dependencies }
|
|
151
|
+
end
|
|
152
|
+
local_artifacts
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def remote_artifacts_graph
|
|
157
|
+
default_source.universe_graph
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def version_constraint_for(cookbook_name)
|
|
161
|
+
if (cookbook_spec = cookbook_spec_for(cookbook_name)) and cookbook_spec.version_fixed?
|
|
162
|
+
version = cookbook_spec.version
|
|
163
|
+
"= #{version}"
|
|
164
|
+
else
|
|
165
|
+
DEFAULT_DEMAND_CONSTRAINT
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def cookbook_version_fixed?(cookbook_name)
|
|
170
|
+
if cookbook_spec = cookbook_spec_for(cookbook_name)
|
|
171
|
+
cookbook_spec.version_fixed?
|
|
172
|
+
else
|
|
173
|
+
false
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def cookbooks_in_run_list
|
|
178
|
+
run_list.map {|item_spec| Chef::RunList::RunListItem.new(item_spec).name }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def build
|
|
182
|
+
yield @dsl
|
|
183
|
+
self
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def evaluate_policyfile(policyfile_string, policyfile_filename)
|
|
187
|
+
@dsl.eval_policyfile(policyfile_string, policyfile_filename)
|
|
188
|
+
self
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
private
|
|
192
|
+
|
|
193
|
+
def cookbooks_for_demands
|
|
194
|
+
(cookbooks_in_run_list + policyfile_cookbook_specs.keys).uniq
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def cache_fixed_version_cookbooks
|
|
198
|
+
ensure_cache_dir_exists
|
|
199
|
+
|
|
200
|
+
policyfile_cookbook_specs.each do |_cookbook_name, cookbook_spec|
|
|
201
|
+
cookbook_spec.ensure_cached if cookbook_spec.version_fixed?
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def ensure_cache_dir_exists
|
|
206
|
+
unless File.exist?(cache_path)
|
|
207
|
+
FileUtils.mkdir_p(cache_path)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def cache_path
|
|
212
|
+
CookbookOmnifetch.storage_path
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
end
|
|
217
|
+
end
|