chef-dk 0.2.0 → 0.2.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/chef-dk/authenticated_http.rb +40 -0
  4. data/lib/chef-dk/chef_runner.rb +5 -0
  5. data/lib/chef-dk/command/exec.rb +4 -1
  6. data/lib/chef-dk/command/generate.rb +11 -0
  7. data/lib/chef-dk/command/generator_commands.rb +20 -365
  8. data/lib/chef-dk/command/generator_commands/app.rb +99 -0
  9. data/lib/chef-dk/command/generator_commands/attribute.rb +37 -0
  10. data/lib/chef-dk/command/generator_commands/base.rb +76 -0
  11. data/lib/chef-dk/command/generator_commands/cookbook.rb +100 -0
  12. data/lib/chef-dk/command/generator_commands/cookbook_code_file.rb +99 -0
  13. data/lib/chef-dk/command/generator_commands/cookbook_file.rb +45 -0
  14. data/lib/chef-dk/command/generator_commands/lwrp.rb +36 -0
  15. data/lib/chef-dk/command/generator_commands/recipe.rb +36 -0
  16. data/lib/chef-dk/command/generator_commands/repo.rb +96 -0
  17. data/lib/chef-dk/command/generator_commands/template.rb +45 -0
  18. data/lib/chef-dk/command/verify.rb +28 -0
  19. data/lib/chef-dk/component_test.rb +16 -3
  20. data/lib/chef-dk/cookbook_omnifetch.rb +2 -0
  21. data/lib/chef-dk/cookbook_profiler/identifiers.rb +3 -15
  22. data/lib/chef-dk/exceptions.rb +15 -0
  23. data/lib/chef-dk/generator.rb +102 -25
  24. data/lib/chef-dk/policyfile/community_cookbook_source.rb +0 -7
  25. data/lib/chef-dk/policyfile/{cookbook_spec.rb → cookbook_location_specification.rb} +35 -6
  26. data/lib/chef-dk/policyfile/cookbook_locks.rb +305 -0
  27. data/lib/chef-dk/policyfile/dsl.rb +26 -12
  28. data/lib/chef-dk/policyfile/read_cookbook_for_compat_mode_upload.rb +70 -0
  29. data/lib/chef-dk/policyfile/solution_dependencies.rb +204 -0
  30. data/lib/chef-dk/policyfile/storage_config.rb +77 -0
  31. data/lib/chef-dk/policyfile/uploader.rb +110 -0
  32. data/lib/chef-dk/policyfile_compiler.rb +59 -29
  33. data/lib/chef-dk/policyfile_lock.rb +104 -160
  34. data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +1 -1
  35. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +0 -1
  36. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +66 -0
  37. data/lib/chef-dk/skeletons/code_generator/files/default/repo/Rakefile +65 -0
  38. data/lib/chef-dk/skeletons/code_generator/files/default/repo/certificates/README.md +19 -0
  39. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/README-policy.md +9 -0
  40. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/README.md +54 -0
  41. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/README.md +63 -0
  42. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +5 -0
  43. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/README.md +16 -0
  44. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +7 -1
  45. data/lib/chef-dk/skeletons/code_generator/recipes/repo.rb +62 -0
  46. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -0
  47. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.apache2.erb +201 -0
  48. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -0
  49. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -0
  50. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -0
  51. data/lib/chef-dk/skeletons/code_generator/templates/default/default_recipe.rb.erb +1 -4
  52. data/lib/chef-dk/skeletons/code_generator/templates/default/metadata.rb.erb +3 -3
  53. data/lib/chef-dk/skeletons/code_generator/templates/default/repo/config/rake.rb.erb +38 -0
  54. data/lib/chef-dk/skeletons/code_generator/templates/default/repo/gitignore.erb +11 -0
  55. data/lib/chef-dk/version.rb +1 -1
  56. data/spec/shared/a_file_generator.rb +121 -0
  57. data/spec/shared/a_generated_file.rb +12 -0
  58. data/spec/shared/fixture_cookbook_checksums.rb +47 -0
  59. data/spec/spec_helper.rb +4 -2
  60. data/spec/unit/chef_runner_spec.rb +12 -5
  61. data/spec/unit/cli_spec.rb +4 -4
  62. data/spec/unit/command/base_spec.rb +1 -1
  63. data/spec/unit/command/exec_spec.rb +37 -27
  64. data/spec/unit/command/generate_spec.rb +3 -3
  65. data/spec/unit/command/generator_commands/app_spec.rb +131 -0
  66. data/spec/unit/command/generator_commands/attribute_spec.rb +32 -0
  67. data/spec/unit/command/generator_commands/cookbook_file_spec.rb +32 -0
  68. data/spec/unit/command/generator_commands/cookbook_spec.rb +205 -0
  69. data/spec/unit/command/generator_commands/lwrp_spec.rb +32 -0
  70. data/spec/unit/command/generator_commands/recipe_spec.rb +32 -0
  71. data/spec/unit/command/generator_commands/repo_spec.rb +287 -0
  72. data/spec/unit/command/generator_commands/template_spec.rb +32 -0
  73. data/spec/unit/command/shell_init_spec.rb +4 -4
  74. data/spec/unit/command/verify_spec.rb +9 -9
  75. data/spec/unit/commands_map_spec.rb +1 -1
  76. data/spec/unit/component_test_spec.rb +3 -3
  77. data/spec/unit/cookbook_profiler/git_spec.rb +7 -7
  78. data/spec/unit/cookbook_profiler/identifiers_spec.rb +12 -8
  79. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +1 -1
  80. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +1 -1
  81. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +1 -1
  82. data/spec/unit/fixtures/example_cookbook/Berksfile +1 -1
  83. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/README.md +4 -0
  84. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/chefignore +96 -0
  85. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/metadata.rb +8 -0
  86. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/recipes/default.rb +8 -0
  87. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +1 -1
  88. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -0
  89. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -0
  90. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -0
  91. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -0
  92. data/spec/unit/generator_spec.rb +120 -0
  93. data/spec/unit/policyfile/{cookbook_spec_spec.rb → cookbook_location_specification_spec.rb} +83 -38
  94. data/spec/unit/policyfile/cookbook_locks_spec.rb +354 -0
  95. data/spec/unit/policyfile/read_cookbook_for_compat_mode_upload_spec.rb +85 -0
  96. data/spec/unit/policyfile/solution_dependencies_spec.rb +145 -0
  97. data/spec/unit/policyfile/storage_config_spec.rb +98 -0
  98. data/spec/unit/policyfile/uploader_spec.rb +292 -0
  99. data/spec/unit/policyfile_demands_spec.rb +177 -24
  100. data/spec/unit/policyfile_evaluation_spec.rb +40 -12
  101. data/spec/unit/{policyfile_builder_spec.rb → policyfile_lock_build_spec.rb} +179 -64
  102. data/spec/unit/policyfile_lock_install_spec.rb +138 -0
  103. data/spec/unit/policyfile_lock_validation_spec.rb +610 -0
  104. metadata +103 -59
  105. data/spec/unit/command/generator_commands_spec.rb +0 -504
@@ -0,0 +1,70 @@
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/cookbook/cookbook_version_loader'
19
+
20
+ require 'chef/cookbook/chefignore'
21
+
22
+ module ChefDK
23
+ module Policyfile
24
+ class ReadCookbookForCompatModeUpload
25
+
26
+ # Convenience method to load a cookbook, set up name and version overrides
27
+ # as necessary, and return a Chef::CookbookVersion object.
28
+ def self.load(name, version_override, directory_path)
29
+ new(name, version_override, directory_path).cookbook_version
30
+ end
31
+
32
+ attr_reader :cookbook_name
33
+ attr_reader :directory_path
34
+ attr_reader :version_override
35
+
36
+ def initialize(cookbook_name, version_override, directory_path)
37
+ @cookbook_name = cookbook_name
38
+ @version_override = version_override
39
+ @directory_path = directory_path
40
+
41
+ @cookbook_version = nil
42
+ @loader = nil
43
+ end
44
+
45
+ def cookbook_version
46
+ @cookbook_version ||=
47
+ begin
48
+ cookbook_version = loader.cookbook_version
49
+ cookbook_version.version = version_override
50
+ cookbook_version.freeze_version
51
+ cookbook_version
52
+ end
53
+ end
54
+
55
+ def loader
56
+ @loader ||=
57
+ begin
58
+ cbvl = Chef::Cookbook::CookbookVersionLoader.new(directory_path, chefignore)
59
+ cbvl.load!
60
+ cbvl
61
+ end
62
+ end
63
+
64
+ def chefignore
65
+ @chefignore ||= Chef::Cookbook::Chefignore.new(File.join(directory_path, "chefignore"))
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,204 @@
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
+
20
+ require 'chef-dk/exceptions'
21
+
22
+ module ChefDK
23
+ module Policyfile
24
+
25
+ class SolutionDependencies
26
+
27
+ Cookbook = Struct.new(:name, :version)
28
+
29
+ class Cookbook
30
+
31
+ def self.parse(str)
32
+ name, version_w_parens = str.split(' ')
33
+ version = version_w_parens[/\(([^)]+)\)/, 1]
34
+ new(name, version)
35
+ end
36
+
37
+ def to_s
38
+ "#{name} (#{version})"
39
+ end
40
+
41
+ def eql?(other)
42
+ other.kind_of?(self.class) and
43
+ other.name == name and
44
+ other.version == version
45
+ end
46
+
47
+ def hash
48
+ [name, version].hash
49
+ end
50
+
51
+ end
52
+
53
+ def self.from_lock(lock_data)
54
+ new.tap {|e| e.consume_lock_data(lock_data) }
55
+ end
56
+
57
+ attr_reader :policyfile_dependencies
58
+
59
+ attr_reader :cookbook_dependencies
60
+
61
+ def initialize
62
+ @policyfile_dependencies = []
63
+ @cookbook_dependencies = {}
64
+ end
65
+
66
+ def add_policyfile_dep(cookbook, constraint)
67
+ @policyfile_dependencies << [ cookbook, Semverse::Constraint.new(constraint) ]
68
+ end
69
+
70
+ def add_cookbook_dep(cookbook_name, version, dependency_list)
71
+ cookbook = Cookbook.new(cookbook_name, version)
72
+ add_cookbook_obj_dep(cookbook, dependency_list)
73
+ end
74
+
75
+ def update_cookbook_dep(cookbook_name, new_version, new_dependency_list)
76
+ @cookbook_dependencies.delete_if { |cb, _deps| cb.name == cookbook_name }
77
+ add_cookbook_dep(cookbook_name, new_version, new_dependency_list)
78
+ end
79
+
80
+ def consume_lock_data(lock_data)
81
+ policyfile_dependencies_data = lock_data["Policyfile"] || []
82
+ policyfile_dependencies_data.each do |cookbook_name, constraint|
83
+ add_policyfile_dep(cookbook_name, constraint)
84
+ end
85
+ cookbook_dependencies_data = lock_data["dependencies"] || {}
86
+ cookbook_dependencies_data.each do |name_and_version, deps_list|
87
+ cookbook = Cookbook.parse(name_and_version)
88
+ add_cookbook_obj_dep(cookbook, deps_list)
89
+ end
90
+ end
91
+
92
+ def test_conflict!(cookbook_name, version)
93
+ unless have_cookbook_dep?(cookbook_name, version)
94
+ raise CookbookNotInWorkingSet, "Cookbook #{cookbook_name} (#{version}) not in the working set, cannot test for conflicts"
95
+ end
96
+
97
+ assert_cookbook_version_valid!(cookbook_name, version)
98
+ assert_cookbook_deps_valid!(cookbook_name, version)
99
+ end
100
+
101
+ def to_lock
102
+ { "Policyfile" => policyfile_dependencies_for_lock, "dependencies" => cookbook_deps_for_lock }
103
+ end
104
+
105
+ def policyfile_dependencies_for_lock
106
+ policyfile_dependencies.map do |name, constraint|
107
+ [ name, constraint.to_s ]
108
+ end
109
+ end
110
+
111
+ def cookbook_deps_for_lock
112
+ cookbook_dependencies.inject({}) do |map, (cookbook, deps)|
113
+ map[cookbook.to_s] = deps.map do |name, constraint|
114
+ [ name, constraint.to_s ]
115
+ end
116
+ map
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def add_cookbook_obj_dep(cookbook, dependency_map)
123
+ @cookbook_dependencies[cookbook] = dependency_map.map do |dep_name, constraint|
124
+ [ dep_name, Semverse::Constraint.new(constraint) ]
125
+ end
126
+ end
127
+
128
+ def assert_cookbook_version_valid!(cookbook_name, version)
129
+ policyfile_conflicts = policyfile_conflicts_with(cookbook_name, version)
130
+ cookbook_conflicts = cookbook_conflicts_with(cookbook_name, version)
131
+ all_conflicts = policyfile_conflicts + cookbook_conflicts
132
+
133
+ return false if all_conflicts.empty?
134
+
135
+ details = all_conflicts.map { |source, name, constraint| "#{source} depends on #{name} #{constraint}" }
136
+ message = "Cookbook #{cookbook_name} (#{version}) conflicts with other dependencies:\n"
137
+ full_message = message + details.join("\n")
138
+ raise DependencyConflict, full_message
139
+ end
140
+
141
+ def assert_cookbook_deps_valid!(cookbook_name, version)
142
+ dependency_conflicts = cookbook_deps_conflicts_for(cookbook_name, version)
143
+ return false if dependency_conflicts.empty?
144
+ message = "Cookbook #{cookbook_name} (#{version}) has dependency constraints that cannot be met by the existing cookbook set:\n"
145
+ full_message = message + dependency_conflicts.join("\n")
146
+ raise DependencyConflict, full_message
147
+ end
148
+
149
+ def policyfile_conflicts_with(cookbook_name, version)
150
+ policyfile_conflicts = []
151
+
152
+ @policyfile_dependencies.each do |dep_name, constraint|
153
+ if dep_name == cookbook_name and !constraint.satisfies?(version)
154
+ policyfile_conflicts << ['Policyfile', dep_name, constraint]
155
+ end
156
+ end
157
+
158
+ policyfile_conflicts
159
+ end
160
+
161
+ def cookbook_conflicts_with(cookbook_name, version)
162
+ cookbook_conflicts = []
163
+
164
+ @cookbook_dependencies.each do |top_level_dep_name, dependencies|
165
+ dependencies.each do |dep_name, constraint|
166
+ if dep_name == cookbook_name and !constraint.satisfies?(version)
167
+ cookbook_conflicts << [top_level_dep_name, dep_name, constraint]
168
+ end
169
+ end
170
+ end
171
+
172
+ cookbook_conflicts
173
+ end
174
+
175
+ def cookbook_deps_conflicts_for(cookbook_name, version)
176
+ conflicts = []
177
+ transitive_deps = find_cookbook_dep_by_name_and_version(cookbook_name, version)
178
+ transitive_deps.each do |name, constraint|
179
+ existing_cookbook = find_cookbook_dep_by_name(name)
180
+ if existing_cookbook.nil?
181
+ conflicts << "Cookbook #{name} isn't included in the existing cookbook set."
182
+ elsif !constraint.satisfies?(existing_cookbook[0].version)
183
+ conflicts << "Dependency on #{name} #{constraint} conflicts with existing version #{existing_cookbook[0]}"
184
+ end
185
+ end
186
+ conflicts
187
+ end
188
+
189
+ def have_cookbook_dep?(name, version)
190
+ @cookbook_dependencies.key?(Cookbook.new(name, version))
191
+ end
192
+
193
+ def find_cookbook_dep_by_name(name)
194
+ @cookbook_dependencies.find { |k,v| k.name == name }
195
+ end
196
+
197
+ def find_cookbook_dep_by_name_and_version(name, version)
198
+ @cookbook_dependencies[Cookbook.new(name, version)]
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+ end
@@ -0,0 +1,77 @@
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/cookbook_omnifetch'
19
+
20
+ module ChefDK
21
+ module Policyfile
22
+
23
+ class StorageConfig
24
+
25
+ attr_accessor :relative_paths_root
26
+ attr_accessor :cache_path
27
+
28
+ attr_reader :policyfile_filename
29
+ attr_reader :policyfile_lock_filename
30
+
31
+ def initialize(options = {})
32
+ @relative_paths_root = Dir.pwd
33
+ @cache_path = CookbookOmnifetch.storage_path
34
+ @policyfile_filename = "<< Policyfile filename not specified >>"
35
+ @policyfile_lock_filename = "<< Policyfile lock filename not specified >>"
36
+ handle_options(options)
37
+ end
38
+
39
+ def use_policyfile(policyfile_filename)
40
+ @policyfile_filename = policyfile_filename
41
+ @relative_paths_root = File.dirname(policyfile_filename)
42
+ self
43
+ end
44
+
45
+ def use_policyfile_lock(policyfile_lock_filename)
46
+ @policyfile_lock_filename = policyfile_lock_filename
47
+ @relative_paths_root = File.dirname(policyfile_lock_filename)
48
+ self
49
+ end
50
+
51
+ private
52
+
53
+ def handle_options(options)
54
+ @cache_path = options[:cache_path] if options[:cache_path]
55
+ @relative_paths_root = options[:relative_paths_root] if options.key?(:relative_paths_root)
56
+ end
57
+ end
58
+
59
+ module StorageConfigDelegation
60
+
61
+ def cache_path
62
+ storage_config.cache_path
63
+ end
64
+
65
+ def relative_paths_root
66
+ storage_config.relative_paths_root
67
+ end
68
+
69
+ def policyfile_filename
70
+ storage_config.policyfile_filename
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+ end
77
+
@@ -0,0 +1,110 @@
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/cookbook_uploader'
19
+ require 'chef-dk/policyfile/read_cookbook_for_compat_mode_upload'
20
+
21
+ module ChefDK
22
+ module Policyfile
23
+ class Uploader
24
+
25
+ COMPAT_MODE_DATA_BAG_NAME = "policyfiles".freeze
26
+
27
+ attr_reader :policyfile_lock
28
+ attr_reader :policy_group
29
+ attr_reader :http_client
30
+
31
+ def initialize(policyfile_lock, policy_group, http_client: nil)
32
+ @policyfile_lock = policyfile_lock
33
+ @policy_group = policy_group
34
+ @http_client = http_client
35
+ end
36
+
37
+ def upload
38
+ uploader.upload_cookbooks
39
+ data_bag_create
40
+ data_bag_item_create
41
+ end
42
+
43
+ def data_bag_create
44
+ http_client.post("data", {"name" => COMPAT_MODE_DATA_BAG_NAME})
45
+ rescue Net::HTTPServerException => e
46
+ raise e unless e.response.code == "409"
47
+ end
48
+
49
+ def data_bag_item_create
50
+ policy_id = "#{policyfile_lock.name}-#{policy_group}"
51
+ lock_data = policyfile_lock.to_lock.dup
52
+
53
+ lock_data["id"] = policy_id
54
+
55
+ data_item = {
56
+ "id" => policy_id,
57
+ "name" => "data_bag_item_#{COMPAT_MODE_DATA_BAG_NAME}_#{policy_id}",
58
+ "data_bag" => COMPAT_MODE_DATA_BAG_NAME,
59
+ "raw_data" => lock_data,
60
+ # we'd prefer to leave this out, but the "compatibility mode"
61
+ # implementation in chef-client relies on magical class inflation
62
+ "json_class" => "Chef::DataBagItem"
63
+ }
64
+
65
+ upload_lockfile_as_data_bag_item(policy_id, data_item)
66
+ end
67
+
68
+ def uploader
69
+ # TODO: uploader runs cookbook validation; we want to do this at a different time.
70
+ @uploader ||= Chef::CookbookUploader.new(cookbook_versions_to_upload, :rest => http_client)
71
+ end
72
+
73
+ def cookbook_versions_to_upload
74
+ cookbook_versions_for_policy.reject do |cookbook|
75
+ remote_already_has_cookbook?(cookbook)
76
+ end
77
+ end
78
+
79
+ def remote_already_has_cookbook?(cookbook)
80
+ return false unless existing_cookbook_on_remote.key?(cookbook.name.to_s)
81
+
82
+ existing_cookbook_on_remote[cookbook.name.to_s]["versions"].any? do |cookbook_info|
83
+ cookbook_info["version"] == cookbook.version
84
+ end
85
+ end
86
+
87
+ def existing_cookbook_on_remote
88
+ @existing_cookbook_on_remote ||= http_client.get('cookbooks?num_versions=all')
89
+ end
90
+
91
+ # An Array of Chef::CookbookVersion objects representing the full set that
92
+ # the policyfile lock requires.
93
+ def cookbook_versions_for_policy
94
+ policyfile_lock.validate_cookbooks!
95
+ policyfile_lock.cookbook_locks.map do |name, lock|
96
+ ReadCookbookForCompatModeUpload.load(name, lock.dotted_decimal_identifier, lock.cookbook_path)
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def upload_lockfile_as_data_bag_item(policy_id, data_item)
103
+ http_client.put("data/#{COMPAT_MODE_DATA_BAG_NAME}/#{policy_id}", data_item)
104
+ rescue Net::HTTPServerException => e
105
+ raise e unless e.response.code == "404"
106
+ http_client.post("data/#{COMPAT_MODE_DATA_BAG_NAME}", data_item)
107
+ end
108
+ end
109
+ end
110
+ end