chef-dk 0.8.0 → 0.9.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.
Files changed (299) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +190 -190
  3. data/Gemfile +26 -0
  4. data/LICENSE +201 -201
  5. data/README.md +276 -276
  6. data/Rakefile +18 -18
  7. data/bin/chef +25 -25
  8. data/lib/chef-dk.rb +19 -19
  9. data/lib/chef-dk/authenticated_http.rb +40 -40
  10. data/lib/chef-dk/builtin_commands.rb +60 -60
  11. data/lib/chef-dk/chef_runner.rb +98 -98
  12. data/lib/chef-dk/cli.rb +200 -200
  13. data/lib/chef-dk/command/base.rb +79 -75
  14. data/lib/chef-dk/command/clean_policy_cookbooks.rb +116 -116
  15. data/lib/chef-dk/command/clean_policy_revisions.rb +113 -113
  16. data/lib/chef-dk/command/delete_policy.rb +122 -122
  17. data/lib/chef-dk/command/delete_policy_group.rb +122 -122
  18. data/lib/chef-dk/command/diff.rb +316 -316
  19. data/lib/chef-dk/command/env.rb +90 -90
  20. data/lib/chef-dk/command/exec.rb +45 -45
  21. data/lib/chef-dk/command/export.rb +151 -153
  22. data/lib/chef-dk/command/gem.rb +47 -47
  23. data/lib/chef-dk/command/generate.rb +120 -118
  24. data/lib/chef-dk/command/generator_commands.rb +80 -80
  25. data/lib/chef-dk/command/generator_commands/app.rb +107 -107
  26. data/lib/chef-dk/command/generator_commands/attribute.rb +37 -37
  27. data/lib/chef-dk/command/generator_commands/base.rb +121 -121
  28. data/lib/chef-dk/command/generator_commands/cookbook.rb +119 -108
  29. data/lib/chef-dk/command/generator_commands/cookbook_code_file.rb +100 -100
  30. data/lib/chef-dk/command/generator_commands/cookbook_file.rb +45 -45
  31. data/lib/chef-dk/command/generator_commands/generator_generator.rb +177 -0
  32. data/lib/chef-dk/command/generator_commands/lwrp.rb +36 -36
  33. data/lib/chef-dk/command/generator_commands/policyfile.rb +86 -83
  34. data/lib/chef-dk/command/generator_commands/recipe.rb +36 -36
  35. data/lib/chef-dk/command/generator_commands/repo.rb +96 -96
  36. data/lib/chef-dk/command/generator_commands/template.rb +46 -46
  37. data/lib/chef-dk/command/install.rb +121 -121
  38. data/lib/chef-dk/command/provision.rb +438 -438
  39. data/lib/chef-dk/command/push.rb +118 -118
  40. data/lib/chef-dk/command/push_archive.rb +126 -126
  41. data/lib/chef-dk/command/shell_init.rb +180 -180
  42. data/lib/chef-dk/command/show_policy.rb +165 -165
  43. data/lib/chef-dk/command/undelete.rb +155 -155
  44. data/lib/chef-dk/command/update.rb +129 -129
  45. data/lib/chef-dk/command/verify.rb +490 -453
  46. data/lib/chef-dk/commands_map.rb +115 -115
  47. data/lib/chef-dk/completions/bash.sh.erb +5 -5
  48. data/lib/chef-dk/completions/chef.fish.erb +10 -10
  49. data/lib/chef-dk/completions/zsh.zsh.erb +21 -21
  50. data/lib/chef-dk/component_test.rb +171 -171
  51. data/lib/chef-dk/configurable.rb +57 -52
  52. data/lib/chef-dk/cookbook_metadata.rb +45 -45
  53. data/lib/chef-dk/cookbook_omnifetch.rb +32 -32
  54. data/lib/chef-dk/cookbook_profiler/git.rb +151 -151
  55. data/lib/chef-dk/cookbook_profiler/identifiers.rb +72 -72
  56. data/lib/chef-dk/cookbook_profiler/null_scm.rb +32 -32
  57. data/lib/chef-dk/exceptions.rb +113 -113
  58. data/lib/chef-dk/generator.rb +163 -162
  59. data/lib/chef-dk/helpers.rb +159 -159
  60. data/lib/chef-dk/pager.rb +106 -106
  61. data/lib/chef-dk/policyfile/chef_repo_cookbook_source.rb +122 -122
  62. data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +54 -54
  63. data/lib/chef-dk/policyfile/community_cookbook_source.rb +82 -82
  64. data/lib/chef-dk/policyfile/comparison_base.rb +124 -124
  65. data/lib/chef-dk/policyfile/cookbook_location_specification.rb +133 -133
  66. data/lib/chef-dk/policyfile/cookbook_locks.rb +466 -466
  67. data/lib/chef-dk/policyfile/cookbook_sources.rb +21 -21
  68. data/lib/chef-dk/policyfile/differ.rb +266 -266
  69. data/lib/chef-dk/policyfile/dsl.rb +197 -197
  70. data/lib/chef-dk/policyfile/lister.rb +232 -232
  71. data/lib/chef-dk/policyfile/null_cookbook_source.rb +45 -45
  72. data/lib/chef-dk/policyfile/read_cookbook_for_compat_mode_upload.rb +124 -124
  73. data/lib/chef-dk/policyfile/reports/install.rb +70 -70
  74. data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -58
  75. data/lib/chef-dk/policyfile/reports/upload.rb +70 -70
  76. data/lib/chef-dk/policyfile/solution_dependencies.rb +298 -298
  77. data/lib/chef-dk/policyfile/storage_config.rb +100 -100
  78. data/lib/chef-dk/policyfile/undo_record.rb +142 -142
  79. data/lib/chef-dk/policyfile/undo_stack.rb +130 -130
  80. data/lib/chef-dk/policyfile/uploader.rb +213 -213
  81. data/lib/chef-dk/policyfile_compiler.rb +322 -322
  82. data/lib/chef-dk/policyfile_lock.rb +552 -552
  83. data/lib/chef-dk/policyfile_services/clean_policies.rb +95 -95
  84. data/lib/chef-dk/policyfile_services/clean_policy_cookbooks.rb +125 -125
  85. data/lib/chef-dk/policyfile_services/export_repo.rb +309 -281
  86. data/lib/chef-dk/policyfile_services/install.rb +125 -125
  87. data/lib/chef-dk/policyfile_services/push.rb +114 -114
  88. data/lib/chef-dk/policyfile_services/push_archive.rb +173 -173
  89. data/lib/chef-dk/policyfile_services/rm_policy.rb +142 -142
  90. data/lib/chef-dk/policyfile_services/rm_policy_group.rb +86 -86
  91. data/lib/chef-dk/policyfile_services/show_policy.rb +237 -237
  92. data/lib/chef-dk/policyfile_services/undelete.rb +108 -108
  93. data/lib/chef-dk/policyfile_services/update_attributes.rb +104 -104
  94. data/lib/chef-dk/service_exception_inspectors.rb +25 -25
  95. data/lib/chef-dk/service_exception_inspectors/base.rb +40 -40
  96. data/lib/chef-dk/service_exception_inspectors/http.rb +121 -121
  97. data/lib/chef-dk/service_exceptions.rb +143 -143
  98. data/lib/chef-dk/shell_out.rb +36 -36
  99. data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +3 -3
  100. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +100 -100
  101. data/lib/chef-dk/skeletons/code_generator/files/default/cookbook_readmes/README-policy.md +9 -9
  102. data/lib/chef-dk/skeletons/code_generator/files/default/cookbook_readmes/README.md +54 -54
  103. data/lib/chef-dk/skeletons/code_generator/files/default/gitignore +16 -16
  104. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +28 -28
  105. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/README.md +27 -0
  106. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -7
  107. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +3 -3
  108. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -8
  109. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/README.md +57 -57
  110. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +3 -3
  111. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +9 -9
  112. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/example.json +12 -12
  113. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/README.md +8 -8
  114. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/example.json +12 -12
  115. data/lib/chef-dk/skeletons/code_generator/files/default/serverspec_spec_helper.rb +8 -3
  116. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +2 -2
  117. data/lib/chef-dk/skeletons/code_generator/metadata.rb +8 -8
  118. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +97 -97
  119. data/lib/chef-dk/skeletons/code_generator/recipes/attribute.rb +12 -12
  120. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +104 -92
  121. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook_file.rb +24 -24
  122. data/lib/chef-dk/skeletons/code_generator/recipes/lwrp.rb +23 -23
  123. data/lib/chef-dk/skeletons/code_generator/recipes/policyfile.rb +8 -8
  124. data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +27 -27
  125. data/lib/chef-dk/skeletons/code_generator/recipes/repo.rb +48 -47
  126. data/lib/chef-dk/skeletons/code_generator/recipes/template.rb +32 -32
  127. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -3
  128. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.apache2.erb +201 -201
  129. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -339
  130. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -674
  131. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -21
  132. data/lib/chef-dk/skeletons/code_generator/templates/default/Policyfile.rb.erb +20 -16
  133. data/lib/chef-dk/skeletons/code_generator/templates/default/README.md.erb +4 -4
  134. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +16 -16
  135. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen_policyfile.yml.erb +27 -0
  136. data/lib/chef-dk/skeletons/code_generator/templates/default/metadata.rb.erb +7 -7
  137. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +5 -5
  138. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +20 -20
  139. data/lib/chef-dk/skeletons/code_generator/templates/default/repo/gitignore.erb +11 -11
  140. data/lib/chef-dk/skeletons/code_generator/templates/default/serverspec_default_spec.rb.erb +9 -9
  141. data/lib/chef-dk/ui.rb +58 -58
  142. data/lib/chef-dk/version.rb +20 -20
  143. data/lib/kitchen/provisioner/policyfile_zero.rb +193 -164
  144. data/spec/shared/a_file_generator.rb +125 -125
  145. data/spec/shared/a_generated_file.rb +12 -12
  146. data/spec/shared/command_with_ui_object.rb +11 -11
  147. data/spec/shared/custom_generator_cookbook.rb +117 -117
  148. data/spec/shared/fixture_cookbook_checksums.rb +47 -47
  149. data/spec/shared/setup_git_cookbooks.rb +53 -53
  150. data/spec/spec_helper.rb +49 -48
  151. data/spec/test_helpers.rb +84 -84
  152. data/spec/unit/chef_runner_spec.rb +111 -110
  153. data/spec/unit/cli_spec.rb +357 -357
  154. data/spec/unit/command/base_spec.rb +169 -136
  155. data/spec/unit/command/clean_policy_cookbooks_spec.rb +181 -181
  156. data/spec/unit/command/clean_policy_revisions_spec.rb +181 -181
  157. data/spec/unit/command/delete_policy_group_spec.rb +207 -207
  158. data/spec/unit/command/delete_policy_spec.rb +207 -207
  159. data/spec/unit/command/diff_spec.rb +312 -312
  160. data/spec/unit/command/env_spec.rb +52 -52
  161. data/spec/unit/command/exec_spec.rb +179 -179
  162. data/spec/unit/command/export_spec.rb +189 -189
  163. data/spec/unit/command/generate_spec.rb +142 -142
  164. data/spec/unit/command/generator_commands/app_spec.rb +169 -169
  165. data/spec/unit/command/generator_commands/attribute_spec.rb +32 -32
  166. data/spec/unit/command/generator_commands/cookbook_file_spec.rb +32 -32
  167. data/spec/unit/command/generator_commands/cookbook_spec.rb +320 -240
  168. data/spec/unit/command/generator_commands/generator_generator_spec.rb +229 -0
  169. data/spec/unit/command/generator_commands/lwrp_spec.rb +32 -32
  170. data/spec/unit/command/generator_commands/policyfile_spec.rb +125 -125
  171. data/spec/unit/command/generator_commands/recipe_spec.rb +34 -34
  172. data/spec/unit/command/generator_commands/repo_spec.rb +283 -283
  173. data/spec/unit/command/generator_commands/template_spec.rb +32 -32
  174. data/spec/unit/command/install_spec.rb +179 -179
  175. data/spec/unit/command/provision_spec.rb +592 -592
  176. data/spec/unit/command/push_archive_spec.rb +153 -153
  177. data/spec/unit/command/push_spec.rb +199 -199
  178. data/spec/unit/command/shell_init_spec.rb +329 -329
  179. data/spec/unit/command/show_policy_spec.rb +235 -235
  180. data/spec/unit/command/undelete_spec.rb +246 -246
  181. data/spec/unit/command/update_spec.rb +251 -251
  182. data/spec/unit/command/verify_spec.rb +323 -322
  183. data/spec/unit/commands_map_spec.rb +57 -57
  184. data/spec/unit/component_test_spec.rb +126 -126
  185. data/spec/unit/cookbook_metadata_spec.rb +98 -98
  186. data/spec/unit/cookbook_profiler/git_spec.rb +176 -176
  187. data/spec/unit/cookbook_profiler/identifiers_spec.rb +83 -83
  188. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_one.rb +9 -9
  189. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_two.rb +9 -9
  190. data/spec/unit/fixtures/command/cli_test_command.rb +26 -26
  191. data/spec/unit/fixtures/command/explicit_path_example.rb +7 -7
  192. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -16
  193. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +3 -3
  194. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -4
  195. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/chefignore +96 -96
  196. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -8
  197. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -8
  198. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/.kitchen.yml +16 -16
  199. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +3 -3
  200. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/README.md +4 -4
  201. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/chefignore +96 -96
  202. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/metadata.rb +8 -8
  203. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/recipes/default.rb +8 -8
  204. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/.kitchen.yml +16 -16
  205. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +3 -3
  206. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/README.md +4 -4
  207. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/chefignore +96 -96
  208. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/metadata.rb +8 -8
  209. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/recipes/default.rb +8 -8
  210. data/spec/unit/fixtures/cookbooks_api/pruned_small_universe.json +1321 -1321
  211. data/spec/unit/fixtures/cookbooks_api/small_universe.json +2987 -2987
  212. data/spec/unit/fixtures/cookbooks_api/universe.json +1 -1
  213. data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +36 -36
  214. data/spec/unit/fixtures/dev_cookbooks/README.md +16 -16
  215. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/integration_test +2 -2
  216. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/verify_me +5 -5
  217. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef/verify_me +3 -3
  218. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/test-kitchen/verify_me +2 -2
  219. data/spec/unit/fixtures/example_cookbook/.gitignore +17 -17
  220. data/spec/unit/fixtures/example_cookbook/.kitchen.yml +16 -16
  221. data/spec/unit/fixtures/example_cookbook/Berksfile +3 -3
  222. data/spec/unit/fixtures/example_cookbook/README.md +4 -4
  223. data/spec/unit/fixtures/example_cookbook/chefignore +96 -96
  224. data/spec/unit/fixtures/example_cookbook/metadata.rb +8 -8
  225. data/spec/unit/fixtures/example_cookbook/recipes/default.rb +8 -8
  226. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.gitignore +17 -17
  227. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.kitchen.yml +16 -16
  228. data/spec/unit/fixtures/example_cookbook_metadata_json_only/Berksfile +3 -3
  229. data/spec/unit/fixtures/example_cookbook_metadata_json_only/README.md +4 -4
  230. data/spec/unit/fixtures/example_cookbook_metadata_json_only/chefignore +96 -96
  231. data/spec/unit/fixtures/example_cookbook_metadata_json_only/metadata.json +5 -5
  232. data/spec/unit/fixtures/example_cookbook_metadata_json_only/recipes/default.rb +8 -8
  233. data/spec/unit/fixtures/example_cookbook_no_metadata/.gitignore +17 -17
  234. data/spec/unit/fixtures/example_cookbook_no_metadata/.kitchen.yml +16 -16
  235. data/spec/unit/fixtures/example_cookbook_no_metadata/Berksfile +3 -3
  236. data/spec/unit/fixtures/example_cookbook_no_metadata/README.md +4 -4
  237. data/spec/unit/fixtures/example_cookbook_no_metadata/chefignore +96 -96
  238. data/spec/unit/fixtures/example_cookbook_no_metadata/recipes/default.rb +8 -8
  239. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/README.md +4 -4
  240. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/chefignore +96 -96
  241. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/metadata.rb +8 -8
  242. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/recipes/default.rb +8 -8
  243. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/Berksfile +3 -3
  244. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/README.md +4 -4
  245. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/chefignore +96 -96
  246. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/metadata.rb +9 -9
  247. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/recipes/default.rb +8 -8
  248. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/.kitchen.yml +16 -16
  249. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +3 -3
  250. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/README.md +4 -4
  251. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/chefignore +96 -96
  252. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/metadata.rb +8 -8
  253. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/recipes/default.rb +8 -8
  254. data/spec/unit/fixtures/local_path_cookbooks/metadata-missing/README.md +2 -2
  255. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -16
  256. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -4
  257. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -8
  258. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -8
  259. data/spec/unit/generator_spec.rb +120 -120
  260. data/spec/unit/helpers_spec.rb +92 -92
  261. data/spec/unit/pager_spec.rb +119 -119
  262. data/spec/unit/policyfile/chef_repo_cookbook_source_spec.rb +66 -66
  263. data/spec/unit/policyfile/chef_server_cookbook_source_spec.rb +34 -34
  264. data/spec/unit/policyfile/community_cookbook_source_spec.rb +51 -51
  265. data/spec/unit/policyfile/comparison_base_spec.rb +343 -343
  266. data/spec/unit/policyfile/cookbook_location_specification_spec.rb +252 -252
  267. data/spec/unit/policyfile/cookbook_locks_spec.rb +529 -529
  268. data/spec/unit/policyfile/differ_spec.rb +687 -687
  269. data/spec/unit/policyfile/lister_spec.rb +272 -272
  270. data/spec/unit/policyfile/null_cookbook_source_spec.rb +35 -35
  271. data/spec/unit/policyfile/read_cookbook_for_compat_mode_upload_spec.rb +92 -92
  272. data/spec/unit/policyfile/reports/install_spec.rb +115 -115
  273. data/spec/unit/policyfile/reports/upload_spec.rb +96 -96
  274. data/spec/unit/policyfile/solution_dependencies_spec.rb +145 -145
  275. data/spec/unit/policyfile/storage_config_spec.rb +172 -172
  276. data/spec/unit/policyfile/undo_record_spec.rb +260 -260
  277. data/spec/unit/policyfile/undo_stack_spec.rb +266 -266
  278. data/spec/unit/policyfile/uploader_spec.rb +410 -410
  279. data/spec/unit/policyfile_demands_spec.rb +876 -876
  280. data/spec/unit/policyfile_evaluation_spec.rb +441 -441
  281. data/spec/unit/policyfile_lock_build_spec.rb +1056 -1056
  282. data/spec/unit/policyfile_lock_install_spec.rb +138 -138
  283. data/spec/unit/policyfile_lock_serialization_spec.rb +425 -425
  284. data/spec/unit/policyfile_lock_validation_spec.rb +611 -611
  285. data/spec/unit/policyfile_services/clean_policies_spec.rb +236 -236
  286. data/spec/unit/policyfile_services/clean_policy_cookbooks_spec.rb +275 -275
  287. data/spec/unit/policyfile_services/export_repo_spec.rb +439 -416
  288. data/spec/unit/policyfile_services/install_spec.rb +191 -191
  289. data/spec/unit/policyfile_services/push_archive_spec.rb +345 -345
  290. data/spec/unit/policyfile_services/push_spec.rb +233 -233
  291. data/spec/unit/policyfile_services/rm_policy_group_spec.rb +241 -241
  292. data/spec/unit/policyfile_services/rm_policy_spec.rb +266 -266
  293. data/spec/unit/policyfile_services/show_policy_spec.rb +889 -889
  294. data/spec/unit/policyfile_services/undelete_spec.rb +304 -304
  295. data/spec/unit/policyfile_services/update_attributes_spec.rb +217 -217
  296. data/spec/unit/service_exception_inspectors/base_spec.rb +43 -43
  297. data/spec/unit/service_exception_inspectors/http_spec.rb +140 -140
  298. data/spec/unit/shell_out_spec.rb +34 -34
  299. metadata +9 -3
@@ -1,95 +1,95 @@
1
- #
2
- # Copyright:: Copyright (c) 2015 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
- require 'chef-dk/service_exceptions'
20
- require 'chef-dk/policyfile/lister'
21
-
22
- module ChefDK
23
- module PolicyfileServices
24
- class CleanPolicies
25
-
26
- Orphan = Struct.new(:policy_name, :revision_id)
27
-
28
- attr_reader :chef_config
29
- attr_reader :ui
30
-
31
- def initialize(config: nil, ui: nil)
32
- @chef_config = config
33
- @ui = ui
34
- end
35
-
36
- def run
37
- revisions_to_remove = orphaned_policies
38
-
39
- if revisions_to_remove.empty?
40
- ui.err("No policy revisions deleted")
41
- return true
42
- end
43
-
44
- results = revisions_to_remove.map do |policy|
45
- [ remove_policy(policy), policy ]
46
- end
47
-
48
- failures = results.select { |result, _policy| result.kind_of?(Exception) }
49
-
50
- unless failures.empty?
51
- details = failures.map do |result, policy|
52
- "- #{policy.policy_name} (#{policy.revision_id}): #{result.class} #{result}"
53
- end
54
-
55
- message = "Failed to delete some policy revisions:\n" + details.join("\n") + "\n"
56
-
57
- raise PolicyfileCleanError.new(message, MultipleErrors.new("multiple errors"))
58
- end
59
-
60
- true
61
- end
62
-
63
- def orphaned_policies
64
- policy_lister.policies_by_name.keys.inject([]) do |orphans, policy_name|
65
- orphans + policy_lister.orphaned_revisions(policy_name).map do |revision_id|
66
- Orphan.new(policy_name, revision_id)
67
- end
68
- end
69
- rescue => e
70
- raise PolicyfileCleanError.new("Failed to list policies for cleaning.", e)
71
- end
72
-
73
- def policy_lister
74
- @policy_lister ||= Policyfile::Lister.new(config: chef_config)
75
- end
76
-
77
- def http_client
78
- @http_client ||= ChefDK::AuthenticatedHTTP.new(chef_config.chef_server_url,
79
- signing_key_filename: chef_config.client_key,
80
- client_name: chef_config.node_name)
81
- end
82
-
83
- private
84
-
85
- def remove_policy(policy)
86
- ui.msg("DELETE #{policy.policy_name} #{policy.revision_id}")
87
- http_client.delete("/policies/#{policy.policy_name}/revisions/#{policy.revision_id}")
88
- :ok
89
- rescue => e
90
- e
91
- end
92
-
93
- end
94
- end
95
- end
1
+ #
2
+ # Copyright:: Copyright (c) 2015 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
+ require 'chef-dk/service_exceptions'
20
+ require 'chef-dk/policyfile/lister'
21
+
22
+ module ChefDK
23
+ module PolicyfileServices
24
+ class CleanPolicies
25
+
26
+ Orphan = Struct.new(:policy_name, :revision_id)
27
+
28
+ attr_reader :chef_config
29
+ attr_reader :ui
30
+
31
+ def initialize(config: nil, ui: nil)
32
+ @chef_config = config
33
+ @ui = ui
34
+ end
35
+
36
+ def run
37
+ revisions_to_remove = orphaned_policies
38
+
39
+ if revisions_to_remove.empty?
40
+ ui.err("No policy revisions deleted")
41
+ return true
42
+ end
43
+
44
+ results = revisions_to_remove.map do |policy|
45
+ [ remove_policy(policy), policy ]
46
+ end
47
+
48
+ failures = results.select { |result, _policy| result.kind_of?(Exception) }
49
+
50
+ unless failures.empty?
51
+ details = failures.map do |result, policy|
52
+ "- #{policy.policy_name} (#{policy.revision_id}): #{result.class} #{result}"
53
+ end
54
+
55
+ message = "Failed to delete some policy revisions:\n" + details.join("\n") + "\n"
56
+
57
+ raise PolicyfileCleanError.new(message, MultipleErrors.new("multiple errors"))
58
+ end
59
+
60
+ true
61
+ end
62
+
63
+ def orphaned_policies
64
+ policy_lister.policies_by_name.keys.inject([]) do |orphans, policy_name|
65
+ orphans + policy_lister.orphaned_revisions(policy_name).map do |revision_id|
66
+ Orphan.new(policy_name, revision_id)
67
+ end
68
+ end
69
+ rescue => e
70
+ raise PolicyfileCleanError.new("Failed to list policies for cleaning.", e)
71
+ end
72
+
73
+ def policy_lister
74
+ @policy_lister ||= Policyfile::Lister.new(config: chef_config)
75
+ end
76
+
77
+ def http_client
78
+ @http_client ||= ChefDK::AuthenticatedHTTP.new(chef_config.chef_server_url,
79
+ signing_key_filename: chef_config.client_key,
80
+ client_name: chef_config.node_name)
81
+ end
82
+
83
+ private
84
+
85
+ def remove_policy(policy)
86
+ ui.msg("DELETE #{policy.policy_name} #{policy.revision_id}")
87
+ http_client.delete("/policies/#{policy.policy_name}/revisions/#{policy.revision_id}")
88
+ :ok
89
+ rescue => e
90
+ e
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -1,125 +1,125 @@
1
- #
2
- # Copyright:: Copyright (c) 2015 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 'set'
19
-
20
- require 'chef-dk/authenticated_http'
21
- require 'chef-dk/service_exceptions'
22
-
23
- module ChefDK
24
- module PolicyfileServices
25
-
26
- class CleanPolicyCookbooks
27
-
28
- attr_reader :chef_config
29
-
30
- attr_reader :ui
31
-
32
- def initialize(config: nil, ui: nil)
33
- @chef_config = config
34
- @ui = ui
35
-
36
- @all_cookbooks = nil
37
- @active_cookbooks = nil
38
- @all_policies = nil
39
- end
40
-
41
- def run
42
- gc_cookbooks
43
- rescue => e
44
- raise PolicyCookbookCleanError.new("Failed to cleanup policy cookbooks", e)
45
- end
46
-
47
- def gc_cookbooks
48
- cookbooks = cookbooks_to_clean
49
-
50
- if cookbooks.empty?
51
- ui.msg("No cookbooks deleted.")
52
- end
53
-
54
- cookbooks.each do |name, identifiers|
55
- identifiers.each do |identifier|
56
- http_client.delete("/cookbook_artifacts/#{name}/#{identifier}")
57
- ui.msg("DELETE #{name} #{identifier}")
58
- end
59
- end
60
- end
61
-
62
-
63
- def all_cookbooks
64
- cookbook_list = http_client.get("/cookbook_artifacts")
65
- cookbook_list.inject({}) do |cb_map, (name, cb_info)|
66
- cb_map[name] = cb_info["versions"].map { |v| v["identifier"] }
67
- cb_map
68
- end
69
- end
70
-
71
- def active_cookbooks
72
- policy_revisions_by_name.inject({}) do |cb_map, (policy_name, revision_ids)|
73
- revision_ids.each do |revision_id|
74
- cookbook_revisions_in_policy(policy_name, revision_id).each do |cb_name, identifier|
75
- cb_map[cb_name] ||= Set.new
76
- cb_map[cb_name] << identifier
77
- end
78
- end
79
- cb_map
80
- end
81
- end
82
-
83
- def cookbooks_to_clean
84
- active_cbs = active_cookbooks
85
-
86
- all_cookbooks.inject({}) do |cb_map, (cb_name, revisions)|
87
- active_revs = active_cbs[cb_name] || Set.new
88
- inactive_revs = Set.new(revisions) - active_revs
89
- cb_map[cb_name] = inactive_revs unless inactive_revs.empty?
90
-
91
- cb_map
92
- end
93
- end
94
-
95
- # @api private
96
- def policy_revisions_by_name
97
- policies_list = http_client.get("/policies")
98
- policies_list.inject({}) do |policies_map, (name, policy_info)|
99
- policies_map[name] = policy_info["revisions"].keys
100
- policies_map
101
- end
102
- end
103
-
104
- # @api private
105
- def cookbook_revisions_in_policy(name, revision_id)
106
- policy_revision_data = http_client.get("/policies/#{name}/revisions/#{revision_id}")
107
-
108
- policy_revision_data["cookbook_locks"].inject({}) do |cb_map, (cb_name, lock_info)|
109
- cb_map[cb_name] = lock_info["identifier"]
110
- cb_map
111
- end
112
- end
113
-
114
- # @api private
115
- # An instance of ChefDK::AuthenticatedHTTP configured with the user's
116
- # server URL and credentials.
117
- def http_client
118
- @http_client ||= ChefDK::AuthenticatedHTTP.new(chef_config.chef_server_url,
119
- signing_key_filename: chef_config.client_key,
120
- client_name: chef_config.node_name)
121
- end
122
- end
123
- end
124
- end
125
-
1
+ #
2
+ # Copyright:: Copyright (c) 2015 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 'set'
19
+
20
+ require 'chef-dk/authenticated_http'
21
+ require 'chef-dk/service_exceptions'
22
+
23
+ module ChefDK
24
+ module PolicyfileServices
25
+
26
+ class CleanPolicyCookbooks
27
+
28
+ attr_reader :chef_config
29
+
30
+ attr_reader :ui
31
+
32
+ def initialize(config: nil, ui: nil)
33
+ @chef_config = config
34
+ @ui = ui
35
+
36
+ @all_cookbooks = nil
37
+ @active_cookbooks = nil
38
+ @all_policies = nil
39
+ end
40
+
41
+ def run
42
+ gc_cookbooks
43
+ rescue => e
44
+ raise PolicyCookbookCleanError.new("Failed to cleanup policy cookbooks", e)
45
+ end
46
+
47
+ def gc_cookbooks
48
+ cookbooks = cookbooks_to_clean
49
+
50
+ if cookbooks.empty?
51
+ ui.msg("No cookbooks deleted.")
52
+ end
53
+
54
+ cookbooks.each do |name, identifiers|
55
+ identifiers.each do |identifier|
56
+ http_client.delete("/cookbook_artifacts/#{name}/#{identifier}")
57
+ ui.msg("DELETE #{name} #{identifier}")
58
+ end
59
+ end
60
+ end
61
+
62
+
63
+ def all_cookbooks
64
+ cookbook_list = http_client.get("/cookbook_artifacts")
65
+ cookbook_list.inject({}) do |cb_map, (name, cb_info)|
66
+ cb_map[name] = cb_info["versions"].map { |v| v["identifier"] }
67
+ cb_map
68
+ end
69
+ end
70
+
71
+ def active_cookbooks
72
+ policy_revisions_by_name.inject({}) do |cb_map, (policy_name, revision_ids)|
73
+ revision_ids.each do |revision_id|
74
+ cookbook_revisions_in_policy(policy_name, revision_id).each do |cb_name, identifier|
75
+ cb_map[cb_name] ||= Set.new
76
+ cb_map[cb_name] << identifier
77
+ end
78
+ end
79
+ cb_map
80
+ end
81
+ end
82
+
83
+ def cookbooks_to_clean
84
+ active_cbs = active_cookbooks
85
+
86
+ all_cookbooks.inject({}) do |cb_map, (cb_name, revisions)|
87
+ active_revs = active_cbs[cb_name] || Set.new
88
+ inactive_revs = Set.new(revisions) - active_revs
89
+ cb_map[cb_name] = inactive_revs unless inactive_revs.empty?
90
+
91
+ cb_map
92
+ end
93
+ end
94
+
95
+ # @api private
96
+ def policy_revisions_by_name
97
+ policies_list = http_client.get("/policies")
98
+ policies_list.inject({}) do |policies_map, (name, policy_info)|
99
+ policies_map[name] = policy_info["revisions"].keys
100
+ policies_map
101
+ end
102
+ end
103
+
104
+ # @api private
105
+ def cookbook_revisions_in_policy(name, revision_id)
106
+ policy_revision_data = http_client.get("/policies/#{name}/revisions/#{revision_id}")
107
+
108
+ policy_revision_data["cookbook_locks"].inject({}) do |cb_map, (cb_name, lock_info)|
109
+ cb_map[cb_name] = lock_info["identifier"]
110
+ cb_map
111
+ end
112
+ end
113
+
114
+ # @api private
115
+ # An instance of ChefDK::AuthenticatedHTTP configured with the user's
116
+ # server URL and credentials.
117
+ def http_client
118
+ @http_client ||= ChefDK::AuthenticatedHTTP.new(chef_config.chef_server_url,
119
+ signing_key_filename: chef_config.client_key,
120
+ client_name: chef_config.node_name)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
@@ -1,281 +1,309 @@
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 'fileutils'
19
- require 'tmpdir'
20
- require 'zlib'
21
-
22
- require 'archive/tar/minitar'
23
-
24
- require 'chef-dk/service_exceptions'
25
- require 'chef-dk/policyfile_lock'
26
- require 'chef-dk/policyfile/storage_config'
27
-
28
- module ChefDK
29
- module PolicyfileServices
30
-
31
- class ExportRepo
32
-
33
- # Policy groups provide namespaces for policies so that a Chef Server can
34
- # have multiple active iterations of a policy at once, but we don't need
35
- # this when serving a single exported policy via Chef Zero, so hardcode
36
- # it to a "well known" value:
37
- POLICY_GROUP = 'local'.freeze
38
-
39
- include Policyfile::StorageConfigDelegation
40
-
41
- attr_reader :storage_config
42
- attr_reader :root_dir
43
- attr_reader :export_dir
44
-
45
- def initialize(policyfile: nil, export_dir: nil, root_dir: nil, archive: false, force: false)
46
- @root_dir = root_dir
47
- @export_dir = File.expand_path(export_dir)
48
- @archive = archive
49
- @force_export = force
50
-
51
- @policy_data = nil
52
- @policyfile_lock = nil
53
-
54
- policyfile_rel_path = policyfile || "Policyfile.rb"
55
- policyfile_full_path = File.expand_path(policyfile_rel_path, root_dir)
56
- @storage_config = Policyfile::StorageConfig.new.use_policyfile(policyfile_full_path)
57
-
58
- @staging_dir = nil
59
- end
60
-
61
- def archive?
62
- @archive
63
- end
64
-
65
- def policy_name
66
- policyfile_lock.name
67
- end
68
-
69
- def run
70
- assert_lockfile_exists!
71
- assert_export_dir_clean!
72
-
73
- validate_lockfile
74
- write_updated_lockfile
75
- export
76
- end
77
-
78
- def policy_data
79
- @policy_data ||= FFI_Yajl::Parser.parse(IO.read(policyfile_lock_expanded_path))
80
- rescue => error
81
- raise PolicyfileExportRepoError.new("Error reading lockfile #{policyfile_lock_expanded_path}", error)
82
- end
83
-
84
- def policyfile_lock
85
- @policyfile_lock || validate_lockfile
86
- end
87
-
88
- def archive_file_location
89
- return nil unless archive?
90
- filename = "#{policyfile_lock.name}-#{policyfile_lock.revision_id}.tgz"
91
- File.join(export_dir, filename)
92
- end
93
-
94
- def export
95
- with_staging_dir do
96
- create_repo_structure
97
- copy_cookbooks
98
- create_policyfile_data_item
99
- copy_policyfile_lock
100
- if archive?
101
- create_archive
102
- else
103
- mv_staged_repo
104
- end
105
- end
106
- rescue => error
107
- msg = "Failed to export policy (in #{policyfile_filename}) to #{export_dir}"
108
- raise PolicyfileExportRepoError.new(msg, error)
109
- end
110
-
111
- private
112
-
113
- def with_staging_dir
114
- p = Process.pid
115
- t = Time.new.utc.strftime("%Y%m%d%H%M%S")
116
- Dir.mktmpdir("chefdk-export-#{p}-#{t}") do |d|
117
- begin
118
- @staging_dir = d
119
- yield
120
- ensure
121
- @staging_dir = nil
122
- end
123
- end
124
- end
125
-
126
- def create_archive
127
- Zlib::GzipWriter.open(archive_file_location) do |gz_file|
128
- Dir.chdir(staging_dir) do
129
- Archive::Tar::Minitar.pack(".", gz_file)
130
- end
131
- end
132
- end
133
-
134
- def staging_dir
135
- @staging_dir
136
- end
137
-
138
- def create_repo_structure
139
- FileUtils.mkdir_p(export_dir)
140
- FileUtils.mkdir_p(cookbooks_staging_dir)
141
- FileUtils.mkdir_p(policyfiles_data_bag_staging_dir)
142
- end
143
-
144
- def copy_cookbooks
145
- policyfile_lock.cookbook_locks.each do |name, lock|
146
- copy_cookbook(lock)
147
- end
148
- end
149
-
150
- def copy_cookbook(lock)
151
- dirname = "#{lock.name}-#{lock.dotted_decimal_identifier}"
152
- export_path = File.join(staging_dir, "cookbooks", dirname)
153
- metadata_rb_path = File.join(export_path, "metadata.rb")
154
- FileUtils.cp_r(lock.cookbook_path, export_path)
155
- FileUtils.rm_f(metadata_rb_path)
156
- metadata = lock.cookbook_version.metadata
157
- metadata.version(lock.dotted_decimal_identifier)
158
-
159
- metadata_json_path = File.join(export_path, "metadata.json")
160
-
161
- File.open(metadata_json_path, "wb+") do |f|
162
- f.print(FFI_Yajl::Encoder.encode(metadata.to_hash, pretty: true ))
163
- end
164
- end
165
-
166
- def create_policyfile_data_item
167
- lock_data = policyfile_lock.to_lock.dup
168
-
169
- lock_data["id"] = policy_id
170
-
171
- data_item = {
172
- "id" => policy_id,
173
- "name" => "data_bag_item_policyfiles_#{policy_id}",
174
- "data_bag" => "policyfiles",
175
- "raw_data" => lock_data,
176
- # we'd prefer to leave this out, but the "compatibility mode"
177
- # implementation in chef-client relies on magical class inflation
178
- "json_class" => "Chef::DataBagItem"
179
- }
180
-
181
- File.open(item_path, "wb+") do |f|
182
- f.print(FFI_Yajl::Encoder.encode(data_item, pretty: true ))
183
- end
184
- end
185
-
186
- def copy_policyfile_lock
187
- File.open(lockfile_staging_path, "wb+") do |f|
188
- f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true ))
189
- end
190
- end
191
-
192
- def mv_staged_repo
193
- # If we got here, either these dirs are empty/don't exist or force is
194
- # set to true.
195
- FileUtils.rm_rf(cookbooks_dir)
196
- FileUtils.rm_rf(policyfiles_data_bag_dir)
197
-
198
- FileUtils.mv(cookbooks_staging_dir, export_dir)
199
- FileUtils.mkdir_p(export_data_bag_dir)
200
- FileUtils.mv(policyfiles_data_bag_staging_dir, export_data_bag_dir)
201
- FileUtils.mv(lockfile_staging_path, export_dir)
202
- end
203
-
204
- def validate_lockfile
205
- return @policyfile_lock if @policyfile_lock
206
- @policyfile_lock = ChefDK::PolicyfileLock.new(storage_config).build_from_lock_data(policy_data)
207
- # TODO: enumerate any cookbook that have been updated
208
- @policyfile_lock.validate_cookbooks!
209
- @policyfile_lock
210
- rescue PolicyfileExportRepoError
211
- raise
212
- rescue => error
213
- raise PolicyfileExportRepoError.new("Invalid lockfile data", error)
214
- end
215
-
216
- def write_updated_lockfile
217
- File.open(policyfile_lock_expanded_path, "wb+") do |f|
218
- f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true ))
219
- end
220
- end
221
-
222
- def assert_lockfile_exists!
223
- unless File.exist?(policyfile_lock_expanded_path)
224
- raise LockfileNotFound, "No lockfile at #{policyfile_lock_expanded_path} - you need to run `install` before `push`"
225
- end
226
- end
227
-
228
- def assert_export_dir_clean!
229
- if !force_export? && !conflicting_fs_entries.empty? && !archive?
230
- msg = "Export dir (#{export_dir}) not clean. Refusing to export. (Conflicting files: #{conflicting_fs_entries.join(', ')})"
231
- raise ExportDirNotEmpty, msg
232
- end
233
- end
234
-
235
- def force_export?
236
- @force_export
237
- end
238
-
239
- def conflicting_fs_entries
240
- Dir.glob(File.join(cookbooks_dir, "*")) +
241
- Dir.glob(File.join(policyfiles_data_bag_dir, "*")) +
242
- Dir.glob(File.join(export_dir, "Policyfile.lock.json"))
243
- end
244
-
245
- def cookbooks_dir
246
- File.join(export_dir, "cookbooks")
247
- end
248
-
249
- def export_data_bag_dir
250
- File.join(export_dir, "data_bags")
251
- end
252
-
253
- def policyfiles_data_bag_dir
254
- File.join(export_data_bag_dir, "policyfiles")
255
- end
256
-
257
- def policy_id
258
- "#{policyfile_lock.name}-#{POLICY_GROUP}"
259
- end
260
-
261
- def item_path
262
- File.join(staging_dir, "data_bags", "policyfiles", "#{policy_id}.json")
263
- end
264
-
265
- def cookbooks_staging_dir
266
- File.join(staging_dir, "cookbooks")
267
- end
268
-
269
- def policyfiles_data_bag_staging_dir
270
- File.join(staging_dir, "data_bags", "policyfiles")
271
- end
272
-
273
- def lockfile_staging_path
274
- File.join(staging_dir, "Policyfile.lock.json")
275
- end
276
-
277
- end
278
-
279
- end
280
- end
281
-
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 'fileutils'
19
+ require 'tmpdir'
20
+ require 'zlib'
21
+
22
+ require 'archive/tar/minitar'
23
+
24
+ require 'chef-dk/service_exceptions'
25
+ require 'chef-dk/policyfile_lock'
26
+ require 'chef-dk/policyfile/storage_config'
27
+
28
+ module ChefDK
29
+ module PolicyfileServices
30
+
31
+ class ExportRepo
32
+
33
+ # Policy groups provide namespaces for policies so that a Chef Server can
34
+ # have multiple active iterations of a policy at once, but we don't need
35
+ # this when serving a single exported policy via Chef Zero, so hardcode
36
+ # it to a "well known" value:
37
+ POLICY_GROUP = 'local'.freeze
38
+
39
+ include Policyfile::StorageConfigDelegation
40
+
41
+ attr_reader :storage_config
42
+ attr_reader :root_dir
43
+ attr_reader :export_dir
44
+
45
+ def initialize(policyfile: nil, export_dir: nil, root_dir: nil, archive: false, force: false)
46
+ @root_dir = root_dir
47
+ @export_dir = File.expand_path(export_dir)
48
+ @archive = archive
49
+ @force_export = force
50
+
51
+ @policy_data = nil
52
+ @policyfile_lock = nil
53
+
54
+ policyfile_rel_path = policyfile || "Policyfile.rb"
55
+ policyfile_full_path = File.expand_path(policyfile_rel_path, root_dir)
56
+ @storage_config = Policyfile::StorageConfig.new.use_policyfile(policyfile_full_path)
57
+
58
+ @staging_dir = nil
59
+ end
60
+
61
+ def archive?
62
+ @archive
63
+ end
64
+
65
+ def policy_name
66
+ policyfile_lock.name
67
+ end
68
+
69
+ def run
70
+ assert_lockfile_exists!
71
+ assert_export_dir_clean!
72
+
73
+ validate_lockfile
74
+ write_updated_lockfile
75
+ export
76
+ end
77
+
78
+ def policy_data
79
+ @policy_data ||= FFI_Yajl::Parser.parse(IO.read(policyfile_lock_expanded_path))
80
+ rescue => error
81
+ raise PolicyfileExportRepoError.new("Error reading lockfile #{policyfile_lock_expanded_path}", error)
82
+ end
83
+
84
+ def policyfile_lock
85
+ @policyfile_lock || validate_lockfile
86
+ end
87
+
88
+ def archive_file_location
89
+ return nil unless archive?
90
+ filename = "#{policyfile_lock.name}-#{policyfile_lock.revision_id}.tgz"
91
+ File.join(export_dir, filename)
92
+ end
93
+
94
+ def export
95
+ with_staging_dir do
96
+ create_repo_structure
97
+ copy_cookbooks
98
+ create_policyfile_data_item
99
+ copy_policyfile_lock
100
+ create_client_rb
101
+ if archive?
102
+ create_archive
103
+ else
104
+ mv_staged_repo
105
+ end
106
+ end
107
+ rescue => error
108
+ msg = "Failed to export policy (in #{policyfile_filename}) to #{export_dir}"
109
+ raise PolicyfileExportRepoError.new(msg, error)
110
+ end
111
+
112
+ private
113
+
114
+ def with_staging_dir
115
+ p = Process.pid
116
+ t = Time.new.utc.strftime("%Y%m%d%H%M%S")
117
+ Dir.mktmpdir("chefdk-export-#{p}-#{t}") do |d|
118
+ begin
119
+ @staging_dir = d
120
+ yield
121
+ ensure
122
+ @staging_dir = nil
123
+ end
124
+ end
125
+ end
126
+
127
+ def create_archive
128
+ Zlib::GzipWriter.open(archive_file_location) do |gz_file|
129
+ Dir.chdir(staging_dir) do
130
+ Archive::Tar::Minitar.pack(".", gz_file)
131
+ end
132
+ end
133
+ end
134
+
135
+ def staging_dir
136
+ @staging_dir
137
+ end
138
+
139
+ def create_repo_structure
140
+ FileUtils.mkdir_p(export_dir)
141
+ FileUtils.mkdir_p(cookbooks_staging_dir)
142
+ FileUtils.mkdir_p(policyfiles_data_bag_staging_dir)
143
+ end
144
+
145
+ def copy_cookbooks
146
+ policyfile_lock.cookbook_locks.each do |name, lock|
147
+ copy_cookbook(lock)
148
+ end
149
+ end
150
+
151
+ def copy_cookbook(lock)
152
+ dirname = "#{lock.name}-#{lock.dotted_decimal_identifier}"
153
+ export_path = File.join(staging_dir, "cookbooks", dirname)
154
+ metadata_rb_path = File.join(export_path, "metadata.rb")
155
+ FileUtils.cp_r(lock.cookbook_path, export_path)
156
+ FileUtils.rm_f(metadata_rb_path)
157
+ metadata = lock.cookbook_version.metadata
158
+ metadata.version(lock.dotted_decimal_identifier)
159
+
160
+ metadata_json_path = File.join(export_path, "metadata.json")
161
+
162
+ File.open(metadata_json_path, "wb+") do |f|
163
+ f.print(FFI_Yajl::Encoder.encode(metadata.to_hash, pretty: true ))
164
+ end
165
+ end
166
+
167
+ def create_policyfile_data_item
168
+ lock_data = policyfile_lock.to_lock.dup
169
+
170
+ lock_data["id"] = policy_id
171
+
172
+ data_item = {
173
+ "id" => policy_id,
174
+ "name" => "data_bag_item_policyfiles_#{policy_id}",
175
+ "data_bag" => "policyfiles",
176
+ "raw_data" => lock_data,
177
+ # we'd prefer to leave this out, but the "compatibility mode"
178
+ # implementation in chef-client relies on magical class inflation
179
+ "json_class" => "Chef::DataBagItem"
180
+ }
181
+
182
+ File.open(item_path, "wb+") do |f|
183
+ f.print(FFI_Yajl::Encoder.encode(data_item, pretty: true ))
184
+ end
185
+ end
186
+
187
+ def copy_policyfile_lock
188
+ File.open(lockfile_staging_path, "wb+") do |f|
189
+ f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true ))
190
+ end
191
+ end
192
+
193
+ def create_client_rb
194
+ File.open(client_rb_staging_path, "wb+") do |f|
195
+ f.print( <<-CONFIG )
196
+ ### Chef Client Configuration ###
197
+ # The settings in this file will configure chef to apply the exported policy in
198
+ # this directory. To use it, run:
199
+ #
200
+ # chef-client -c client.rb -z
201
+ #
202
+
203
+ use_policyfile true
204
+
205
+ # compatibility mode settings are used because chef-zero doesn't yet support
206
+ # native mode:
207
+ deployment_group '#{policy_name}-local'
208
+ versioned_cookbooks true
209
+ policy_document_native_api false
210
+
211
+ CONFIG
212
+ end
213
+ end
214
+
215
+ def mv_staged_repo
216
+ # If we got here, either these dirs are empty/don't exist or force is
217
+ # set to true.
218
+ FileUtils.rm_rf(cookbooks_dir)
219
+ FileUtils.rm_rf(policyfiles_data_bag_dir)
220
+
221
+ FileUtils.mv(cookbooks_staging_dir, export_dir)
222
+ FileUtils.mkdir_p(export_data_bag_dir)
223
+ FileUtils.mv(policyfiles_data_bag_staging_dir, export_data_bag_dir)
224
+ FileUtils.mv(lockfile_staging_path, export_dir)
225
+ FileUtils.mv(client_rb_staging_path, export_dir)
226
+ end
227
+
228
+ def validate_lockfile
229
+ return @policyfile_lock if @policyfile_lock
230
+ @policyfile_lock = ChefDK::PolicyfileLock.new(storage_config).build_from_lock_data(policy_data)
231
+ # TODO: enumerate any cookbook that have been updated
232
+ @policyfile_lock.validate_cookbooks!
233
+ @policyfile_lock
234
+ rescue PolicyfileExportRepoError
235
+ raise
236
+ rescue => error
237
+ raise PolicyfileExportRepoError.new("Invalid lockfile data", error)
238
+ end
239
+
240
+ def write_updated_lockfile
241
+ File.open(policyfile_lock_expanded_path, "wb+") do |f|
242
+ f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true ))
243
+ end
244
+ end
245
+
246
+ def assert_lockfile_exists!
247
+ unless File.exist?(policyfile_lock_expanded_path)
248
+ raise LockfileNotFound, "No lockfile at #{policyfile_lock_expanded_path} - you need to run `install` before `push`"
249
+ end
250
+ end
251
+
252
+ def assert_export_dir_clean!
253
+ if !force_export? && !conflicting_fs_entries.empty? && !archive?
254
+ msg = "Export dir (#{export_dir}) not clean. Refusing to export. (Conflicting files: #{conflicting_fs_entries.join(', ')})"
255
+ raise ExportDirNotEmpty, msg
256
+ end
257
+ end
258
+
259
+ def force_export?
260
+ @force_export
261
+ end
262
+
263
+ def conflicting_fs_entries
264
+ Dir.glob(File.join(cookbooks_dir, "*")) +
265
+ Dir.glob(File.join(policyfiles_data_bag_dir, "*")) +
266
+ Dir.glob(File.join(export_dir, "Policyfile.lock.json"))
267
+ end
268
+
269
+ def cookbooks_dir
270
+ File.join(export_dir, "cookbooks")
271
+ end
272
+
273
+ def export_data_bag_dir
274
+ File.join(export_dir, "data_bags")
275
+ end
276
+
277
+ def policyfiles_data_bag_dir
278
+ File.join(export_data_bag_dir, "policyfiles")
279
+ end
280
+
281
+ def policy_id
282
+ "#{policyfile_lock.name}-#{POLICY_GROUP}"
283
+ end
284
+
285
+ def item_path
286
+ File.join(staging_dir, "data_bags", "policyfiles", "#{policy_id}.json")
287
+ end
288
+
289
+ def cookbooks_staging_dir
290
+ File.join(staging_dir, "cookbooks")
291
+ end
292
+
293
+ def policyfiles_data_bag_staging_dir
294
+ File.join(staging_dir, "data_bags", "policyfiles")
295
+ end
296
+
297
+ def lockfile_staging_path
298
+ File.join(staging_dir, "Policyfile.lock.json")
299
+ end
300
+
301
+ def client_rb_staging_path
302
+ File.join(staging_dir, "client.rb")
303
+ end
304
+
305
+ end
306
+
307
+ end
308
+ end
309
+