chef-cli 1.0.3
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/Gemfile +32 -0
- data/LICENSE +201 -0
- data/Rakefile +70 -0
- data/bin/chef +25 -0
- data/chef-cli.gemspec +53 -0
- data/lib/chef-cli.rb +19 -0
- data/lib/chef-cli/authenticated_http.rb +22 -0
- data/lib/chef-cli/builtin_commands.rb +62 -0
- data/lib/chef-cli/chef_runner.rb +114 -0
- data/lib/chef-cli/chef_server_api_multi.rb +73 -0
- data/lib/chef-cli/cli.rb +206 -0
- data/lib/chef-cli/command/base.rb +89 -0
- data/lib/chef-cli/command/clean_policy_cookbooks.rb +115 -0
- data/lib/chef-cli/command/clean_policy_revisions.rb +112 -0
- data/lib/chef-cli/command/delete_policy.rb +121 -0
- data/lib/chef-cli/command/delete_policy_group.rb +121 -0
- data/lib/chef-cli/command/describe_cookbook.rb +98 -0
- data/lib/chef-cli/command/diff.rb +316 -0
- data/lib/chef-cli/command/env.rb +99 -0
- data/lib/chef-cli/command/exec.rb +45 -0
- data/lib/chef-cli/command/export.rb +156 -0
- data/lib/chef-cli/command/gem.rb +48 -0
- data/lib/chef-cli/command/generate.rb +123 -0
- data/lib/chef-cli/command/generator_commands.rb +83 -0
- data/lib/chef-cli/command/generator_commands/attribute.rb +37 -0
- data/lib/chef-cli/command/generator_commands/base.rb +157 -0
- data/lib/chef-cli/command/generator_commands/build_cookbook.rb +126 -0
- data/lib/chef-cli/command/generator_commands/chef_exts/generator_desc_resource.rb +40 -0
- data/lib/chef-cli/command/generator_commands/chef_exts/quieter_doc_formatter.rb +38 -0
- data/lib/chef-cli/command/generator_commands/chef_exts/recipe_dsl_ext.rb +39 -0
- data/lib/chef-cli/command/generator_commands/cookbook.rb +251 -0
- data/lib/chef-cli/command/generator_commands/cookbook_code_file.rb +100 -0
- data/lib/chef-cli/command/generator_commands/cookbook_file.rb +46 -0
- data/lib/chef-cli/command/generator_commands/generator_generator.rb +175 -0
- data/lib/chef-cli/command/generator_commands/helpers.rb +37 -0
- data/lib/chef-cli/command/generator_commands/policyfile.rb +125 -0
- data/lib/chef-cli/command/generator_commands/recipe.rb +37 -0
- data/lib/chef-cli/command/generator_commands/repo.rb +140 -0
- data/lib/chef-cli/command/generator_commands/resource.rb +37 -0
- data/lib/chef-cli/command/generator_commands/template.rb +47 -0
- data/lib/chef-cli/command/install.rb +121 -0
- data/lib/chef-cli/command/provision.rb +38 -0
- data/lib/chef-cli/command/push.rb +118 -0
- data/lib/chef-cli/command/push_archive.rb +126 -0
- data/lib/chef-cli/command/shell_init.rb +185 -0
- data/lib/chef-cli/command/show_policy.rb +164 -0
- data/lib/chef-cli/command/undelete.rb +155 -0
- data/lib/chef-cli/command/update.rb +140 -0
- data/lib/chef-cli/command/verify.rb +548 -0
- data/lib/chef-cli/commands_map.rb +113 -0
- data/lib/chef-cli/completions/bash.sh.erb +5 -0
- data/lib/chef-cli/completions/chef.fish.erb +10 -0
- data/lib/chef-cli/completions/zsh.zsh.erb +21 -0
- data/lib/chef-cli/component_test.rb +226 -0
- data/lib/chef-cli/configurable.rb +88 -0
- data/lib/chef-cli/cookbook_metadata.rb +45 -0
- data/lib/chef-cli/cookbook_omnifetch.rb +32 -0
- data/lib/chef-cli/cookbook_profiler/git.rb +152 -0
- data/lib/chef-cli/cookbook_profiler/identifiers.rb +72 -0
- data/lib/chef-cli/cookbook_profiler/null_scm.rb +31 -0
- data/lib/chef-cli/dist.rb +31 -0
- data/lib/chef-cli/exceptions.rb +153 -0
- data/lib/chef-cli/generator.rb +165 -0
- data/lib/chef-cli/helpers.rb +170 -0
- data/lib/chef-cli/pager.rb +104 -0
- data/lib/chef-cli/policyfile/artifactory_cookbook_source.rb +102 -0
- data/lib/chef-cli/policyfile/attribute_merge_checker.rb +110 -0
- data/lib/chef-cli/policyfile/chef_repo_cookbook_source.rb +138 -0
- data/lib/chef-cli/policyfile/chef_server_cookbook_source.rb +99 -0
- data/lib/chef-cli/policyfile/chef_server_lock_fetcher.rb +167 -0
- data/lib/chef-cli/policyfile/community_cookbook_source.rb +95 -0
- data/lib/chef-cli/policyfile/comparison_base.rb +123 -0
- data/lib/chef-cli/policyfile/cookbook_location_specification.rb +154 -0
- data/lib/chef-cli/policyfile/cookbook_locks.rb +466 -0
- data/lib/chef-cli/policyfile/cookbook_sources.rb +23 -0
- data/lib/chef-cli/policyfile/delivery_supermarket_source.rb +89 -0
- data/lib/chef-cli/policyfile/differ.rb +263 -0
- data/lib/chef-cli/policyfile/dsl.rb +288 -0
- data/lib/chef-cli/policyfile/git_lock_fetcher.rb +265 -0
- data/lib/chef-cli/policyfile/included_policies_cookbook_source.rb +156 -0
- data/lib/chef-cli/policyfile/lister.rb +229 -0
- data/lib/chef-cli/policyfile/local_lock_fetcher.rb +132 -0
- data/lib/chef-cli/policyfile/lock_applier.rb +80 -0
- data/lib/chef-cli/policyfile/lock_fetcher_mixin.rb +37 -0
- data/lib/chef-cli/policyfile/null_cookbook_source.rb +49 -0
- data/lib/chef-cli/policyfile/policyfile_location_specification.rb +128 -0
- data/lib/chef-cli/policyfile/read_cookbook_for_compat_mode_upload.rb +124 -0
- data/lib/chef-cli/policyfile/remote_lock_fetcher.rb +108 -0
- data/lib/chef-cli/policyfile/reports/install.rb +69 -0
- data/lib/chef-cli/policyfile/reports/table_printer.rb +57 -0
- data/lib/chef-cli/policyfile/reports/upload.rb +70 -0
- data/lib/chef-cli/policyfile/solution_dependencies.rb +311 -0
- data/lib/chef-cli/policyfile/source_uri.rb +57 -0
- data/lib/chef-cli/policyfile/storage_config.rb +112 -0
- data/lib/chef-cli/policyfile/undo_record.rb +139 -0
- data/lib/chef-cli/policyfile/undo_stack.rb +128 -0
- data/lib/chef-cli/policyfile/uploader.rb +222 -0
- data/lib/chef-cli/policyfile_compiler.rb +528 -0
- data/lib/chef-cli/policyfile_lock.rb +581 -0
- data/lib/chef-cli/policyfile_services/clean_policies.rb +95 -0
- data/lib/chef-cli/policyfile_services/clean_policy_cookbooks.rb +123 -0
- data/lib/chef-cli/policyfile_services/export_repo.rb +419 -0
- data/lib/chef-cli/policyfile_services/install.rb +167 -0
- data/lib/chef-cli/policyfile_services/push.rb +112 -0
- data/lib/chef-cli/policyfile_services/push_archive.rb +164 -0
- data/lib/chef-cli/policyfile_services/rm_policy.rb +141 -0
- data/lib/chef-cli/policyfile_services/rm_policy_group.rb +85 -0
- data/lib/chef-cli/policyfile_services/show_policy.rb +234 -0
- data/lib/chef-cli/policyfile_services/undelete.rb +108 -0
- data/lib/chef-cli/policyfile_services/update_attributes.rb +110 -0
- data/lib/chef-cli/service_exception_inspectors.rb +24 -0
- data/lib/chef-cli/service_exception_inspectors/base.rb +39 -0
- data/lib/chef-cli/service_exception_inspectors/http.rb +119 -0
- data/lib/chef-cli/service_exceptions.rb +142 -0
- data/lib/chef-cli/shell_out.rb +36 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/Berksfile +3 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/build_cookbook/README.md +146 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/build_cookbook/kitchen.yml +21 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/build_cookbook/test-fixture-recipe.rb +8 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/chefignore +110 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/cookbook_readmes/README-policy.md +9 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/cookbook_readmes/README.md +66 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/delivery-config.json +17 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/delivery-project.toml +34 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/gitignore +22 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/README.md +20 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/cookbooks/example/README.md +27 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +6 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/data_bags/README.md +56 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +4 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/dot-chef-repo.txt +6 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/environments/README.md +9 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/environments/example.json +13 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/policyfiles/README.md +24 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/roles/README.md +9 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/repo/roles/example.json +13 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/spec_helper.rb +2 -0
- data/lib/chef-cli/skeletons/code_generator/files/default/spec_helper_policyfile.rb +2 -0
- data/lib/chef-cli/skeletons/code_generator/metadata.rb +8 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/attribute.rb +11 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/build_cookbook.rb +175 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/cookbook.rb +167 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/cookbook_file.rb +23 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/helpers.rb +19 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/policyfile.rb +7 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/recipe.rb +50 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/repo.rb +71 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/resource.rb +12 -0
- data/lib/chef-cli/skeletons/code_generator/recipes/template.rb +31 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/CHANGELOG.md.erb +11 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/LICENSE.apachev2.erb +201 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/Policyfile.rb.erb +25 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/README.md.erb +4 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/attribute.rb.erb +0 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/build_cookbook/Berksfile.erb +7 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/build_cookbook/metadata.rb.erb +10 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/build_cookbook/recipe.rb.erb +9 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/cookbook_file.erb +0 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/helpers.rb.erb +39 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/inspec_default_test.rb.erb +16 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/kitchen.yml.erb +38 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/kitchen_dokken.yml.erb +36 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/kitchen_policyfile.yml.erb +32 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/metadata.rb.erb +20 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/recipe.rb.erb +5 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/recipe_spec.rb.erb +29 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/repo/gitignore.erb +128 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/resource.rb.erb +1 -0
- data/lib/chef-cli/skeletons/code_generator/templates/default/template.erb +0 -0
- data/lib/chef-cli/ui.rb +57 -0
- data/lib/chef-cli/version.rb +20 -0
- data/lib/kitchen/provisioner/policyfile_zero.rb +195 -0
- data/spec/shared/a_file_generator.rb +125 -0
- data/spec/shared/a_generated_file.rb +12 -0
- data/spec/shared/command_with_ui_object.rb +11 -0
- data/spec/shared/custom_generator_cookbook.rb +136 -0
- data/spec/shared/fixture_cookbook_checksums.rb +46 -0
- data/spec/shared/setup_git_committer_config.rb +54 -0
- data/spec/shared/setup_git_cookbooks.rb +53 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/test_helpers.rb +84 -0
- data/spec/unit/chef_runner_spec.rb +139 -0
- data/spec/unit/chef_server_api_multi_spec.rb +120 -0
- data/spec/unit/cli_spec.rb +375 -0
- data/spec/unit/command/base_spec.rb +195 -0
- data/spec/unit/command/clean_policy_cookbooks_spec.rb +180 -0
- data/spec/unit/command/clean_policy_revisions_spec.rb +180 -0
- data/spec/unit/command/delete_policy_group_spec.rb +206 -0
- data/spec/unit/command/delete_policy_spec.rb +206 -0
- data/spec/unit/command/diff_spec.rb +311 -0
- data/spec/unit/command/env_spec.rb +86 -0
- data/spec/unit/command/exec_spec.rb +178 -0
- data/spec/unit/command/export_spec.rb +199 -0
- data/spec/unit/command/generate_spec.rb +142 -0
- data/spec/unit/command/generator_commands/attribute_spec.rb +31 -0
- data/spec/unit/command/generator_commands/base_spec.rb +180 -0
- data/spec/unit/command/generator_commands/build_cookbook_spec.rb +377 -0
- data/spec/unit/command/generator_commands/chef_exts/generator_desc_resource_spec.rb +77 -0
- data/spec/unit/command/generator_commands/chef_exts/recipe_dsl_ext_spec.rb +111 -0
- data/spec/unit/command/generator_commands/cookbook_file_spec.rb +31 -0
- data/spec/unit/command/generator_commands/cookbook_spec.rb +769 -0
- data/spec/unit/command/generator_commands/generator_generator_spec.rb +227 -0
- data/spec/unit/command/generator_commands/helpers_spec.rb +31 -0
- data/spec/unit/command/generator_commands/policyfile_spec.rb +223 -0
- data/spec/unit/command/generator_commands/recipe_spec.rb +37 -0
- data/spec/unit/command/generator_commands/repo_spec.rb +374 -0
- data/spec/unit/command/generator_commands/resource_spec.rb +31 -0
- data/spec/unit/command/generator_commands/template_spec.rb +31 -0
- data/spec/unit/command/install_spec.rb +179 -0
- data/spec/unit/command/push_archive_spec.rb +153 -0
- data/spec/unit/command/push_spec.rb +198 -0
- data/spec/unit/command/shell_init_spec.rb +339 -0
- data/spec/unit/command/show_policy_spec.rb +234 -0
- data/spec/unit/command/undelete_spec.rb +244 -0
- data/spec/unit/command/update_spec.rb +283 -0
- data/spec/unit/command/verify_spec.rb +341 -0
- data/spec/unit/commands_map_spec.rb +57 -0
- data/spec/unit/component_test_spec.rb +128 -0
- data/spec/unit/configurable_spec.rb +68 -0
- data/spec/unit/cookbook_metadata_spec.rb +96 -0
- data/spec/unit/cookbook_profiler/git_spec.rb +176 -0
- data/spec/unit/cookbook_profiler/identifiers_spec.rb +81 -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/configurable/test_config_loader.rb +5 -0
- data/spec/unit/fixtures/configurable/test_configurable.rb +10 -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/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/kitchen.yml +16 -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/chef_server_universe.json +56 -0
- data/spec/unit/fixtures/cookbooks_api/pruned_chef_server_universe.json +30 -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 +33 -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/example_cookbook_metadata_json_only/.gitignore +17 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/.kitchen.yml +16 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/Berksfile +3 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/README.md +4 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/chefignore +96 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/metadata.json +5 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/recipes/default.rb +8 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/.gitignore +17 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/.kitchen.yml +16 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/Berksfile +3 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/README.md +4 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/chefignore +96 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/recipes/default.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/README.md +4 -0
- data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/chefignore +96 -0
- data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/metadata.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/recipes/default.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/Berksfile +3 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/README.md +4 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/chefignore +96 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/metadata.rb +9 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/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/extra/extra_file.txt +0 -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/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -0
- data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -0
- data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -0
- data/spec/unit/generator_spec.rb +119 -0
- data/spec/unit/pager_spec.rb +117 -0
- data/spec/unit/policyfile/artifactory_cookbook_source_spec.rb +59 -0
- data/spec/unit/policyfile/attribute_merge_checker_spec.rb +80 -0
- data/spec/unit/policyfile/chef_repo_cookbook_source_spec.rb +93 -0
- data/spec/unit/policyfile/chef_server_cookbook_source_spec.rb +55 -0
- data/spec/unit/policyfile/chef_server_lock_fetcher_spec.rb +161 -0
- data/spec/unit/policyfile/community_cookbook_source_spec.rb +83 -0
- data/spec/unit/policyfile/comparison_base_spec.rb +340 -0
- data/spec/unit/policyfile/cookbook_location_specification_spec.rb +347 -0
- data/spec/unit/policyfile/cookbook_locks_spec.rb +527 -0
- data/spec/unit/policyfile/delivery_supermarket_source_spec.rb +129 -0
- data/spec/unit/policyfile/differ_spec.rb +686 -0
- data/spec/unit/policyfile/git_lock_fetcher_spec.rb +155 -0
- data/spec/unit/policyfile/included_policies_cookbook_source_spec.rb +242 -0
- data/spec/unit/policyfile/lister_spec.rb +268 -0
- data/spec/unit/policyfile/local_lock_fetcher_spec.rb +199 -0
- data/spec/unit/policyfile/lock_applier_spec.rb +100 -0
- data/spec/unit/policyfile/lock_fetcher_mixin_spec.rb +60 -0
- data/spec/unit/policyfile/null_cookbook_source_spec.rb +34 -0
- data/spec/unit/policyfile/read_cookbook_for_compat_mode_upload_spec.rb +92 -0
- data/spec/unit/policyfile/remote_lock_fetcher_spec.rb +129 -0
- data/spec/unit/policyfile/reports/install_spec.rb +114 -0
- data/spec/unit/policyfile/reports/upload_spec.rb +94 -0
- data/spec/unit/policyfile/solution_dependencies_spec.rb +170 -0
- data/spec/unit/policyfile/source_uri_spec.rb +36 -0
- data/spec/unit/policyfile/storage_config_spec.rb +180 -0
- data/spec/unit/policyfile/undo_record_spec.rb +258 -0
- data/spec/unit/policyfile/undo_stack_spec.rb +265 -0
- data/spec/unit/policyfile/uploader_spec.rb +410 -0
- data/spec/unit/policyfile_demands_spec.rb +1197 -0
- data/spec/unit/policyfile_evaluation_spec.rb +628 -0
- data/spec/unit/policyfile_includes_dsl_spec.rb +220 -0
- data/spec/unit/policyfile_includes_spec.rb +720 -0
- data/spec/unit/policyfile_install_with_includes_spec.rb +232 -0
- data/spec/unit/policyfile_lock_build_spec.rb +1065 -0
- data/spec/unit/policyfile_lock_install_spec.rb +137 -0
- data/spec/unit/policyfile_lock_serialization_spec.rb +424 -0
- data/spec/unit/policyfile_lock_validation_spec.rb +608 -0
- data/spec/unit/policyfile_services/clean_policies_spec.rb +236 -0
- data/spec/unit/policyfile_services/clean_policy_cookbooks_spec.rb +272 -0
- data/spec/unit/policyfile_services/export_repo_spec.rb +473 -0
- data/spec/unit/policyfile_services/install_spec.rb +209 -0
- data/spec/unit/policyfile_services/push_archive_spec.rb +359 -0
- data/spec/unit/policyfile_services/push_spec.rb +249 -0
- data/spec/unit/policyfile_services/rm_policy_group_spec.rb +237 -0
- data/spec/unit/policyfile_services/rm_policy_spec.rb +263 -0
- data/spec/unit/policyfile_services/show_policy_spec.rb +887 -0
- data/spec/unit/policyfile_services/undelete_spec.rb +302 -0
- data/spec/unit/policyfile_services/update_attributes_spec.rb +229 -0
- data/spec/unit/policyfile_services/update_spec.rb +162 -0
- data/spec/unit/service_exception_inspectors/base_spec.rb +41 -0
- data/spec/unit/service_exception_inspectors/http_spec.rb +138 -0
- data/spec/unit/shell_out_spec.rb +34 -0
- metadata +796 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014-2018 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_relative "../cookbook_omnifetch"
|
|
20
|
+
require_relative "../exceptions"
|
|
21
|
+
require "chef/http/simple"
|
|
22
|
+
|
|
23
|
+
module ChefCLI
|
|
24
|
+
module Policyfile
|
|
25
|
+
|
|
26
|
+
class CommunityCookbookSource
|
|
27
|
+
|
|
28
|
+
attr_reader :uri
|
|
29
|
+
attr_reader :preferred_cookbooks
|
|
30
|
+
|
|
31
|
+
def initialize(uri = nil)
|
|
32
|
+
@uri = uri || "https://supermarket.chef.io"
|
|
33
|
+
@http_connections = {}
|
|
34
|
+
@preferred_cookbooks = []
|
|
35
|
+
yield self if block_given?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def default_source_args
|
|
39
|
+
[:supermarket, uri]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def preferred_for(*cookbook_names)
|
|
43
|
+
preferred_cookbooks.concat(cookbook_names)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def preferred_source_for?(cookbook_name)
|
|
47
|
+
preferred_cookbooks.include?(cookbook_name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def ==(other)
|
|
51
|
+
other.kind_of?(self.class) && other.uri == uri && other.preferred_cookbooks == preferred_cookbooks
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def universe_graph
|
|
55
|
+
@universe_graph ||= begin
|
|
56
|
+
full_community_graph.inject({}) do |normalized_graph, (cookbook_name, metadata_by_version)|
|
|
57
|
+
normalized_graph[cookbook_name] = metadata_by_version.inject({}) do |deps_by_version, (version, metadata)|
|
|
58
|
+
deps_by_version[version] = metadata["dependencies"]
|
|
59
|
+
deps_by_version
|
|
60
|
+
end
|
|
61
|
+
normalized_graph
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def source_options_for(cookbook_name, cookbook_version)
|
|
67
|
+
base_uri = full_community_graph[cookbook_name][cookbook_version]["download_url"]
|
|
68
|
+
{ artifactserver: base_uri, version: cookbook_version }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def null?
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def desc
|
|
76
|
+
"supermarket(#{uri})"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def http_connection_for(base_url)
|
|
82
|
+
@http_connections[base_url] ||= Chef::HTTP::Simple.new(base_url)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def full_community_graph
|
|
86
|
+
@full_community_graph ||=
|
|
87
|
+
begin
|
|
88
|
+
graph_json = http_connection_for(uri).get("/universe")
|
|
89
|
+
JSON.parse(graph_json)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2015-2019 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 "ffi_yajl" unless defined?(FFI_Yajl)
|
|
19
|
+
require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
|
|
20
|
+
require_relative "../service_exceptions"
|
|
21
|
+
|
|
22
|
+
module ChefCLI
|
|
23
|
+
module Policyfile
|
|
24
|
+
module ComparisonBase
|
|
25
|
+
|
|
26
|
+
class Local
|
|
27
|
+
|
|
28
|
+
attr_reader :policyfile_lock_relpath
|
|
29
|
+
|
|
30
|
+
def initialize(policyfile_lock_relpath)
|
|
31
|
+
@policyfile_lock_relpath = policyfile_lock_relpath
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def name
|
|
35
|
+
"local:#{policyfile_lock_relpath}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def lock
|
|
39
|
+
raise LockfileNotFound, "Expected lockfile at #{policyfile_lock_relpath} does not exist" unless File.exist?(policyfile_lock_relpath)
|
|
40
|
+
raise LockfileNotFound, "Expected lockfile at #{policyfile_lock_relpath} cannot be read" unless File.readable?(policyfile_lock_relpath)
|
|
41
|
+
FFI_Yajl::Parser.parse(IO.read(policyfile_lock_relpath))
|
|
42
|
+
rescue FFI_Yajl::ParseError => e
|
|
43
|
+
raise MalformedLockfile, "Invalid JSON in lockfile at #{policyfile_lock_relpath}:\n #{e.message}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Git
|
|
49
|
+
|
|
50
|
+
attr_reader :ref
|
|
51
|
+
attr_reader :policyfile_lock_relpath
|
|
52
|
+
|
|
53
|
+
def initialize(ref, policyfile_lock_relpath)
|
|
54
|
+
@ref = ref
|
|
55
|
+
@policyfile_lock_relpath = policyfile_lock_relpath
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def name
|
|
59
|
+
"git:#{ref}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def lock
|
|
63
|
+
git_cmd.run_command
|
|
64
|
+
git_cmd.error!
|
|
65
|
+
FFI_Yajl::Parser.parse(git_cmd.stdout)
|
|
66
|
+
rescue Mixlib::ShellOut::ShellCommandFailed
|
|
67
|
+
raise GitError, "Git command `#{git_cmd_string}` failed with message: #{git_cmd.stderr.chomp}"
|
|
68
|
+
rescue FFI_Yajl::ParseError => e
|
|
69
|
+
raise MalformedLockfile, "Invalid JSON in lockfile at git ref '#{ref}' at path '#{policyfile_lock_relpath}':\n #{e.message}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def git_cmd
|
|
73
|
+
@git_cmd ||= Mixlib::ShellOut.new(git_cmd_string)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def git_cmd_string
|
|
77
|
+
# Git is a little picky about how we specify the paths, but it looks
|
|
78
|
+
# like we don't need to worry about the relative path to the root of
|
|
79
|
+
# the repo if we give git a leading dot:
|
|
80
|
+
#
|
|
81
|
+
# git show 6644e6cb2ade90b8aff2ebb44728958fbc939ebf:zero.rb
|
|
82
|
+
# fatal: Path 'etc/zero.rb' exists, but not 'zero.rb'.
|
|
83
|
+
# Did you mean '6644e6cb2ade90b8aff2ebb44728958fbc939ebf:etc/zero.rb' aka '6644e6cb2ade90b8aff2ebb44728958fbc939ebf:./zero.rb'?
|
|
84
|
+
# git show 6644e6cb2ade90b8aff2ebb44728958fbc939ebf:./zero.rb
|
|
85
|
+
# (works)
|
|
86
|
+
"git show #{ref}:./#{policyfile_lock_relpath}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class PolicyGroup
|
|
92
|
+
|
|
93
|
+
attr_reader :group
|
|
94
|
+
attr_reader :policy_name
|
|
95
|
+
attr_reader :http_client
|
|
96
|
+
|
|
97
|
+
def initialize(group, policy_name, http_client)
|
|
98
|
+
@group = group
|
|
99
|
+
@policy_name = policy_name
|
|
100
|
+
@http_client = http_client
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def name
|
|
104
|
+
"policy_group:#{group}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def lock
|
|
108
|
+
http_client.get("policy_groups/#{group}/policies/#{policy_name}")
|
|
109
|
+
rescue Net::ProtocolError => e
|
|
110
|
+
if e.respond_to?(:response) && e.response.code.to_s == "404"
|
|
111
|
+
raise PolicyfileDownloadError.new("No Policyfile lock named '#{policy_name}' found in policy_group '#{group}' at #{http_client.url}", e)
|
|
112
|
+
else
|
|
113
|
+
raise PolicyfileDownloadError.new("HTTP error attempting to fetch Policyfile lock from #{http_client.url}", e)
|
|
114
|
+
end
|
|
115
|
+
rescue => e
|
|
116
|
+
raise PolicyfileDownloadError.new("Failed to fetch Policyfile lock from #{http_client.url}", e)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014-2018 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_relative "../cookbook_omnifetch"
|
|
20
|
+
require_relative "storage_config"
|
|
21
|
+
|
|
22
|
+
module ChefCLI
|
|
23
|
+
module Policyfile
|
|
24
|
+
|
|
25
|
+
class CookbookLocationSpecification
|
|
26
|
+
|
|
27
|
+
#--
|
|
28
|
+
# Provides #relative_paths_root, which is required by CookbookOmnifetch
|
|
29
|
+
# API contract
|
|
30
|
+
include StorageConfigDelegation
|
|
31
|
+
|
|
32
|
+
SOURCE_TYPES = [:git, :github, :path, :artifactserver, :chef_server, :chef_server_artifact, :artifactory].freeze
|
|
33
|
+
|
|
34
|
+
#--
|
|
35
|
+
# Required by CookbookOmnifetch API contract
|
|
36
|
+
attr_reader :version_constraint
|
|
37
|
+
|
|
38
|
+
#--
|
|
39
|
+
# Required by CookbookOmnifetch API contract
|
|
40
|
+
attr_reader :name
|
|
41
|
+
|
|
42
|
+
#--
|
|
43
|
+
# Required by CookbookOmnifetch API contract
|
|
44
|
+
attr_reader :source_options
|
|
45
|
+
attr_reader :source_type
|
|
46
|
+
attr_reader :storage_config
|
|
47
|
+
|
|
48
|
+
def initialize(name, version_constraint, source_options, storage_config)
|
|
49
|
+
@name = name
|
|
50
|
+
@version_constraint = Semverse::Constraint.new(version_constraint)
|
|
51
|
+
@source_options = source_options
|
|
52
|
+
@source_type = SOURCE_TYPES.find { |type| source_options.key?(type) }
|
|
53
|
+
@storage_config = storage_config
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ==(other)
|
|
57
|
+
other.kind_of?(self.class) &&
|
|
58
|
+
other.name == name &&
|
|
59
|
+
other.version_constraint == version_constraint &&
|
|
60
|
+
other.source_options == source_options
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def to_s
|
|
64
|
+
# Note, this may appear in exceptions
|
|
65
|
+
s = "Cookbook '#{name}'"
|
|
66
|
+
s << " #{version_constraint}"
|
|
67
|
+
s << " #{source_options}" unless source_options.empty?
|
|
68
|
+
s
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def mirrors_canonical_upstream?
|
|
72
|
+
[:git, :github, :artifactserver, :chef_server, :chef_server_artifact, :artifactory].include?(source_type)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def installed?
|
|
76
|
+
installer.installed?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def ensure_cached
|
|
80
|
+
unless installer.installed?
|
|
81
|
+
installer.install
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def valid?
|
|
86
|
+
errors.empty?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def errors
|
|
90
|
+
error_messages = []
|
|
91
|
+
if source_options_invalid?
|
|
92
|
+
error_messages << "Cookbook `#{name}' has invalid source options `#{source_options.inspect}'"
|
|
93
|
+
end
|
|
94
|
+
error_messages
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def installer
|
|
98
|
+
# TODO: handle 'bad' return values here (invalid source_options, etc.)
|
|
99
|
+
@installer ||= CookbookOmnifetch.init(self, source_options)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def cache_key
|
|
103
|
+
installer.cache_key
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def relative_path
|
|
107
|
+
installer.relative_path.to_s
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def uri
|
|
111
|
+
installer.uri
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def version_fixed?
|
|
115
|
+
[:git, :github, :path, :chef_server_artifact].include?(@source_type)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def version
|
|
119
|
+
cached_cookbook.version
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def dependencies
|
|
123
|
+
cached_cookbook.dependencies
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def cookbook_has_recipe?(recipe_name)
|
|
127
|
+
expected_path = cookbook_path.join("recipes/#{recipe_name}.rb")
|
|
128
|
+
expected_path.exist?
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def cached_cookbook
|
|
132
|
+
# TODO: handle 'bad' return values here (cookbook not installed yet)
|
|
133
|
+
installer.cached_cookbook
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def source_options_for_lock
|
|
137
|
+
installer.lock_data
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def source_options_invalid?
|
|
141
|
+
!source_options.empty? && installer.nil?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def cookbook_path
|
|
145
|
+
if installer.respond_to?(:expanded_path)
|
|
146
|
+
installer.expanded_path
|
|
147
|
+
else
|
|
148
|
+
installer.install_path.expand_path
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014-2018 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" unless defined?(Forwardable)
|
|
19
|
+
|
|
20
|
+
require_relative "../exceptions"
|
|
21
|
+
|
|
22
|
+
require_relative "../cookbook_profiler/null_scm"
|
|
23
|
+
require_relative "../cookbook_profiler/git"
|
|
24
|
+
|
|
25
|
+
require_relative "../cookbook_profiler/identifiers"
|
|
26
|
+
require_relative "storage_config"
|
|
27
|
+
|
|
28
|
+
require_relative "cookbook_location_specification"
|
|
29
|
+
|
|
30
|
+
module ChefCLI
|
|
31
|
+
|
|
32
|
+
module Policyfile
|
|
33
|
+
|
|
34
|
+
# Base class for CookbookLock implementations
|
|
35
|
+
class CookbookLock
|
|
36
|
+
|
|
37
|
+
REQUIRED_LOCK_DATA_KEYS = %w{version identifier dotted_decimal_identifier cache_key source_options}.freeze
|
|
38
|
+
REQUIRED_LOCK_DATA_KEYS.each(&:freeze)
|
|
39
|
+
REQUIRED_LOCK_DATA_KEYS.freeze
|
|
40
|
+
|
|
41
|
+
include Policyfile::StorageConfigDelegation
|
|
42
|
+
|
|
43
|
+
# The cookbook name (without any version or other info suffixed)
|
|
44
|
+
attr_reader :name
|
|
45
|
+
|
|
46
|
+
# Options specifying the source and revision of this cookbook. These can
|
|
47
|
+
# be passed to a CookbookLocationSpecification to create an object that can install the
|
|
48
|
+
# same revision of the cookbook on another machine.
|
|
49
|
+
attr_accessor :source_options
|
|
50
|
+
|
|
51
|
+
# A string that uniquely identifies the cookbook version. If not
|
|
52
|
+
# explicitly set, an identifier is generated based on the cookbook's
|
|
53
|
+
# content.
|
|
54
|
+
attr_accessor :identifier
|
|
55
|
+
|
|
56
|
+
# A string in "X.Y.Z" version number format that uniquely identifies the
|
|
57
|
+
# cookbook version. This is for compatibility with Chef Infra Server 11.x,
|
|
58
|
+
# where cookbooks are stored by x.y.z version numbers.
|
|
59
|
+
attr_accessor :dotted_decimal_identifier
|
|
60
|
+
|
|
61
|
+
attr_reader :storage_config
|
|
62
|
+
|
|
63
|
+
attr_accessor :version
|
|
64
|
+
|
|
65
|
+
def initialize(name, storage_config)
|
|
66
|
+
@name = name
|
|
67
|
+
@version = nil
|
|
68
|
+
@source_options = nil
|
|
69
|
+
@identifier = nil
|
|
70
|
+
@dotted_decimal_identifier = nil
|
|
71
|
+
@storage_config = storage_config
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def installed?
|
|
75
|
+
cookbook_location_spec.installed?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def install_locked
|
|
79
|
+
cookbook_location_spec.ensure_cached
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def cookbook_location_spec
|
|
83
|
+
raise InvalidCookbookLockData, "Cannot create CookbookLocationSpecification for #{name} without version" if version.nil?
|
|
84
|
+
raise InvalidCookbookLockData, "Cannot create CookbookLocationSpecification for #{name} without source options" if source_options.nil?
|
|
85
|
+
@location_spec ||= CookbookLocationSpecification.new(name, "= #{version}", source_options, storage_config)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def dependencies
|
|
89
|
+
cookbook_location_spec.dependencies
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def gather_profile_data
|
|
93
|
+
@identifier ||= identifiers.content_identifier
|
|
94
|
+
@dotted_decimal_identifier ||= identifiers.dotted_decimal_identifier
|
|
95
|
+
@version ||= identifiers.semver_version
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def identifiers
|
|
99
|
+
@identifiers ||= CookbookProfiler::Identifiers.new(cookbook_version)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def cookbook_path
|
|
103
|
+
raise NotImplementedError, "#{self.class} must override #cookbook_path with a specific implementation"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def to_lock
|
|
107
|
+
validate!
|
|
108
|
+
lock_data
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def lock_data
|
|
112
|
+
raise NotImplementedError, "#{self.class} must override #lock_data a specific implementation"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def build_from_lock_data(lock_data)
|
|
116
|
+
raise NotImplementedError, "#{self.class} must override #build_from_lock_data with a specific implementation"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def validate!
|
|
120
|
+
raise NotImplementedError, "#{self.class} must override #validate! with a specific implementation"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def refresh!
|
|
124
|
+
raise NotImplementedError, "#{self.class} must override #refresh! with a specific implementation"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def updated?
|
|
128
|
+
false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def identifier_updated?
|
|
132
|
+
false
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def version_updated?
|
|
136
|
+
false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def symbolize_source_options_keys(source_options_from_json)
|
|
140
|
+
source_options_from_json ||= {}
|
|
141
|
+
source_options_from_json.inject({}) do |normalized_source_opts, (key, value)|
|
|
142
|
+
normalized_source_opts[key.to_sym] = value
|
|
143
|
+
normalized_source_opts
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def cookbook_version
|
|
148
|
+
@cookbook_version ||= cookbook_loader.cookbook_version
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def cookbook_loader
|
|
152
|
+
@cookbook_loader ||=
|
|
153
|
+
begin
|
|
154
|
+
loader = Chef::Cookbook::CookbookVersionLoader.new(cookbook_path, chefignore)
|
|
155
|
+
loader.load!
|
|
156
|
+
loader
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def chefignore
|
|
161
|
+
@chefignore ||= Chef::Cookbook::Chefignore.new(File.join(cookbook_path, "chefignore"))
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
private
|
|
165
|
+
|
|
166
|
+
def assert_required_keys_valid!(lock_data)
|
|
167
|
+
missing_keys = REQUIRED_LOCK_DATA_KEYS.reject { |key| lock_data.key?(key) }
|
|
168
|
+
unless missing_keys.empty?
|
|
169
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} missing required attributes `#{missing_keys.join("', `")}'"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
version = lock_data["version"]
|
|
173
|
+
unless version.kind_of?(String)
|
|
174
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} `version' attribute must be a string (got: #{version})"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
identifier = lock_data["identifier"]
|
|
178
|
+
unless identifier.kind_of?(String)
|
|
179
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} `identifier' attribute must be a string (got: #{identifier})"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
cache_key = lock_data["cache_key"]
|
|
183
|
+
unless cache_key.kind_of?(String) || cache_key.nil?
|
|
184
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} `cache_key' attribute must be a string (got: #{cache_key})"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
source_options = lock_data["source_options"]
|
|
188
|
+
unless source_options.kind_of?(Hash)
|
|
189
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} `source_options' attribute must be a Hash (JSON object) (got: #{source_options})"
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# CachedCookbook objects represent a cookbook that has been fetched from an
|
|
196
|
+
# upstream canonical source and stored (presumed unmodified).
|
|
197
|
+
class CachedCookbook < CookbookLock
|
|
198
|
+
|
|
199
|
+
# The directory name in the cookbook cache where the cookbook is stored.
|
|
200
|
+
# By convention, this should be the name of the cookbook followed by a
|
|
201
|
+
# hyphen and then some sort of version identifier (depending on the
|
|
202
|
+
# cookbook source).
|
|
203
|
+
attr_accessor :cache_key
|
|
204
|
+
|
|
205
|
+
# A URI pointing to the canonical source of the cookbook.
|
|
206
|
+
attr_accessor :origin
|
|
207
|
+
|
|
208
|
+
def initialize(name, storage_config)
|
|
209
|
+
@name = name
|
|
210
|
+
@version = nil
|
|
211
|
+
@origin = nil
|
|
212
|
+
@source_options = nil
|
|
213
|
+
@cache_key = nil
|
|
214
|
+
@identifier = nil
|
|
215
|
+
@dotted_decimal_identifier = nil
|
|
216
|
+
@storage_config = storage_config
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def cookbook_path
|
|
220
|
+
if cache_key.nil?
|
|
221
|
+
raise MissingCookbookLockData, "Cannot locate cached cookbook `#{name}' because the `cache_key' attribute is not set"
|
|
222
|
+
end
|
|
223
|
+
File.join(cache_path, cache_key)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def build_from_lock_data(lock_data)
|
|
227
|
+
assert_required_keys_valid!(lock_data)
|
|
228
|
+
|
|
229
|
+
@version = lock_data["version"]
|
|
230
|
+
@identifier = lock_data["identifier"]
|
|
231
|
+
@dotted_decimal_identifier = lock_data["dotted_decimal_identifier"]
|
|
232
|
+
@cache_key = lock_data["cache_key"]
|
|
233
|
+
@origin = lock_data["origin"]
|
|
234
|
+
@source_options = symbolize_source_options_keys(lock_data["source_options"])
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def lock_data
|
|
238
|
+
{
|
|
239
|
+
"version" => version,
|
|
240
|
+
"identifier" => identifier,
|
|
241
|
+
"dotted_decimal_identifier" => dotted_decimal_identifier,
|
|
242
|
+
"cache_key" => cache_key,
|
|
243
|
+
"origin" => origin,
|
|
244
|
+
"source_options" => source_options,
|
|
245
|
+
}
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def validate!
|
|
249
|
+
if cache_key.nil?
|
|
250
|
+
raise CachedCookbookNotFound, "Cookbook `#{name}' does not have a `cache_key` set, cannot locate cookbook"
|
|
251
|
+
end
|
|
252
|
+
unless File.exist?(cookbook_path)
|
|
253
|
+
raise CachedCookbookNotFound, "Cookbook `#{name}' not found at expected cache location `#{cache_key}' (full path: `#{cookbook_path}')"
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# We do not expect the cookbook to get mutated out-of-band, so refreshing
|
|
258
|
+
# the data generally should have no affect. If the cookbook has been
|
|
259
|
+
# mutated, though, then a CachedCookbookModified exception is raised.
|
|
260
|
+
def refresh!
|
|
261
|
+
# This behavior fits better with the intent of the #validate! method,
|
|
262
|
+
# but we cannot check for modifications there because the user may be
|
|
263
|
+
# setting custom identifiers.
|
|
264
|
+
if @identifier && identifiers.content_identifier != @identifier
|
|
265
|
+
message = "Cached cookbook `#{name}' (#{version}) has been modified since the lockfile was generated. " +
|
|
266
|
+
"Cached cookbooks cannot be modified. (full path: `#{cookbook_path}')"
|
|
267
|
+
raise CachedCookbookModified, message
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# LocalCookbook objects represent cookbooks that are sourced from the local
|
|
274
|
+
# filesystem and are assumed to be under active development.
|
|
275
|
+
class LocalCookbook < CookbookLock
|
|
276
|
+
|
|
277
|
+
# A relative or absolute path to the cookbook. If a relative path is
|
|
278
|
+
# given, it is resolved relative to #relative_paths_root
|
|
279
|
+
attr_accessor :source
|
|
280
|
+
|
|
281
|
+
def initialize(name, storage_config)
|
|
282
|
+
@name = name
|
|
283
|
+
@identifier = nil
|
|
284
|
+
@storage_config = storage_config
|
|
285
|
+
|
|
286
|
+
@identifier_updated = false
|
|
287
|
+
@version_updated = false
|
|
288
|
+
@cookbook_in_git_repo = nil
|
|
289
|
+
@scm_info = nil
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def cookbook_path
|
|
293
|
+
File.expand_path(source, relative_paths_root)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def scm_profiler
|
|
297
|
+
if cookbook_in_git_repo?
|
|
298
|
+
CookbookProfiler::Git.new(cookbook_path)
|
|
299
|
+
else
|
|
300
|
+
CookbookProfiler::NullSCM.new(cookbook_path)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def scm_info
|
|
305
|
+
@scm_info
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def to_lock
|
|
309
|
+
refresh_scm_info
|
|
310
|
+
super
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def lock_data
|
|
314
|
+
{
|
|
315
|
+
"version" => version,
|
|
316
|
+
"identifier" => identifier,
|
|
317
|
+
"dotted_decimal_identifier" => dotted_decimal_identifier,
|
|
318
|
+
"source" => source,
|
|
319
|
+
"cache_key" => nil,
|
|
320
|
+
"scm_info" => scm_info,
|
|
321
|
+
"source_options" => source_options,
|
|
322
|
+
}
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def build_from_lock_data(lock_data)
|
|
326
|
+
assert_required_keys_valid!(lock_data)
|
|
327
|
+
|
|
328
|
+
@version = lock_data["version"]
|
|
329
|
+
@identifier = lock_data["identifier"]
|
|
330
|
+
@dotted_decimal_identifier = lock_data["dotted_decimal_identifier"]
|
|
331
|
+
@source = lock_data["source"]
|
|
332
|
+
@source_options = symbolize_source_options_keys(lock_data["source_options"])
|
|
333
|
+
@scm_info = lock_data["scm_info"]
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def validate!
|
|
337
|
+
if source.nil?
|
|
338
|
+
raise LocalCookbookNotFound, "Cookbook `#{name}' does not have a `source` set, cannot locate cookbook"
|
|
339
|
+
end
|
|
340
|
+
unless File.exist?(cookbook_path)
|
|
341
|
+
raise LocalCookbookNotFound, "Cookbook `#{name}' not found at path source `#{source}` (full path: `#{cookbook_path}')"
|
|
342
|
+
end
|
|
343
|
+
unless cookbook_version.name.to_s == name
|
|
344
|
+
msg = "The cookbook at path source `#{source}' is expected to be named `#{name}', but is now named `#{cookbook_version.name}' (full path: #{cookbook_path})"
|
|
345
|
+
raise MalformedCookbook, msg
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def refresh!
|
|
350
|
+
old_identifier, old_version = @identifier, @version
|
|
351
|
+
@identifier, @dotted_decimal_identifier, @version = nil, nil, nil
|
|
352
|
+
gather_profile_data
|
|
353
|
+
if @identifier != old_identifier
|
|
354
|
+
@identifier_updated = true
|
|
355
|
+
end
|
|
356
|
+
if @version != old_version
|
|
357
|
+
@version_updated = true
|
|
358
|
+
end
|
|
359
|
+
self
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def updated?
|
|
363
|
+
@identifier_updated || @version_updated
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def version_updated?
|
|
367
|
+
@version_updated
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def identifier_updated?
|
|
371
|
+
@identifier_updated
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
private
|
|
375
|
+
|
|
376
|
+
def refresh_scm_info
|
|
377
|
+
@scm_info = scm_profiler.profile_data
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def assert_required_keys_valid!(lock_data)
|
|
381
|
+
super
|
|
382
|
+
|
|
383
|
+
source = lock_data["source"]
|
|
384
|
+
if source.nil?
|
|
385
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} is invalid. Lock data for a local cookbook must have a `source' attribute"
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
unless source.kind_of?(String)
|
|
389
|
+
raise InvalidLockfile, "Lockfile cookbook_lock for #{name} is invalid: `source' attribute must be a String (got: #{source.inspect})"
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def cookbook_in_git_repo?
|
|
394
|
+
return @cookbook_in_git_repo unless @cookbook_in_git_repo.nil?
|
|
395
|
+
|
|
396
|
+
@cookbook_in_git_repo = false
|
|
397
|
+
|
|
398
|
+
dot_git = Pathname.new(".git")
|
|
399
|
+
Pathname.new(cookbook_path).ascend do |parent_dir|
|
|
400
|
+
possbile_git_dir = parent_dir + dot_git
|
|
401
|
+
if possbile_git_dir.exist?
|
|
402
|
+
@cookbook_in_git_repo = true
|
|
403
|
+
break
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
@cookbook_in_git_repo
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
class ArchivedCookbook < CookbookLock
|
|
413
|
+
|
|
414
|
+
extend Forwardable
|
|
415
|
+
|
|
416
|
+
def_delegator :@archived_lock, :name
|
|
417
|
+
def_delegator :@archived_lock, :source_options
|
|
418
|
+
def_delegator :@archived_lock, :identifier
|
|
419
|
+
def_delegator :@archived_lock, :dotted_decimal_identifier
|
|
420
|
+
def_delegator :@archived_lock, :version
|
|
421
|
+
def_delegator :@archived_lock, :source
|
|
422
|
+
|
|
423
|
+
# #to_lock calls #validate! which will typically ensure that the cookbook
|
|
424
|
+
# is present at the correct path for the lock type. For an archived
|
|
425
|
+
# cookbook, the cookbook is located in the archive, so it probably won't
|
|
426
|
+
# exist there. Therefore, we bypass #validate! and get the lock data
|
|
427
|
+
# directly.
|
|
428
|
+
def_delegator :@archived_lock, :lock_data, :to_lock
|
|
429
|
+
|
|
430
|
+
def initialize(archived_lock, storage_config)
|
|
431
|
+
@archived_lock = archived_lock
|
|
432
|
+
@storage_config = storage_config
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def build_from_lock_data(lock_data)
|
|
436
|
+
raise NotImplementedError, "ArchivedCookbook cannot be built from lock data, it can only wrap an existing lock object"
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def installed?
|
|
440
|
+
File.exist?(cookbook_path) && File.directory?(cookbook_path)
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# The cookbook is assumed to be stored in a Chef Zero compatible repo as
|
|
444
|
+
# created by `chef export`. Currently that only creates "compatibility
|
|
445
|
+
# mode" repos since Chef Zero doesn't yet support cookbook_artifact APIs.
|
|
446
|
+
# So the cookbook will be located in a path like:
|
|
447
|
+
# cookbooks/nginx-111.222.333
|
|
448
|
+
def cookbook_path
|
|
449
|
+
File.join(relative_paths_root, "cookbook_artifacts", "#{name}-#{identifier}")
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
# We trust that archived cookbooks haven't been modified, so just return
|
|
453
|
+
# true for #validate!
|
|
454
|
+
def validate!
|
|
455
|
+
true
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# We trust that archived cookbooks haven't been modified, so just return
|
|
459
|
+
# true for #refresh!
|
|
460
|
+
def refresh!
|
|
461
|
+
true
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
end
|
|
466
|
+
end
|